删除链表的倒数第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. 作为.NET程序员,您需要IronPython么?

    .NET作为一个成熟的开发平台,为很多语言的发展提供了肥沃的土壤:历史相对久远的有Managed C++.C#.VB.NET.J#,正值壮年的则有IronPython.IronRuby,而老赵极力推崇 ...

  2. Oracle12c多租户如何连接到CDB或PDB、CDB与PDB容器切换

    Oracle 数据库 12 c 多租户选项允许单个容器数据库 (CDB) 来承载多个单独的可插拔数据库 (PDB).那么我们如何连接到容器数据库 (CDB) 和可插拔数据库 (PDB). 1. V$S ...

  3. debian软件安装和卸载

    用root身份执行如下命令: dpkg -l |grep "^rc"|awk '{print $2}' |xargs aptitude -y purge dpkg是Debian P ...

  4. POJ 2017 No Brainer(超级水题)

    一.Description Zombies love to eat brains. Yum. Input The first line contains a single integer n indi ...

  5. angular-cli.json配置参数解析,常用命令解析

    1.angular-cli.json配置参数解析 { "project": { "name": "ng-admin", //项目名称 &qu ...

  6. ES6学习之字符串的扩展

    字符的Unicode表示法 \uxxxx可以表示一个双字节的字符(xxxx表示字符编码,范围在0000---FFFF),超出此范围用两个双字节表示. console.log("\u0061& ...

  7. C#的闭包

    简单的理解:闭包变量是把局部变量的作用域扩展到回调函数,发生在匿名方法注册到委托上,而匿名方法中使用外部的局部变量 说什么都不如图示那么容易明白啊 先看C#的源码 class Program { st ...

  8. linux日常管理-sar工具

    查看网卡瓶颈 查看网卡流量 默认10分钟一次 查看实时流量  每秒钟显示一次 显示5次 网卡有 lo eth0   主要看eth0外网  rxbyt/s 进网口和 txbyt/s出网口 带宽看txby ...

  9. 字符编码ANSI、ASCII、GB2312、GBK、GB18030、UNICODE、UTF-8小结

    编码和解码可以理解成二进制和字符(广义的字符,包括汉字等)的映射表,编码即从字符映射至二进制,解码则为逆过程. 1.英语字符编码ASCII 开始计算机只在美国用.8字节一共可以组合出256(2的8次方 ...

  10. LEADTOOLS V19: 世界领先的图像处理开发工具包强势来袭

      投递人 itwriter 发布于 2014-12-22 16:04 评论(0) 有214人阅读   原文链接  [收藏]   « » LEAD 科技于 2014 年 12 月 11 日发布 LEA ...