day5: 链表

1. 剑指 Offer 22. 链表中倒数第k个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。

示例:

给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.

解法1:  暴力

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        p = head  # 第k个节点
        node_list = []
        while p:   # 暴力遍历
            node_list.append(p)
            p = p.next
        return node_list[-k]

解法2: 快慢指针

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        # 快慢指针, fast 比快指针先多走k, 然后同步前进, 
        # fast到达 最后一个节点, slow到达目标节点的前一个节点。
        slow = fast = head
        count = 0
        while fast and fast.next:
            fast = fast.next
            count += 1
            if count > k:
                slow = slow.next
        if count == k - 1:  #  特殊情况 k为头节点
            return head
        request = slow.next
        return request

解法3: 快慢指针  注意和解法2的区别

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        # 快慢指针, fast 比快指针先多走k, 然后同步前进, 
        # fast到达 最后一个节点, slow到达目标节点的前一个节点。
        slow = fast = head
        count = 0
        while fast and fast.next:
            fast = fast.next
            count += 1
            if count >= k:
                slow = slow.next
        request = slow 
        return request

 2. 141. 环形链表

给定一个链表,判断链表中是否有环。

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

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

解法1:  快慢指针

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        fast = head
        slow = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                return True
        return False

3.  142. 环形链表 II

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。

说明:不允许修改给定的链表。

进阶:你是否可以不用额外空间解决此题?

解法1:    快慢指针,当快慢指针相遇后,  慢指针 和 从head出发指针, 必定会相遇。

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        fast = slow = head
        while fast and fast.next:
            fast = fast.next.next
            slow = slow.next
            if fast == slow:
                while head != slow:
                    head = head.next
                    slow = slow.next
                return head
        return None

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

给定一个链表,删除链表的倒数第 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:

给定的 n 保证是有效的。

进阶:

你能尝试使用一趟扫描实现吗?

解法1:  快慢指针

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
       # 一次遍历, 快慢指针遍历, fast走到最后一个节点, slow走到目标节点的前置节点, 好思路
       # fast 和 slow 差 n个节点。
        fast = slow = head
        count = 0
        while fast and fast.next:  # fast 非空
            fast = fast.next  # fast 首先比 slow 多走n
            count += 1
            if count > n:
                slow = slow.next
        # 几种特殊情况
        if count == n - 1:  # 删除头节点   
            head = head.next
        else:
            # fast 到结尾了
            if slow.next: 
                slow.next =  slow.next.next
            else:
                head = None
        return head

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

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

输入:head = []
输出:[]

示例 3:

输入:head = [1]
输出:[1]

解法1: 递归

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        # 递归, 先背一种解法
        if not head or not head.next: # None 或者 一个节点
            return head
        
        newhead = head.next  # 新的头节点
        head.next = self.swapPairs(newhead.next)  # 递归 交换 剩余 节点, 一次交换两个
        newhead.next = head

        return newhead

6.  148. 排序链表

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

进阶:

你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

示例 1:

day5: 链表_第1张图片

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2:

day5: 链表_第2张图片

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3:

输入:head = []
输出:[]

解法1:  O(n)遍历出所有节点值, O(nlogn)排序, O(n)将排序后数据写进节点 (不管黑猫白猫,能逮着耗子就是好猫)

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        # # 超时 O(n*n)
        # flag = True
        # while flag:
        #     flag =False
        #     p = head
        #     while p and p.next:
        #         if p.val > p.next.val:
        #             p.val, p.next.val = p.next.val, p.val
        #             flag = True
        #         p = p.next
        # return head
        temp = []
        p = head
        while p:
            temp.append(p.val)
            p = p.next
        temp = sorted(temp)  # O(nlogn)  快速排序
        p = head
        i = 0 
        while p:
            p.val = temp[i]
            i = i + 1
            p = p.next
        return head

解法2:  归并排序(快慢指针 找中点) + 合并链表(合并两个有序链表方法) 这题得背下来

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        # 归并排序(快慢指针 找中点) + 合并链表(合并两个有序链表方法) # 考点太多了
        # 归并排序
        def sortFunc(head, tail):  # 需要知道 头 尾
            if not head:  # 为null
                return head
            if head.next == tail:  # 两个节点时, 返回头节点就行,因为mid
                head.next = None
                return head
            # 快慢指针
            fast=slow=head
            while fast != tail:  # 这个快慢指针 用法 也特殊, 总结快慢指针的用法形式;
                slow = slow.next
                fast = fast.next
                if fast != tail:
                    fast = fast.next
            # slow 就是中点
            mid = slow
            return merge(sortFunc(head, mid), sortFunc(mid, tail))
        # 合并两个有序链表
        def merge(head1, head2):
            p = q = ListNode(0, None)
            l1 = head1
            l2 = head2
            while l1 and l2:
                if l1.val < l2.val:
                    p.next = l1
                    l1 = l1.next
                else:
                    p.next = l2
                    l2 = l2.next
                p = p.next
            if l1:
                p.next = l1
            if l2:
                p.next = l2
            return q.next

        return sortFunc(head, None)

7. 147. 对链表进行插入排序

对链表进行插入排序。

插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。

插入排序算法:

插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
重复直到所有输入数据插入完为止。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

解法1:  插入排序定义

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def insertionSortList(self, head: ListNode) -> ListNode:
        # 插入排序 
        if not head:
            return head
        dummyHead = ListNode(0)  # 头节点 前一个节点, 用来方便在 头节点前 插入 节点
        dummyHead.next = head
        lastedsorted = head  # 有序区域的最后一个节点
        cur = head.next  # 下一个待排序的无序节点
        while cur:
            if lastedsorted.val <= cur.val:  # 有序 无需插入
                lastedsorted = lastedsorted.next
            else:
                # 需要插入,从头遍历
                pre = dummyHead
                while pre.next.val <= cur.val:
                    pre = pre.next
                lastedsorted.next = cur.next  # 将但前无序节点之后的节点 给 最后一个有序的next
                cur.next = pre.next  # cur插入到 pre 和 pre.next之间
                pre.next = cur

            cur = lastedsorted.next  # 待排序节点

        return dummyHead.next

你可能感兴趣的:(Python,面试题,leetcode,链表)