力扣刷题记录(Java)按代码随想录顺序——链表篇

203 移除链表元素 

203. 移除链表元素icon-default.png?t=N7T8https://leetcode.cn/problems/remove-linked-list-elements/


题目描述:

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

解题思路:

链表的题,一般加一个虚拟头结点dummy head会更好处理,即处理规则会比较统一。否则有时候要分是否为头结点进行讨论。本题采用加dummy head的方法。

用一个指针cur去遍历链表。由于我们删除链表结点时,要拿到该结点的上一个结点,让其指向下下一个结点,就可以删除该结点。所以此处cur的含义是:我们删除结点的上一个结点

Java小知识:

1. Java里不是“->”,而是“.”。

2. 创建ListNode的时候,力扣给出的代码是直接用了int,实际上还可以用泛型<T>,可惜我忘了,到时候要补一下泛型的知识。

放一下易错的地方:

不写else的话,如果连着两个结点的值都等于val,会有一个被忽略。

力扣代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummyHead = new ListNode(val-1,head);
        ListNode cur = dummyHead;//临时指针,指向要删的结点的前一个
        while(cur.next != null){
            if(cur.next.val == val) cur.next = cur.next.next;
            else cur = cur.next;
        }
        return dummyHead.next;
    }
}

本地代码:

我在本地debug,用了两个类,放在同一个package下。

Solution类:

在main函数中,手动创建了链表。l3和l33的值都为3。

package lc203;

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummyHead = new ListNode(val-1,head);
        ListNode cur = dummyHead;//临时指针,指向要删的结点的前一个
        while(cur.next != null){
            if(cur.next.val == val) cur.next = cur.next.next;
            else cur = cur.next;
        }
        return dummyHead.next;
    }


    public static void main(String[] args) {
        Solution solution = new Solution();
        //创建一个链表,头结点是l1,共5个结点。
        ListNode l5 = new ListNode(5,null);
        ListNode l4 = new ListNode(4,l5);
        ListNode l3 = new ListNode(3,l4);
        ListNode l33 = new ListNode(3,l3);
        ListNode l2 = new ListNode(2,l33);
        ListNode l1 = new ListNode(1,l2);

        ListNode cur = l1;
        while(cur != null){//cur是要打印的结点,和之前函数中的cur意义不一样
            System.out.print(cur.val);
            cur = cur.next;
        }

        solution.removeElements(l1,3);

        ListNode cur2 = l1;
        while (cur2 != null){
            System.out.print(cur2.val);
            cur2 = cur2.next;
        }
    }
}

ListNode类:

直接复制力扣上的描述

package lc203;

//Definition for singly-linked list.

public class ListNode {
    int val;
    ListNode next;
    ListNode() {}
    ListNode(int val) { this.val = val; }
    ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

206 反转链表 

206. 反转链表icon-default.png?t=N7T8https://leetcode.cn/problems/reverse-linked-list/

题目描述:

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

解题思路: 

这题很折磨,缝缝补补改来改去好几次。

我的思路是这样的,相当于三个指针在动,核心是让cur指向pre,tmp是用于暂存后面结点的,以免丢失后面的结点。如图所示,带有圆圈的1 2 3 4是步骤顺序。

要注意的点:

1. while循环的进入条件,是cur!=null,之前想写cur.next!=null,你就想cur为最后一个结点时,进不进循环,实际是要进的,因为最后一个结点还没指向倒数第二个结点呢,所以不能这么写。还有就是,可以写成while(cur)这样更简洁。

1个月后更新:Java里好像不能这样写,会报错

2. 初始化条件要注意,我之前初始化写的是:

ListNode pre = head;
ListNode cur = head.next;//不能这样写,可能会是空链表。。。
ListNode tmp = cur.next;

这样就没考虑到传进来的链表可能是空链表的情况,head就是null,head没有next,更没有head.next.next。

所以我改成了这样,相当于三个指针一起往前挪了一位。

ListNode pre = null;
ListNode cur = head;
ListNode tmp = cur.next;

 结果还是错的,因为tmp还是cur.next,说了一百遍cur可能没有next

所以要把tmp放在循环里面去定义,因为进循环首先就要判断cur是否为空,这样就可以避免空指针异常。

3. (也算是初始化问题吧)还要说的就是,反转链表不是从第二个结点指向第一个结点开始,而是从第一个结点指向null开始。为什么呢?因为如果你从第二个结点开始,那相当于第一个结点的next还是第二个结点,那么假设原链表是12345,你按反转顺序打印本该是54321,结果你的第一个结点没处理,打印出来就是54321212121212121212121无限循环。这个第一个结点,反转后相当于尾结点,请记住,尾结点的next是null

力扣代码:

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while(cur!=null){//之前想写cur.next!=null,你就想最后一个结点进不进循环,实际是要进的,所以不能这么写
            ListNode tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
            if(tmp!=null) tmp = tmp.next;
        }
        return pre;//返回尾结点
    }
}

24 两两交换链表中的节点

. - 力扣(LeetCode)

题目描述:

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

解题思路:

先分情况讨论:链表偶数个节点的话,两两交换;链表奇数个节点的话,最后一个节点不用管。

操作的指针(cur)一定要指向要反转的2个节点的前1个节点。 

循环终止条件为(cur.next!=null && cur.next.next!=null),相当于cur后面必须要有至少两个节点

力扣代码:

搞了三个tmp,懒得想到底哪个节点要暂存

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummyHead = new ListNode(-1,head);
        ListNode cur = dummyHead;
        while(cur.next!=null && cur.next.next!=null){
            //不管了直接搞三个tmp,就不用想哪个要暂存 哪个不用暂存了
            ListNode tmp1 = cur.next;
            ListNode tmp2 = cur.next.next;
            ListNode tmp3 = cur.next.next.next;
            cur.next = tmp2;
            tmp2.next = tmp1;
            tmp1.next = tmp3;
            cur = cur.next.next;
        }
        return dummyHead.next;
    }
}

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

19. 删除链表的倒数第 N 个结点icon-default.png?t=N7T8https://leetcode.cn/problems/remove-nth-node-from-end-of-list/

题目描述:

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

解题思路:

快慢指针,fast领先n+1个,因为slow要指向要删除节点的前一个。

(自己随便找个例子,简单画个图就知道到底领先几个了)

力扣代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyHead = new ListNode(-1,head);
        ListNode fast = dummyHead;
        ListNode slow = dummyHead;
        for(int i=0;i<n+1;i++){//fast先走n+1步
            fast = fast.next;
        }
        while(fast!=null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dummyHead.next;
    }
}

142 环形链表2

. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/linked-list-cycle-ii题目描述:

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

解题思路:

快慢指针,如图所示,fast走的路程为x+y+n(y+z),slow走的路程为x+y。

要注意的点:

1. 为什么快慢指针一定会相遇,而不是快指针跳过慢指针?入环后,相当于fast在以每次一个节点的速度靠近慢指针,所以一定会相遇。

2. 为什么慢指针一定不到一圈?慢指针进入环的时候,两个指针相差的节点数一定小于一圈,相对速度是1,所以一圈内必被追上。

3. 如下图,懒得打字了

4. 写代码的时候,我犯了一个错误,看下面代码注释掉的那行,我在while(index1!=index2)的里面写了if(index1==index2) return xxx;这样不行,因为有可能一开始index1就与index2相等,进不了while,到不了if,就永远出不了外层循环。

力扣代码:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while(fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast==slow){
                ListNode index1 = slow;//快慢指针相遇点
                ListNode index2 = head;//起点
                while(index1!=index2){//这俩指针同时出发,在入环第一个节点相遇
                    index1 = index1.next;
                    index2 = index2.next;
                    // if(index1 == index2) return index1;//为什么不能这样写:可能一开始index1就和index2相等,进不了这个while循环,就出不了外面的大循环
                }
                return index1;
            }
        }
        return null;
    }
}

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值