leetcode-zgd-day4-24.两两相交链表中的节点/19.删除链表的倒数第N个节点/面试题 02.07. 链表相交/142.环形链表II

1,185 阅读3分钟

24.两两相交链表中的节点

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

该题目本文将以普通循环方式以及递归的方式来进行解题

添加头结点的方式:

 public ListNode swapPairs(ListNode head) {
     // 添加头结点
     if(head == null || head.next == null) return head;
     ListNode nHead = new ListNode(-1,head);
     ListNode p = nHead;
     while(p.next != null && p.next.next != null){
         ListNode q = p.next;
         ListNode r = p.next.next;
         q.next = r.next;
         p.next = r;
         r.next = q;
         p = q;
     }
     return nHead.next;
 }

不添加头结点的方式:

 public ListNode swapPairs(ListNode head) {
     // 不添加虚拟头节点的写法
     if(head == null || head.next == null) return head;
     ListNode p = head.next;
     head.next = p.next;
     p.next = head;
     ListNode q = p.next;
     while(q.next != null && q.next.next != null){
         ListNode n = q.next;
         ListNode nn = q.next.next;
         n.next = nn.next;
         q.next = nn;
         nn.next = n;
         q = n;
     }
     return p;
 }

递归方式:

 public ListNode swapPairs(ListNode head) {
     // 递归方式,前提:能够将问题分解为相同的较小的子问题
     if(head == null || head.next == null) return head;
     ListNode node1 = head;
     ListNode node2 = head.next;
     ListNode node3 = swapPairs(head.next.next);
     node2.next = node1;
     node1.next = node3;
     return node2;
 }

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

题目链接:代码随想录 (programmercarl.com)

这个题目一共两种解题思路:笨方法:遍历整个链表,看具体有多少个结点,再根据节点数判断要删除结点的正向位置,最差需要遍历链表。

 public ListNode removeNthFromEnd(ListNode head, int n) {
     if(head.next == null) return null;
     int m = 0;
     ListNode p = head;
     while(p != null){
         p = p.next;
         m++;
     }
     int time = m - n - 1;
     if(time == -1) return head.next;
     p = head;
     while(time > 0){
         p = p.next;
         time--;
     }
     p.next = p.next.next;
     return head;
 }

方法二:双指针法,该方法利用双指针之间的距离差,可以在只遍历一次的情况下确定要删除元素的位置。

 public ListNode removeNthFromEnd(ListNode head, int n) {
     // 设一个虚拟头结点
     ListNode nHead = new ListNode(-1,head);
     ListNode fast = nHead;
     ListNode slow = nHead;
     while(n > 0){
         fast = fast.next;
         n--;
     }
     while(fast.next != null){
         fast = fast.next;
         slow = slow.next;
     }
     slow.next = slow.next.next;
     return nHead.next;
 }

面试题 02.07. 链表相交

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

解题思路:首先确定两个链表的长度差,先移动长链表的指针,移动到指定位置,然后长短链表共同往后移动指针,看何时两个指针指向相同结点,注意!不是判断两个指针指向结点的值是否相等,而是判断结点是否是同一个结点

 public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
     ListNode p = headA;
     ListNode q = headB;
     int lenA = 0, lenB = 0;
     while(p != null){
         lenA++;
         p = p.next;
     }
     while(q != null){
         lenB++;
         q = q.next;
     }
     if(lenB < lenA){
         ListNode temp = headA;
         headA = headB;
         headB = temp;
     }
     p = headA;
     q = headB;
     int time = lenB > lenA ? lenB - lenA : lenA - lenB;
     while(time > 0){
         q = q.next;
         time--;
     }
     while(p != q){
         p = p.next;
         q = q.next;
     }
     return p;
 }

142.环形链表II

题目链接:142. 环形链表 II - 力扣(LeetCode)

解题思路:

经验教训:最初因为设置slow和fast都为头结点开始,为了避免if(fast == slow)直接触发,所以先在循环外执行了一次fast和slow指针的移动,然后再做while(fast != null && fast.next != null)的循环。但是实际上这样做是多余的。问题就在于没有理清先判断什么后判断什么?

实际上应该先判断是否有环,有环就一直循环下去知道找到答案,所以最外层循环就是保证fast指针的下移是合法的,也就是while(fast != null && fast.next != null)。

在有环的前提下,还需要考虑有一个或者两个结点的环是否需要单独考虑,这套逻辑是否有漏洞。根据代码模拟,发现有环情况下一个或者两个结点的环并不需要单独考虑。这是代码就已经形成了。

不要在开始之前对进行特殊处理,例如此题不要先在循环外进行一次fast和slow指针的移动,可能只是逻辑没有捋顺清楚。

每当有特殊情况需要处理时,都要问自己一下这样做真的有必要吗?正常情况是否已经涵盖了这种情况。

 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 p = head;
             while(p != slow){
                 p = p.next;
                 slow = slow.next;
             }
             return p;
         }
     }
     return null;
 }