Bootstrap

代码随想录算法训练营第4天| 24. 两两交换链表中的节点;19.删除链表的倒数第N个节点 ; 面试题 02.07. 链表相交 ; 142.环形链表II ; 总结

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

Leetcode链接: link

class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode dummyhead = new ListNode(0);
        dummyhead.next = head;
        ListNode previous = dummyhead;
        ListNode node1 = dummyhead.next;
        while(node1 != null && node1.next != null){
            ListNode node2 = node1.next;
            ListNode temp = node2.next;

            previous.next = node2;
            node2.next = node1;
            node1.next = temp;
            previous = node1;
            node1 = temp;
        }
        return dummyhead.next;
    }
}

这一题目要使用的三个不同的指针,如 代码随想录说的一样,看了图之后才能理顺很多东西,不然只能在脑海里自己构思每个指针的连接方法。

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

Leetcode链接: link

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyhead = new ListNode(0);
        dummyhead.next =  head;
        ListNode front = dummyhead;
        ListNode end = dummyhead;
        for(int i = 0; i < n+1 ; i++){
            if(end == null){
                return dummyhead.next;
            }else{
                end = end.next;
            }
        }
        while(end != null){
            end = end.next;
            front = front.next;
        }
        front.next = front.next.next;
        return dummyhead.next;
    }
}

这题和之前的array有一题很像,也是删除array倒数的第几个element。做法其实是一样的,用快慢指针就可以在O(n)的时间内找到要删除的node的位置。先让end指针先走n+1步,然后再让front指针和end指针一起走,知道end指针达到最后。以为我们删除node需要在目标node前面一个node位置来删除。如果是array那题的话就不需要,end可以先走n步。

面试题 02.07.链表相交

Leetcode链接: link

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        ListNode node1 = headA, node2 = headB;
        int len1 = 0;
        int len2 = 0;
        
        while(node1 != null){
            len1++;
            node1 = node1.next; 
        }
        while(node2 != null){
            len2++;
            node2 = node2.next; 
        }
        
        node1 = headA;
        node2 = headB;
        if(len1 > len2){
            for(int i = 0; i < len1-len2; i ++){
                node1 = node1.next;
            }
        }else if(len1 < len2){
            for(int i = 0; i < len2-len1; i ++){
                node2 = node2.next;
            } 
        }

        while (node1 != null) {
            if(node1 == node2){
                return node1;
            }
            node1 = node1.next;
            node2 = node2.next;

        }
        return null;
    }
}

这题是比较有意思的一题,我一开始想的方法和代码随想录上面的方法差不多。就是先遍历一遍,然后再把长的那个linkedlist的前面部分读完,再和短的一起读。后来看到官网有一种更加简洁的方法:

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        
        ListNode node1 = headA;
        ListNode node2 = headB;
        
        while (node1 != node2) {
            if (node1 == null) {
                node1 = headB; // 如果 node1 到达了链表末端,则切换到链表B的头部
            } else {
                node1 = node1.next;
            }
            
            if (node2 == null) {
                node2 = headA; // 如果 node2 到达了链表末端,则切换到链表A的头部
            } else {
                node2 = node2.next;
            }
        }
        
        return node1; // 返回相交节点,或在没有相交时返回 null
    }
}

这个方法理解起来也很简单,就是在一个循环里,node1先向headA走,走完再走一遍headB,等于是走headA+headB的linkedlist,node2就相反先走headB再走headA,等于是走headB+headA的linkedlist.如果A和B在一个地方合体了,那他们的尾部肯定是一样的。而且他们长度也是一样的。

请添加图片描述

142.环形链表II

Leetcode链接: link

//hash table
public class Solution {
    public ListNode detectCycle(ListNode head) {
        Set<ListNode> set = new HashSet<ListNode>();
        ListNode temp = head;
        while (temp != null) {
            if(set.contains(temp)){
                return temp;
            }else{
                set.add(temp);
            }
            temp = temp.next;
        }
        return null;
    }
}

第一想法就是使用hash table。把所有的node一个个添加到hash table里面。然后每次添加的时候检测hash table里是否又这个node,如果有就说明遇到了cycle。如果到最后变成null了就说明没有cycle。另外还有一个快慢指针的方法。他们的时间复杂度都是一样的O(n),空间复杂度则是hash table O(n), 快慢指针O(1).

总结

其实感觉没什么好总结的,个人感觉linkedlist只要理解了,其实比array还简单很多,因为array的玩法比linkedlist多很多。

;