代码随想录day04

发布时间 2023-06-11 00:05:32作者: 白展堂17
 
 

第二章 链表part02

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

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

虚拟头节点

/**
 * 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 dummynode = new ListNode(0);
        dummynode.next = head;
        // 设置当前节点cur
        ListNode cur = dummynode;
        // 循环退出条件:
        while (cur.next != null && cur.next.next != null){
            // 两两交换
            ListNode node1 = cur.next;
            ListNode node2 = node1.next;
            cur.next = node2;
            node1.next = node2.next;
            node2.next = node1;
            cur = node1;
        }
        return dummynode.next;
    }
}

 

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

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

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        // 双指针法
        ListNode dummy = new ListNode(0, head);
        ListNode fast = head;
        ListNode slow = dummy;
        // fast 先向前n步
        for (int i = 0; i < n; i++){
            fast = fast.next;
        }
        // slow fast 同步向前遍历,直到fast到底为null,注意slow和fast之间的间距为n+1
        while (fast!= null){
            fast = fast.next;
            slow = slow.next;
        }
        // 删除slow.next 节点
        slow.next = slow.next.next;
        return dummy.next;
    }
}

 

面试题 02.07. 链表相交 

class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        // 方法一 先遍历两个链表,求出差值,尾部对齐,再从对齐处开始往遍历,找第一次重合即可
        ListNode a = headA;
        ListNode b = headB;
        // 求出两个链表的长度
        int lenA = 0;
        int lenB = 0;
        while (a != null) {
            a = a.next;
            lenA++;
        }
        while (b != null) {
            b = b.next;
            lenB++;
        }
        // 重置头结点
        a = headA;
        b = headB;
        // 让a为长链
        if (lenA < lenB) {
            // 1. swap (lenA, lenB);
            int tmpLen = lenA;
            lenA = lenB;
            lenB = tmpLen;
            // 2. swap (curA, curB);
            ListNode tmpNode = a;
            a = b;
            b = tmpNode;
        }

        // 求长度差
        int gap = lenA - lenB;
        // a先动,对齐
        while (gap > 0) {
            a = a.next;
            gap--;
        }

        // 一起动
        while (a != null) {
            if (a == b) {
                return a;
            }
            a = a.next;
            b = b.next;
        }
        return null;

        // // 方法二 双指针 一个先遍历a然后遍历b,另一个先遍历b然后遍历a,第一次重合即可
        // ListNode node1 = headA;
        // ListNode node2 = headB;
        // while (node1 != node2){
        //     if (node1 == null){
        //         node1 = headB;
        //     }else{
        //         node1 = node1.next;
        //     }

        //     if (node2 == null){
        //         node2 = headA;
        //     }else{
        //         node2 = node2.next;
        //     }
        // }
        // return node1;
    }
}

 

142.环形链表II 

哈希表法

快慢指针法 后续继续学习

class Solution {
    public ListNode detectCycle(ListNode head) {
        // 方法1 哈希表
        // 当前节点cur
        ListNode cur = head;
        // 哈希表
        Set<ListNode> visited = new HashSet<ListNode>();
        // cur遍历,存到哈希表内,出现重复的就是环入口
        while (cur != null){
            if (visited.contains(cur)){
                return cur;
            }else{
                visited.add(cur);
            }
            cur = cur.next;
        }
        return null;
        // 方法2 快慢指针
        // 暂时无法理解
    }
}