算法 - 链表2

78 阅读2分钟

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

题目以及讲解

一定要画图,然后看图写代码。 否则下面那堆next 你一定会晕。

// @lc code=start
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public var val: Int
 *     public var next: ListNode?
 *     public init() { self.val = 0; self.next = nil; }
 *     public init(_ val: Int) { self.val = val; self.next = nil; }
 *     public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
 * }
 */
class Solution {
    func swapPairs(_ head: ListNode?) -> ListNode? {
        let dummyNode = ListNode(0, head)
        var curNode: ListNode? = dummyNode
        while curNode?.next != nil, curNode?.next?.next != nil {
            let temp1 = curNode?.next
            let temp2 = curNode?.next?.next?.next
            curNode?.next = curNode?.next?.next
            curNode?.next?.next = temp1
            temp1?.next = temp2

            curNode = curNode?.next?.next
        }
        return dummyNode.next
    }
}
// @lc code=end

题目2: 19.删除链表的倒数第N个节点

题目以及讲解

思考: 双指针还比较容易想到这种解法, 但是边界,也就是找被删除节点的上一个节点, 需要认真校对一下。
我用这个判断 while fast?.next != nil 让fast少走了一步
以至于最终slow可以定位在被删除节点的上一个节点。

// @lc code=start
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public var val: Int
 *     public var next: ListNode?
 *     public init() { self.val = 0; self.next = nil; }
 *     public init(_ val: Int) { self.val = val; self.next = nil; }
 *     public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
 * }
 */
class Solution {
    func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
        let dummyNode: ListNode? = ListNode(0, head)
        var fast = dummyNode
        var slow = dummyNode
        for _ in 0..<n {
            fast = fast?.next
        }
        if fast == nil {
            return dummyNode?.next
        }
        while fast?.next != nil {
            fast = fast?.next
            slow = slow?.next
        }
        slow?.next = slow?.next?.next
        return dummyNode?.next
    }
}
// @lc code=end

题目3: 160.链表相交

题目以及讲解

对齐节点后开始遍历。 一开始没想出来,思路还是要多再回忆几次。 这里可以提一下swift版本题解

// @lc code=start
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public var val: Int
 *     public var next: ListNode?
 *     public init(_ val: Int) {
 *         self.val = val
 *         self.next = nil
 *     }
 * }
 */

class Solution {
    func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? {
        var lenA = 0
        var lenB = 0
        // 定义较长链表 和 较短链表
        var longNode = headA
        var shortNode = headB
        while longNode != nil {
            longNode = longNode?.next
            lenA += 1
        }
        while shortNode != nil {
            shortNode = shortNode?.next
            lenB += 1
        }
        var gap = abs(lenA - lenB)
        // 确保longNode 指向较长的链表
        if lenB > lenA {
            longNode = headB
            shortNode = headA
        } else {
            longNode = headA
            shortNode = headB
        }
        while gap > 0 {
            gap -= 1
            longNode = longNode?.next
        }
        while longNode != nil {
            if longNode === shortNode {
                return longNode
            }
            longNode = longNode?.next
            shortNode = shortNode?.next
        }
        return nil
    }
}

// @lc code=end

题目4: 142.环形链表II

题目以及讲解

过程的确有很多证明需要理解, 可以先记下来了。

class Solution {
    func detectCycle(_ head: ListNode?) -> ListNode? {
        var slow: ListNode? = head
        var fast: ListNode? = head
        while fast != nil && fast?.next != nil {
            slow = slow?.next
            fast = fast?.next?.next
            if slow === fast {
                // 环内相遇
                var list1: ListNode? = slow
                var list2: ListNode? = head
                while list1 !== list2 {
                    list1 = list1?.next
                    list2 = list2?.next
                }
                return list2
            }
        }
        return nil
    }
}