LeetCode单链表相关题目

67 阅读4分钟

237. 删除链表中的节点 leetcode.cn/problems/de…

有一个单链表的 head,我们想删除它其中的一个节点 node。

给你一个需要删除的节点 node 。你将 无法访问 第一个节点 head。

链表的所有值都是 唯一的,并且保证给定的节点 node 不是链表中的最后一个节点。

删除给定的节点。注意,删除节点并不是指从内存中删除它。这里的意思是:

给定节点的值不应该存在于链表中。

链表中的节点数应该减少 1。

node 前面的所有值顺序相同。

node 后面的所有值顺序相同。

public class ListNode {
    public var val: Int
    public var next: ListNode?
    public init(_ val: Int) {
        self.val = val
        self.next = nil
    }
}

class Solution {
    func deleteNode(_ node: ListNode?) {
        node?.val = (node?.next?.val)!
        node?.next = node?.next?.next
    }
}

206. 反转链表 ttps://leetcode.cn/problems/reverse-linked-list/description/

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

通过递归和迭代两种方法实现

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
    }
}
// 递归
func reverseList(_ head: ListNode?) -> ListNode? {
    if head == nil || head?.next == nil { // 空链表或者只有一个结点直接return
        return head
    }
    let newHead = reverseList(head?.next) // 已经翻转
    head?.next?.next = head // 已经翻转过的链表的最后一个结点(即head.next)的next指向头结点
    head?.next = nil // 将头结点的next置为nil
    return newHead
}

// 1 2
// 1.next.next = 1, 1.next = null -> 2.next = 1, 1.next = null

// 1 2 3
// head = 3
// 1.next.next = 1, 1.next = null -> 2.next = 1, 1.next = null
// 2.next.next = 2, 2.next = null -> 3.next = 2, 2.next = null

// 1 2 3 4
// head = 4
// 1.next.next = 1, 1.next = null -> 2.next = 1, 1.next = null
// 2.next.next = 2, 2.next = null -> 3.next = 2, 2.next = null
// 3.next.next = 3, 3.next = null -> 4.next = 3, 3.next = null
// 迭代
func reverseList2(_ head: ListNode?) -> ListNode? {
    if head == nil || head?.next == nil { // 空链表或者只有一个结点直接return
        return head
    }
    var tempHead = head
    var newHead: ListNode?
    while tempHead != nil {
        let temp = tempHead?.next
        tempHead?.next = newHead
        newHead = tempHead
        tempHead = temp
    }
    return newHead
}

测试代码:

let s = Solution()
var node0 = ListNode(0, nil)
var node1 = ListNode(1, node0)
var node2 = ListNode(2, node1)
var node3 = ListNode(3, node2)
// 初始链表:3 -> 2 -> 1 -> 0 -> nil
//s.reverseList2(node3)
// 翻转后链表:0 -> 1 -> 2 -> 3 -> nil

141. 环形链表 leetcode.cn/problems/li…

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

class Solution_141 {
    // 快慢指针
    func hasCycle(_ head: ListNode?) -> Bool {
        if head == nil || head?.next == nil {
            return false
        }
        var slow = head
        var fast = head?.next
        
        while fast != nil, fast?.next != nil {
            slow = slow?.next
            fast = fast?.next?.next
            
            // === 是比较两个对象的地址是否相等,不能用==是因为listNode不满足equalable协议
            if slow === fast {
                return true
            }
        }
        return false
    }
}

测试代码:

let s = Solution_141()
var node0 = ListNode(0, nil)
var node1 = ListNode(1, node0)
var node2 = ListNode(2, node1)
var node3 = ListNode(3, node2)
print(s.hasCycle(node3)) // false
node0.next = node2
print(s.hasCycle(node3)) // true

203. 移除链表元素 leetcode.cn/problems/re…

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

class Solution_203 {
    func removeElements(_ head: ListNode?, _ val: Int) -> ListNode? {
        if head == nil {
            return head
        }
        let newHead = ListNode(-1, head) // 增加一个虚拟头结点
        var prev: ListNode? = newHead
        while prev?.next != nil {
            if prev?.next?.val == val {
                prev?.next = prev?.next?.next
            } else {
                prev = prev?.next
            }
        }
        return newHead.next // 虚拟头结点的next一定是head
    }
}

测试代码:

let s = Solution_203()
var node0 = ListNode(6, nil)
var node1 = ListNode(5, node0)
var node2 = ListNode(4, node1)
var node3 = ListNode(3, node2)
var node4 = ListNode(6, node3)
var node5 = ListNode(2, node4)
var node6 = ListNode(1, node5)
let head = s.removeElements(node6, 1)

83. 删除排序链表中的重复元素 leetcode.cn/problems/re…

给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

class Solution_83 {
    func deleteDuplicates(_ head: ListNode?) -> ListNode? {
        if head == nil || head?.next == nil {
            return head
        }
        var current = head
        // 链表已经排序,故相同的元素一定相连
        while current != nil, current?.next != nil {
            if current?.val == current?.next?.val {
                current?.next = current?.next?.next
            } else {
                current = current?.next
            }
        }
        return head
    }
}

测试代码:

// 删除排序链表中的重复元素
let s = Solution_83()
var node0 = ListNode(3, nil)
var node1 = ListNode(3, node0)
var node2 = ListNode(2, node1)
var node3 = ListNode(1, node2)
var node4 = ListNode(1, node3)
let head = s.deleteDuplicates(node4)

876. 链表的中间结点 leetcode.cn/problems/mi…

 给你单链表的头结点 head ,请你找出并返回链表的中间结点。

 如果有两个中间结点,则返回第二个中间结点。

class Solution_876 {
    func middleNode(_ head: ListNode?) -> ListNode? {
        // 快慢指针
        if head == nil || head?.next == nil {
            return head
        }
        var fast = head
        var slow = head
        
        while fast?.next != nil {
            fast = fast?.next?.next
            slow = slow?.next
        }
        return slow
    }
}


// 1 2 3 4 5 6 7 8 9 0
//     3   5   7   9   *
//   2 3 4 5 6