删除链表的倒数第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. poj 2069 Super Star 模拟退火

    题目大意: 给定三位空间上的n(\(n \leq 30\))个点,求最小的球覆盖掉所有的点. 题解: 貌似我们可以用类似于二维平面中的随机增量法瞎搞一下 但是我不会怎么搞 所以我们模拟退火就好了啊QA ...

  2. Python:struct模块的pack、unpack

    mport struct pack.unpack.pack_into.unpack_from 1 # ref: http://blog.csdn<a href="http://lib. ...

  3. C语言学习笔记--C语言中变量的属性关键字

    变量属性关键字的使用语法:property type var_name; 1.auto 关键字 auto关键字是C语言中局部变量的默认的关键字,C编译器默认所有的局部变量都是auto的,它表明了被修饰 ...

  4. web实现本地缓存的方法

    Cookie(或者Cookies) 指一般网站为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据(通常经过加密). cookie一般通过http请求中在头部一起发送到服务器端.一条c ...

  5. 0010_while循环

    while 条件: 代码块 break:跳出循环语句 continue:跳出本次循环,进入下一次循环. __author__ = 'qq593' #!/usr/bin/env python #-*- ...

  6. p2345 奶牛集会

    传送门 题目 约翰的N 头奶牛每年都会参加“哞哞大会”.哞哞大会是奶牛界的盛事.集会上的活动很 多,比如堆干草,跨栅栏,摸牛仔的屁股等等.它们参加活动时会聚在一起,第i 头奶牛的坐标为Xi,没有两头奶 ...

  7. 7、scala面向对象-继承

    一.继承 1.extends Scala中,让子类继承父类,与Java一样,也是使用extends关键字 继承就代表,子类可以从父类继承父类的field和method:然后子类可以在自己内部放入父类所 ...

  8. 1. csrf 简介

    浅谈CSRF CSRF是什么? (Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,它在 年曾被列为互联网 大安全隐患之一,也被称为“One Click A ...

  9. “MVC+Nhibernate+Jquery-EasyUI” 信息发布系统 第三篇(登录窗口的实现以及如何保存登录者的信息)

    一.前言: 1.再看这篇文章的时候,您是否已经完成前两篇介绍的文章里的功能了?(Tabs页的添加,Tabs页右键的关闭,主题的更换)                 2.今天来说说登录窗口吧,看截图: ...

  10. cargo实现自动化部署远程jetty容器(非安全模式)

    cargo实现自动化部署应用至远程jetty容器 (非安全模式) 一.准备: WAR包:Deployer Web application for the Jetty remote containers ...