代码随想录【力扣刷题】第四天 || 24两两交换链表中的交点 || 19.删除链表的倒数第N个节点 ||面试题 02.07. 链表相交

目录

24 两两交换链表中的节点

题目链接

题目要求

思路分析

代码如下

本题收获

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

题目链接

题目要求

思路分析 

代码如下

本题收获

面试题 02.07. 链表相交 

题目链接

题目要求

思路分析

代码如下

 本题收获


24 两两交换链表中的节点

题目链接

24. 两两交换链表中的节点 - 力扣(LeetCode)

题目要求

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

思路分析

以1→2→3→4为例

  1. 我很早之前做这个题目,想的是1→2,变成2→1 然后3→4,变成4→3,但是这种想法,很难去实现,因为没有固定的“变化”,即没有规律。当2→1 完成后,链表是2→1→3→4,后续很难处理。没有彻底掌握
  2. 2022年9月24日19:01:30 再写这道题目时,首先我想到了需要加一个虚拟节点。一部分是因为:需要返回新的头结点,有虚拟节点的话方便操作,另一部分是:加上虚拟节点之-1→1→2→3→4。  三个节点为一个周期,第一个节点不变,交换后面两个交点,-1→2→1→3→4,然后temp 向后移动两个位置。再三个节点为周期。直到不需要交换。
  3. while()循环的判定条件,java中要特别注意:NullPointer 空指针异常。由2可得:三个节点为周期,所以三个节点都要存在,如果最后之后只剩两个节点时就不需要交换。while(temp.next.next!=null){}.此时存在空指针异常的可能性,所以这里的while()循环条件要写的全面。


此处引用公众号“代码随想录”的图片

代码如下

class Solution {
    public ListNode swapPairs(ListNode head) {
        // 先判断链表是否为空
        if(head==null){
            return head;
        }
        else{
            // 生成一个虚拟头结点
            ListNode dummy=new ListNode(-1,head);
            ListNode temp=dummy;
            ListNode cur=null;
            ListNode curNext=null;

            while (temp!=null&&temp.next!=null&&temp.next.next!=null) { // while() 循环可能没写对
                cur=temp.next;
                curNext=cur.next;
                temp.next=curNext;
                cur.next=curNext.next;
                curNext.next=cur;
                // 三个节点为一个周期,所以temp 移动两个位置
                temp=cur;
            }
            head =dummy.next;
            return  head;
        }

    }
}

本题收获

  • 自己解决问题的能力。我能把三个节点为周期,实现交换的目的想明白,但是卡在了while()循环的判定条件,我第一次写while(temp,next.next!=null),自己也知道一定会发生nullpointer 异常,最开始不知道如何去改,当下有想过去看答案怎么写,但是不太想轻易放弃,后面又认真琢磨了以下,决定把while()循环条件写的全面一点,给了自己最后10min时间思考,避免死磕。
  • 注意细节问题

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

题目链接

19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

题目要求

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

  • 链表中结点的数目为 sz
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz

思路分析 

  1. 暴力解法,两遍for循环,第一次先遍历出整个链表的长度length,第二遍去寻找length-n的节点,这样操作的时间复杂度是O(n^2),这是我很早之前第一遍的做法。
  2. 在2022年9月28日晚上,我回忆起来 :代码随想录上的思路“快慢指针”。让快指针比慢指针先走n步,这样当fast 走到链表的末尾,慢指针刚好指向被删除节点的前驱。
  3. 关于细节问题,while()循环中的条件怎么写?
    1. 我的建议是以题目中的示例1→2→3→4→5 为例,n=2,自己手动模拟一遍。
    2. 以及认真看题目的提示。这里面包含了我应该如何处理一些特殊问题,在这个问题中我不需要判断链表是否为空,因为1 <= sz <= 30

代码如下

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
//     需要创建一个虚拟节点,万一删除操作之后,头结点发生了变化
        ListNode dummy=new ListNode (-1,head);
//      使用快慢指针法,让快指针比慢指针先走n步,这样当快指针到达链表的末尾元素时,
//        慢指针刚好指向被删除节点的前驱结点。
        ListNode slow=dummy;
        ListNode fast=dummy;
        while (n>0){
            fast=fast.next;
            n--;
        }
        while(fast.next!=null){
            fast=fast.next;
            slow=slow.next;
        }
//       此时,慢指针slow指向被删除节点的前驱元素
        slow.next=slow.next.next;
        head=dummy.next;
        return  head;
    }
}

本题收获

  • 开心自己能在二刷这个题目的时候,想到了“快慢指针法”,不再使用暴力解法
  • 更加熟练的处理边界条件。给自己点赞。

面试题 02.07. 链表相交 

题目链接

面试题 02.07. 链表相交 - 力扣(LeetCode)

题目要求

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

思路分析

  1. 这个图可以很直观的看出:当两个值val相等时,并不是相交的起始点,而是指向相同的节点要关注next值。
  2. “尾部对齐” :当两个链表相交时,从相交起始节点到链表的尾部是重合的,因此需要从两个不同的链表相同的位置开始遍历,寻找相交起始节点。
    1. 如何找到两个不同链表的同一位置开始遍历?
      1. 分别求出两个链表的长度,然后较长的链表-较短链表的长移动长链表的head
  3. 这个题目:两个链表可以是空链表,所以需要判断是否为空的特殊情况。

图一

代码如下

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA==null || headB==null){
            return  null;
        }
//        分别求出链表A、B的长度
        int lengthA=0;
        int lengthB=0;
        ListNode tempA=headA;
        ListNode tempB=headB;
        while (tempA!=null){
            lengthA++;
            tempA=tempA.next;
        }
        while (tempB!=null){
            lengthB++;
            tempB=tempB.next;
        }
//      从同一起点开始遍历
        if(lengthA>lengthB){
            int move_num=lengthA-lengthB;
            while (move_num>0){
                headA=headA.next;
                move_num--;
            }
        }
        else{
            int move_num=lengthB-lengthA;
            while (move_num>0){
                headB=headB.next;
                move_num--;
            }
        }
     
        while (headA!=headB){
            headA=headA.next;
            headB=headB.next;
        }

        // 需要考虑不相交的情况
        if(headA!=null){
            return  headA;
        }
        else {
            return  null;
        }

    }
}

 本题收获

  • 这个题目算是1.5刷,之前一刷的时候,这个题目连代码可能都没有看懂,大概只记得了一个“尾部对齐”的思路,这次顺着这个思路,大概想到了要求出链表的长度,然后再从不同链表的同一起点开始遍历。
  • 考虑问题更加全面,当两个链表均不为空的时候,也存在不相交的可能,也要考虑进去。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值