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

67 阅读3分钟

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

题目链接:LeetCode 24 - 中等

思路

看到交换链表中的节点,想到用迭代&虚拟头节点的方式

迭代法:

java
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dumphead = new ListNode(-1,head);

        ListNode temp;
        ListNode cur = dumphead;
        ListNode firstNode;
        ListNode secondNode;
        
        while(cur.next!=null && cur.next.next!=null){
            firstNode = cur.next;
            secondNode = cur.next.next;

            temp = cur.next.next.next;

            cur.next = secondNode;
            secondNode.next = firstNode;
            firstNode.next = temp;

            cur = firstNode;
        }
        return dumphead.next;
    }
}

总结

  1. 除了迭代法,可以使用递归的方式来解决该问题。
java
class Solution {
    public ListNode swapPairs(ListNode head) {
        // 递归版本

        //递归停止的条件
        if(head==null || head.next==null) return head;

        ListNode next = head.next;
        //递归的开始
        ListNode temp = swapPairs(next.next);

        next.next = head;
        //以下两条代码请注意
        head.next = temp; 
        return next;
    } 
}
  1. 在写代码的时候,增加一些注解可能更有助于理解。

删除链表的倒数第N个结点 LeetCode 19

题目链接:LeetCode 19 - 中等

思路

删除倒数第N个节点,第一反应想到的就是使用双指针的方式,但是由于是删除该节点,因此需要找到该节点的前一个节点。

一次扫描实现:

java
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode delete = head;
        ListNode endNode = head;

        for(int i=0;i<=n;i++){
            if(endNode == null){
                return head.next;
            }
            endNode = endNode.next;
        }

        while(endNode!=null){
            endNode = endNode.next;
            delete = delete.next;
        }
        delete.next = delete.next.next;
        return head;
    }
}

总结

  1. 在提交的过程中发现了如果要删除的元素为元素的第一个节点的时候,我们找到的endNode为null,因此将该特殊情况特殊处理。
  2. 在代码随想录中,给出的是采用快慢指针(即双指针)与虚拟头结点结合的方式,省去了我上述提到的特殊情况的特殊处理方式,使得代码更加间接易懂。

链表相交 LeetCode 面试题02.07

题目链接:LeetCode 面试题02.07 - 简单

思路

考虑过是否需要了解两个链表的长度,但是没有去尝试,而是想要使用双指针的方式。但是一直没有考虑出来。

时间复杂度为O(n):

java
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode tmpA = headA;
        ListNode tmpB = headB;
        int lenA = 0;
        int lenB = 0;
        while(tmpA!=null){
            lenA++;
            tmpA = tmpA.next;
        }
        while(tmpB!=null){
            lenB++;
            tmpB = tmpB.next;
        }
        tmpA = headA;
        tmpB = headB;
        //如果B比A的数据更多,将其互相交换
        if(lenB > lenA){
            int tmplen;
            tmplen = lenA;
            lenA = lenB;
            lenB = tmplen;

            ListNode tmp;

            tmp = tmpA;
            tmpA = tmpB;
            tmpB = tmp;
        }
        int gap = lenA - lenB;
        while(gap-- >0){
            tmpA = tmpA.next;
        }
        while(tmpA!=null){
            if(tmpA == tmpB){
                return tmpA;
            }
            tmpA = tmpA.next;
            tmpB = tmpB.next;
        }

        return null;
    }
}

总结

  1. 学习到了使用两个链表交换的方式来简化代码。
  2. 想到的东西马上去做去了解。

环形链表Ⅱ LeetCode 142

题目链接:LeetCode 142 - 中等

思路

首先是判断链表是否有环,其次是找到环的入口。考虑到了使用快慢指针来判断链表是否为环形链表,但是没有能够找到环的入口。

时间复杂度为O(n):

java
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fastNode = head;
        ListNode slowNode = head;
        while(fastNode!=null && fastNode.next!=null){
            fastNode = fastNode.next.next;
            slowNode = slowNode.next;
            if (fastNode == slowNode) {// 有环
                ListNode index1 = fastNode;
                ListNode index2 = head;
                // 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
                while (index1 != index2) {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }
}

总结

两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口