删除链表的倒数第N个节点

感觉自己对于链表的知识还是了解的不够深入,所以没有想到用双指针进行操作。我的想法是这样的,首先计算整个链表的长度,然后遍历到长度减去n的节点处,执行删除操作。

自己的代码:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* cur=head;
ListNode *cou=head;
int i=0; int count=1;
while(cou->next!=NULL)
{
cou=cou->next;
count++;
}
if(count==1) return NULL;
if(count==n) {head=head->next;
return head;} while(head->next!=NULL && i<count-1-n)
{
head=head->next;
i++;
}
if(head->next!=NULL)
{
ListNode *temp;
temp=head->next;
head->next=temp->next;
} return cur;
}
};

相信看过代码后都会觉得这个代码的逻辑比较奇怪,尤其是

if(count==1) return NULL;        if(count==n) {
head=head->next;
return head;
}

这段代码,感觉是根据测试案例试出来的。的确是这样的,我的代码在[1,2]去掉倒数第二个元素或者[1,2,3]去掉倒数第三各元素的时候总是会去除中间的额元素,经排查原因应该是head节点的理解有些问题。我认为的head是头指针,head->next才是第一个结点,但这代码里的意思好像是head就已经是第一个节点了,所以在后面判断的时候有些bug。当然我们还是习惯用比较常规的方法就是用双指针的方法进行问题的解决:

这里放出大神的代码:

class Solution{
public:
ListNode* removeNthFromEnd(ListNode* head,int n){
if(!head->next) return NULL;
LisNode *pre=head,*cur=head;
for(int i=0;i<n;i++) cur=cur->next;
if(!cur) return head->next;
while(cur->next){
cur=cur->next;
pre=pre->next;
}
pre->next=pre->next->next;
return head;
}
};

下面我来解释一下这段代码的意思,定义了两个指针,两个指针相差n个距离,这样的话当其中一个指针指向结尾处的时候,另一个指针就自然指向了我们需要删除的前一个元素位置了,然后执行删除操作,这样非常的快捷。

反转链表

感觉这道题有些帅,试着走了一遍逻辑,并不是像我之前以为的一个新链表然后反向遍历读出数据,但是这个逻辑是一次反转一个,用到dummy始终指向头结点、cur始终指向当前的节点、tmp指向下一个结点,逻辑就是将cur下一个指向tmp的下一个结点,将tmp指向头结点,然后dummy再指向tmp,然后再次进行迭代。仔细思考一下这个反转转的真的很有智慧。代码如下:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head) return head;
ListNode *dummy=new ListNode(-1);
dummy->next=head;
ListNode *cur=head;
while(cur->next)
{
ListNode *tmp=cur->next;
cur->next=temp->next;
tmp->next=dummy->next;
dummy->next=tmp;
}
return dummy->next;
}
};

合并两个有序链表

这题比较简单,就是不断地判断;如果有一个链表已经比较晚了,则直接把后面所有的元素再加到新链表中就OK了。代码如下:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1!=NULL&&l2==NULL) return l1;
if(l1==NULL&&l2!=NULL) return l2;
ListNode head(0);
ListNode* l3=&head;
while(l1!=NULL&&l2!=NULL)
{
if(l1->val<l2->val)
{
l3->next=l1;
l1=l1->next;
}
else
{
l3->next=l2;
l2=l2->next;
}
l3=l3->next; } if(l1!=NULL)
l3->next=l1;
if(l2!=NULL)
l3->next=l2; return head.next;
}
};

回文链表

解释在代码注释里了,感觉学到了一招快速到达链表的中央了(slow与fast的应用,fast->next->next是slow->next速度的两倍,当fast->next指向结尾,slow指向中间!!)

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
//O(n)时间表示不能有嵌套循环, O(1)空间表示不能再次添加新链表
if(!head||!head->next) return true;
ListNode *slow=head,*fast=head;
stack<int> s;
s.push(head->val);
while(fast->next!=NULL && fast->next->next!=NULL)
{
slow=slow->next;
fast=fast=fast->next->next; //fast的速度是slow的两倍,这样就能保证slow最后能找到链表的中间
s.push(slow->val);
}
if(fast->next==NULL)
s.pop(); //说明是奇数个,中间的就不用进行比较了,所以直接pop掉比较后面的 while(slow->next!=NULL)
{
slow=slow->next;
int tmp=s.top();
s.pop();
if(tmp!=slow->val) return false;
}
return true;
}
};

环形链表

环形链表是循环链表的最简单形式,即首尾是相连的。所以若我们指定两个指针,fast和slow。两个指针同时从头结点开始出发,fast指针走两步,slow指针走一步;若链表有环,这两个指针肯定会在某点相遇;若链表无环,fast会直接先到达NULL。因为不断的循环,只要有环就一定会相遇,如果没环则一定会存在NULL。

代码如下:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *slow=head,*fast=head;
while(fast!=NULL && fast->next!=NULL)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast) return true;
}
return false;
}
};

Leetcode初级算法(链表篇)的更多相关文章

  1. LeetCode初级算法--链表01:反转链表

    LeetCode初级算法--链表01:反转链表 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/ ...

  2. LeetCode初级算法--链表02:合并两个有序链表

    LeetCode初级算法--链表02:合并两个有序链表 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn. ...

  3. LeetCode初级算法(树篇)

    目录 二叉树的最大深度 验证二叉搜索树 对称二叉树 二叉树的层次遍历 将有序数组转换为二叉搜索树 二叉树的最大深度 二叉树,所以可以考虑用递归来做.由于根节点已经算过了,所以需要加上1:每次返回都是以 ...

  4. LeetCode初级算法(其他篇)

    目录 缺失数字 位1的个数 颠倒二进制位 有效的括号 汉明距离 帕斯卡三角形 缺失数字 最初的想法是将0到n全部加起来,再减去输入的数字之和,那么差如果非零的话就是我们所需要的数字.但是一想,可能会发 ...

  5. Leetcode初级算法(字符串篇)

    目录 反转字符串 颠倒整数 字符串中的第一个唯一字符 有效的字母异位词 验证回文字符串 实现strStr() 数数并说 最长公共前缀 字符串转整数(atoi) 反转字符串 和vector同样的进行sw ...

  6. LeetCode初级算法的Python实现--链表

    LeetCode初级算法的Python实现--链表 之前没有接触过Python编写的链表,所以这里记录一下思路.这里前面的代码是和leetcode中的一样,因为做题需要调用,所以下面会给出. 首先定义 ...

  7. LeetCode初级算法(数组)解答

    这里记录了LeetCode初级算法中数组的一些题目: 加一 本来想先转成整数,加1后再转回去:耽美想到测试的例子考虑到了这个方法的笨重,所以int类型超了最大范围65536,导致程序出错. class ...

  8. 【LeetCode算法】LeetCode初级算法——字符串

      在LeetCode初级算法的字符串专题中,共给出了九道题目,分别为:反转字符串,整数反转,字符串中的第一个唯一字符,有效的字母异位词,验证回文字符串,字符串转换整数,实现strStr(),报数,最 ...

  9. LeetCode初级算法之数组:48 旋转图像

    旋转图像 题目地址:https://leetcode-cn.com/problems/rotate-image/ 给定一个 n × n 的二维矩阵表示一个图像. 将图像顺时针旋转 90 度. 说明: ...

随机推荐

  1. npm in macbook

    打开终端,试了很多次 npm install anywhere -g,结果还是报错,大概就说没权限. 所以,才想起之前看过的博客中,提到用sudo去执行. 终于,没问题了! 如果npm install ...

  2. ssh免密码登录配置方法,(图示加命令)

    首先,说明一下我们要做的是,serverA 服务器的 usera 用户免密码登录 serverB 服务器的 userb用户. 我们先使用usera 登录 serverA 服务器 [root@serve ...

  3. POJ1703(2集合并查集)

    Find them, Catch them Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 39402   Accepted: ...

  4. 问题11:如何进行反向迭代 & 如何实现反向迭代

    # 有关列表问题,参考:Python:列表list 案例: 需求:实现一个连续浮点数发生器FloatRange(和range类似),根据给定范围(start,end)和步进值(step),产生一系列连 ...

  5. UML核心元素--参与者

    定义:参与者是在系统之外与系统交互的某人或某事物.参与者在建模过程中处于核心地位. 1.系统之外:系统之外的定义说明在参与者和系统之间存在明确的边界,参与者只能存在于边界之外,边界之内的所有人和事务都 ...

  6. springMVC绑定json参数之一

    一.SpringMVC @RequestBody接收Json对象字符串 以前,一直以为在SpringMVC环境中,@RequestBody接收的是一个Json对象,一直在调试代码都没有成功,后来发现, ...

  7. python 基础 列表 字符串转换

    1. 字符串转列表 str1 = "hi hello world" print(str1.split(" "))输出:['hi', 'hello', 'worl ...

  8. linux日常管理-rsync后台服务方式-2

    把本地的数据拷贝到远程 这里是个错误,read only.只允许读,不允许写. 改一下远程机器的配置文件 把read only改为no 拷贝到远程成功 tree一下远程机器的目录 ////////// ...

  9. docker里安装ubuntu

    使用 Ubuntu 官方镜像 Ubuntu 相关的镜像有很多,这里使用 -s 10 参数,只搜索那些被收藏 10 次以上的镜像 $ docker search -s 10 ubuntu NAME DE ...

  10. std::min error C2059: 语法错误:“::” 的解决方法

    std::min error C2059: 语法错误:"::" 的解决方法 下面这段代码: size_t n = std::min(count_, num_elements); 编 ...