代码随想录算法训练营Day04-链表 | LC024两两交换链表中的节点、LC019删除链表的倒数第N个节点、LC160相交链表、LC142环形链表Ⅱ | Java代码实现

前言

没提示会死,自己根本想不出来啊

LeetCode24.两两交换链表中的节点

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

思路

交换相邻两节点,需要操作连接它们的三个指针。
设置虚拟头节点。
第一次提交时没有考虑步骤一,导致链表出现分支。

在这里插入图片描述

完整代码

  class Solution {
      public ListNode swapPairs(ListNode head) {
          if (head == null)
              return null;
          ListNode pre = new ListNode(0, head);
          head = pre;
          while (pre.next != null && pre.next.next != null) {
              ListNode curr = pre.next;
              ListNode next = pre.next.next;
              curr.next = next.next; // 3
              next.next = curr; // 2
              pre.next = next; // 1
              pre = curr;
              
          }
          return head.next;
      }
  }

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

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

思路

快慢指针法:
设置虚拟头节点,初始快慢指针指向虚拟头节点。
先移动快指针n步,再同时移动快慢指针,当快指针遍历到末尾时,慢指针就指向了要删除的节点。
由于删除该节点要找到上一个节点,所以可以让快指针先走 n + 1 步。
此时快指针遍历到末尾时,慢指针恰好指向要删除节点的上一个。
执行删除操作。
编写代码时要注意判空,避免空指针异常。

完整代码

  class Solution {
      public ListNode removeNthFromEnd(ListNode head, int n) {
          ListNode dummyNode = new ListNode(0, head);
          ListNode slowIndex = dummyNode;
          ListNode fastIndex = dummyNode;
          while (n-- >= 0) {
              fastIndex = fastIndex.next;
          }
          while (fastIndex != null) {
              slowIndex = slowIndex.next;
              fastIndex = fastIndex.next;
          }
          slowIndex.next = slowIndex.next.next;
          return dummyNode.next;
      }
  }

LeetCode160.相交链表

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

思路

  • 方法一:
    求出两个链表的长度差,先移动长链表,对齐长度,然后一起移动。
    比较指针直到相等。

  • 方法二:
    设A链表相交前的节点个数为 a ,A链表相交前的节点个数为 b ,共同节点个数为 c
    A链表移动到末尾时跳转到B链表开始,A链表移动到末尾时跳转到B链表开始
    同时移动 a + b + c + 1 步时,恰好为相交节点
    如果没有相交部分,第 a + b + 1 步会同时为null,停止循环
    所以移动条件判断的是currA而不是currA.next
    currA.next不经过null位置,如果不相交就死循环了

注意:比较的是指针是否相等,即是否为同一个节点对象,而不是节点存储的值。

完整代码

  public class Solution {
    //  方法1
      public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
          ListNode currA = headA;
          ListNode currB = headB;
          int lenA = 0;
          int lenB = 0;
          while (currA != null) {
              lenA++;
              currA = currA.next;
          }
          while (currB != null) {
              lenB++;
              currB = currB.next;
          }
        //  让currA保存较长链表的头节点
          if (lenA >= lenB) {
              currA = headA;
              currB = headB;
          } else {
              currA = headB;
              currB = headA;
          }
        //  长链表先移动的步数
          int count = Math.abs(lenA - lenB);
          while (count-- > 0) {
              currA = currA.next;
          }
          while (currA != currB) {
              currA = currA.next;
              currB = currB.next;
          }
          return currA;
      }
  }
  public class Solution {
    //  方法2
      public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
          ListNode currA = headA;
          ListNode currB = headB;
          while (currA != currB) {
            //  移动A链表
              if (currA != null) {
                  currA = currA.next;
              } else {
                  currA = headB;
              }
            //  移动B链表
              if (currB != null) {
                  currB = currB.next;
              } else {
                  currB = headA;
              }
          }
          return currA;
      }
  }

LeetCode142.环形链表Ⅱ

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

思路

这道题目,不仅考察对链表的操作,而且还需要一些数学运算。

主要考察两知识点:

  • 判断链表是否环
  • 如果有环,如何找到这个环的入口
  1. 快慢指针,快指针一次走2步,慢指针一次走1步。
    如果有环会在环内相遇,因为进环就出不去了。
    没有环快指针会先遍历到空节点。
  2. 设入环前距离为x,相遇位置距环入口距离为y,剩余环距离为z
    可列方程,2 * (x + y) = x + n * (y + z) + y
    化简得 x = (n - 1) * (y + z) + z
    即从 相遇位置 和 起点 同时移动,会在环入口处相遇

完整代码

  public class Solution {
      public ListNode detectCycle(ListNode head) {
          ListNode slow = head;
          ListNode fast = head;
          ListNode index1 = null;
          ListNode index2 = head;
          while (fast != null && fast.next != null) {
              slow = slow.next;
              fast = fast.next.next;
              if (slow == fast) {
                  index1 = slow;
                  break;
              }
          }
          while (index1 != null && index1 != index2) {
              index1 = index1.next;
              index2 = index2.next;
          }
          return index1;
      }
  }

今日总结

完成比完美重要!完成比完美重要!完成比完美重要!
不要犯完美主义强迫症,虽然解法没写全,笔记总结了跟没总结一样。
下一章就离开舒适区了,一刷一定要坚持下来啊!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值