day4

1、leetcode24 两两交换链表中的节点

  1. 思路图解

    24.两两交换链表中的节点1

  2. 代码

    class Solution {
        public ListNode swapPairs(ListNode head) {
            ListNode dummyHead = new ListNode(0);
            dummyHead.next = head;
            ListNode cur = dummyHead;//cur节点作为辅助变量,遍历原链表,一定要指向要进行交换操作节点的前一个节点,才能保证能够对后面进行操作
    		
            //当cur.next==null表示遍历到偶数个节点的最后一个;
            //当cur.next.next==null表示遍历奇数个节点中剩下最后一个节点
            while(cur.next!=null && cur.next.next!=null){
                //记录两个临时节点,防止交换操作中,节点指向改变,无法正确操作
                ListNode temp = cur.next;
                ListNode temp1 = cur.next.next.next;
    
                cur.next = cur.next.next; //步骤一
                cur.next.next = temp; //步骤二
                temp.next = temp1; //步骤三
                
                cur = cur.next.next; // cur移动两位,准备下一轮交换
            }
    
            return dummyHead.next;
    
        }
    }
    

2、leetcode19 删除链表的倒数第N个节点

  1. 双指针法

    1. 双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。

      1. 注意:这里fast首先走n + 1步 ,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作)
    2. 步骤

      1. 定义fast指针和slow指针,初始值为虚拟头结点
      2. fast首先走n + 1步
      3. fast和slow同时移动,直到fast指向末尾null
      4. 删除slow指向的下一个节点
    3. 代码实现

      class Solution {
          public ListNode removeNthFromEnd(ListNode head, int n) {
              ListNode dummyHead =new ListNode(0);
              dummyHead.next = head;
              ListNode fast = dummyHead;
              ListNode slow = dummyHead;
              n++; //fast移动n+1步
      
              while(n>0 && fast != null){
                  fast = fast.next;
                  n--;
              }
      
              while(fast!=null){
                  fast = fast.next;
                  slow = slow.next;
              }
      
              slow.next = slow.next.next;
              return dummyHead.next;
      
          }
      }
      
  2. 将删除倒数第N个节点 ,转换为删除顺数索引为index = size-n的节点的问题(index从0开始)

    1. 代码实现

      class Solution {
          public ListNode removeNthFromEnd(ListNode head, int n) {
              ListNode dummyHead =new ListNode(0);
              dummyHead.next = head;
              ListNode cur = dummyHead.next;
              int size = 0;
              int index = 0;
      
              while(cur != null){
                  cur = cur.next;
                  size++;
              }
      
              index = size - n; //index从0开始
              cur = dummyHead; //cur要定位到要删除节点的前一个节点
              while(index>0){
                  cur = cur.next;
                  index--;
              }
              cur.next = cur.next.next;
      
              return dummyHead.next;
      
          }
      }
      

3、面试题 02.07. 链表相交

  1. 思路

    1. 注意:交点不是数值相等,而是指针相等。

    2. 求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置

      面试题02.07.链表相交_2

    3. 此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。否则循环退出返回空指针。

  2. 代码

    public class Solution {
        public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
            ListNode curA = headA;
            ListNode curB = headB;
            int sizeA = 0;
            int sizeB = 0;
    
            //求出链表A的长度
            while(curA != null){
                curA = curA.next;
                sizeA++;
            }
            
            //求出链表B的长度
            while(curB != null){
                curB = curB.next;
                sizeB++;
            }
    
            curA = headA;
            curB = headB;
    
            //让较长链表的cur移动至,和较短链表的头节点对齐的位置【让curA和curB在同一起点上(末尾位置对齐)】
            if(sizeA >= sizeB){
                for(int i=0; i < sizeA-sizeB;i++){
                    curA = curA.next;
                }
            } else {
                for(int i=0; i < sizeB-sizeA;i++){
                    curB = curB.next;
                }
            }
    
            //比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。
            while(curA != null){
                if(curA == curB){
                    return curA;
                }
                curA = curA.next;
                curB = curB.next;
            }
    
            return null;
            
        }
    }
    

4、leetcode142 环形链表Ⅱ

  1. 如何判断链表是否有环?

    1. 采用快慢指针法。
      1. 分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
      2. 分析:
        1. fast指针一定先进入环中,如果fast指针和slow指针相遇的话,一定是在环中相遇,一定是快指针去追慢指针
        2. 因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow相遇。
  2. 已经有环存在,如何找到这个环的入口?

    1. img

    2. 相遇时,慢指针走过节点数2 = 快指针走过节点数,n为fast指针在环内走了n圈才遇到slow指针,n>=1
      $$
      (x+y)
      2 = x+y+n(y+z)
      $$

      $$
      x=(n-1)(y+z)+z, n>=1
      $$

      当 n为1的时候,公式就化解为 x = z

      当n大于1时,就是fast指针在环形转n圈之后才遇到 slow指针。

      其实这种情况和n为1的时候 效果是一样的,一样可以通过这个方法找到 环形的入口节点,只不过,index1 指针在环里 多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点。

    3. 从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。(x = z)

  3. 代码

    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;
    
                // 快慢指针相遇,说明有环,此时从head 和 相遇点,同时查找直至相遇
                if(fast == slow){
                    ListNode index1 = fast;
                    ListNode index2 = head;
    
                    while(index1!=index2){
                        index1 = index1.next;
                        index2 = index2.next;
                    }
    
                    return index1;// 返回环的入口
                }
            }
            
            return null;
        }
    }
    
posted @ 2023-01-14 22:45  黄三七  阅读(28)  评论(0)    收藏  举报