【Leetcode】链表系列

【Leetcode-3】

一、题目:两数相加

  给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

  请你将两个数相加,并以相同形式返回一个表示和的链表。

  你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

二、代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        last_v = 0
        p1, p2 = l1, l2
        head = p = ListNode(0)
        while p1 or p2 or last_v:
            v1 = p1.val if p1 else 0
            v2 = p2.val if p2 else 0
            v = v1 + v2 + last_v
            node = ListNode(v%10)
            last_v = v // 10
            p.next = node
            p = p.next
            if p1:
                p1 = p1.next
            if p2:
                p2 = p2.next
        return head.next

【Leetcode-19】

一、题目:删除链表的倒数第n个结点

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

二、代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        if not head:
            return head
        p = ListNode(0)
        p.next = head
        p1 = p2 = p
        for i in range(n):
            p2 = p2.next
        while p2 and p2.next:
            p1 = p1.next
            p2 = p2.next
            
        p1.next = p1.next.next
        return p.next

【Leetcode-21】

一、题目:合并两个有序链表

  将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

二、代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        head = p = ListNode()
        p1, p2 = l1, l2
        while p1 or p2:
            v1 = p1.val if p1 else float('inf')
            v2 = p2.val if p2 else float('inf')
            if v1 < v2:
                p.next = p1
                p1 = p1.next
            else:
                p.next = p2
                p2 = p2.next
            p = p.next
        return head.next

【Leetcode-23】

一、题目:合并k个升序链表

  给你一个链表数组,每个链表都已经按升序排列。

  请你将所有链表合并到一个升序链表中,返回合并后的链表。

二、代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        """
        分治思想,类似于归并排序
        """
        def split_and_merge(lists, l, r):
            if l == r:
                return lists[l]
            mid = (l + r) // 2
            l1 = split_and_merge(lists, l, mid)
            l2 = split_and_merge(lists, mid+1, r)
            lt = merge_list(l1, l2)
            return lt

        def merge_list(l1, l2):
            dummy = ListNode()
            p1, p2, p = l1, l2, dummy
            while p1 or p2:
                val1 = p1.val if p1 else float('inf')
                val2 = p2.val if p2 else float('inf')
                if val1 < val2:
                    p.next = p1
                    p1 = p1.next
                else:
                    p.next = p2
                    p2 = p2.next
                p = p.next
            return dummy.next

        if not lists:
            return
        n = len(lists)
        l = split_and_merge(lists, 0, n-1)
        return l

【Leetcode-24】

一、题目:两两交换链表中的结点

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

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

二、代码:

class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        """
        每次走两步,交换2节点,若步数不到2则不交换
        """
        dummy = ListNode()
        dummy.next = head  # 哑节点,避免处理头
        p = dummy  # p指向处理完成的节点
        # 0-1-2-3..,p开始指向0
        while p.next and p.next.next:  
            tmp = p.next.next  # tmp=2
            p.next.next = tmp.next  # 1-3
            tmp.next = p.next  # 2-1
            p.next = tmp  # 0-2
            p = p.next.next
        return dummy.next

【Leetcode-25】

一、题目:K个一组翻转链表

  给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

  k 是一个正整数,它的值小于或等于链表的长度。

  如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

二、代码:

def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
        """
        pre指向拼接完成链表的尾部,head和tail分别指向待翻转部分的头部和尾部,nxt指向未翻转部分的头部,如果没走k步就到了None,那么直接break
        """
        def reverse(head):
            final_tail = head
            pre = None
            p = head
            while p:
                tmp = p.next
                p.next = pre
                pre = p
                p = tmp
            return pre, final_tail

        dummy = ListNode(0, head)
        pre, tail, head = dummy, dummy, dummy.next
        while pre:  # 未翻转完
            i = 0
            while i < k:
                tail = tail.next
                if not tail:
                    return dummy.next
                i += 1
            # 断开再翻转
            nxt = tail.next
            tail.next = None
            head, tail = reverse(head)
            # 接起来
            pre.next = head
            tail.next = nxt
            pre = tail
            head = tail.next
        return dummy.next

【Leetcode-61】

一、题目:旋转链表

  给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

二、代码:

def rotateRight(self, head: ListNode, k: int) -> ListNode:
        """
        链表长度n,移动k%n次
        移动方法:把链表连成环,起始在head,然后在后移n-k-1处切开
        1->2->3->4->5,k=1则移动5-1-1=3次,到4,4处切开,返回5处
        """
        if not head or not head.next or k == 0:
            return head
        # 计算链表长度
        n = 1
        p = head
        while p.next:
            n += 1
            p = p.next
        if n <= 1 or k % n == 0:  # 不必移动
            return head
        k = k % n
        # 连成环
        p.next = head
        p = head
        k = n - k - 1  # 在此后面断开
        while k > 0:  # 
            k -= 1
            p = p.next
        # 切开
        h = p.next
        p.next = None
        return h

【Leetcode-82】

一、题目:删除排序链表中的重复元素2

  存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字。

  返回同样按升序排列的结果链表。

二、代码:

def deleteDuplicates(self, head: ListNode) -> ListNode:
        """
        pre指向已处理完的链表,判断pre.next是否是重复的,重复就循环删除
        注意:
        1.不重复直接往下走
        2.重复的话pre不往下走,因为此刻只是走到了一个重复元素的下一个,这个元素不知道会不会重复,也是未处理,因此pre不变
        """
        dummy = ListNode(0, head)
        pre = dummy
        while pre:  # 未处理完
            if pre.next and pre.next.next and pre.next.val == pre.next.next.val:
                # 已经重复,删除这个元素,一直过了这个元素到下一位
                p = pre.next
                val = p.val
                while p and p.val == val:
                    p = p.next
                pre.next = p
            else:
                pre = pre.next
        return dummy.next

【Leetcode-86】

一、题目:分割链表

  给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

  你应当 保留 两个分区中每个节点的初始相对位置。

二、代码:

def partition(self, head: ListNode, x: int) -> ListNode:
        """
        慢指针p1指向<x的元素的尾部,快指针p2指向待处理的元素,遇到<x的元素则接到p1的后面,pre指向p2的前一个用于接链表
        """
        dummy = ListNode(0, head)
        p1, pre, p2 = dummy, dummy, head
        while p2:
            if p2.val < x:
                # 拆出来再插入
                pre.next = p2.next
                p2.next = p1.next
                p1.next = p2
                p1 = p1.next
            pre = p2
            p2 = p2.next
        return dummy.next

【Leetcode-138】

一、题目:复制带随机指针的链表

  给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

  构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

  例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

  返回复制链表的头节点。

  用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

  val:一个表示 Node.val 的整数。
  random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。
  你的代码 只 接受原链表的头节点 head 作为传入参数。

二、代码:

"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""

class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        """
        原结点后增加副本->补充副本的random->副本拆分出来
        """
        if not head:
            return head
        # 原结点后增加副本
        p = head
        while p:
            node = Node(p.val)
            node.next = p.next
            p.next = node
            p = p.next.next
        # 补充副本的random
        p = head
        while p:
            p.next.random = p.random.next if p.random else None
            p = p.next.next
        # 副本拆分出来
        p1 = head
        head2 = p2 = head.next
        while p2.next:
            p1.next = p2.next
            p2.next = p2.next.next
            p1 = p1.next
            p2 = p2.next
        return head2

【Leetcode-141】

一、题目:两两交换链表中的节点

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

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

二、代码:

# 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:
        """
        每次走两步,交换2节点,若步数不到2则不交换
        """
        dummy = ListNode()
        dummy.next = head  # 哑节点,避免处理头
        p = dummy  # p指向处理完成的节点
        # 0-1-2-3..,p开始指向0
        while p.next and p.next.next:  
            tmp = p.next.next  # tmp=2
            p.next.next = tmp.next  # 1-3
            tmp.next = p.next  # 2-1
            p.next = tmp  # 0-2
            p = p.next.next
        return dummy.next

【Leetcode-141】

一、题目:环形链表

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

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

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

二、代码:

# 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:
        p1 = p2 = head
        while p2 and p2.next:
            p1 = p1.next
            p2 = p2.next.next
            if p1 == p2:
                return True        
        return False

【Leetcode-142】

一、题目:环形链表2

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

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

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

  进阶:

  你是否可以使用 O(1) 空间解决此题?

二、代码:

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        p1 = p2 = head
        flag = False  # 无环
        while p2 and p2.next:
            p1 = p1.next
            p2 = p2.next.next
            if p1 == p2:
                flag = True  # 有环
                break
        if flag:
            p2 = head
            while p1 != p2:
                p1 = p1.next
                p2 = p2.next
            return p1
        else:
            return None

【Leetcode-146】

一、题目:LRU缓存机制

二、代码:

class ListNode:
    def __init__(self, key=None, value=None):
        self.key = key
        self.value = value
        self.pre = None
        self.next = None

class LRUCache:

    def __init__(self, capacity: int):
        self.capacity = capacity
        self.hashmap = {}
        self.head = ListNode()
        self.tail = ListNode()
        self.head.next = self.tail
        self.tail.pre = self.head

    def move_to_head(self, node):
        # 从原位置拆出来,放到开头
        node.pre.next = node.next
        node.next.pre = node.pre
        self.insert_to_head(node)
        
    def insert_to_head(self, node):
        node.next = self.head.next
        self.head.next.pre = node
        node.pre = self.head
        self.head.next = node

    def get(self, key: int) -> int:
        if key in self.hashmap:
            node = self.hashmap[key]
            self.move_to_head(node)
            return node.value
        else:
            return -1

    def put(self, key: int, value: int) -> None:
        if key in self.hashmap:
            self.hashmap[key].value = value
            node = self.hashmap[key]
            self.move_to_head(node)
        else:
            if len(self.hashmap) == self.capacity:
                # 在尾部删除一个节点
                del_node = self.tail.pre
                del_node.pre.next = self.tail
                self.tail.pre = del_node.pre
                del self.hashmap[del_node.key]
            node = ListNode(key, value)
            self.hashmap[key] = node
            self.insert_to_head(node)


# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)

【Leetcode-148】

一、题目:排序链表

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

  进阶:

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

二、代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        def my_sort(root):
            # 在中间拆分
            if not root or not root.next:
                return root
            p1, p2 = root, root.next
            while p2 and p2.next:
                p1 = p1.next
                p2 = p2.next.next
            # 截断
            left = root
            right = p1.next
            p1.next = None
            # 分别排序
            left = my_sort(left)
            right = my_sort(right)
            # 合并
            pre = p = ListNode(0)
            p1, p2 = left, right
            while p1 or p2:
                v1 = p1.val if p1 else float('inf')
                v2 = p2.val if p2 else float('inf')
                if v1 < v2:
                    p.next = p1
                    p1 = p1.next
                else:
                    p.next = p2
                    p2 = p2.next
                p = p.next
            return pre.next

        root = my_sort(head)
        return root

【Leetcode-160】

一、题目:相交链表

  编写一个程序,找到两个单链表相交的起始节点。

二、代码:

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

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        p1, p2 = headA, headB
        while p1 or p2:
            if p1 == p2:
                break
            p1 = p1.next if p1 else headB
            p2 = p2.next if p2 else headA
        return p1

【Leetcode-206】

一、题目:反转链表

  反转一个单链表。

二、代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre = None
        p = head
        while p:
            tmp = p.next
            p.next = pre
            pre = p
            p = tmp
        return pre
博文转载请注明出处。
原文地址:https://www.cnblogs.com/EstherLjy/p/14608024.html