【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-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 的整数倍,那么请将最后剩余的节点保持原有顺序。
二、代码:
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: """ pre表示已经翻转完的尾部,两个指针head/tail指向要翻转的头和尾 先找到tail,如果找到了就翻转head-tail的链表并接回pre 以1-2-3-4-5,k=3为例 """ def reverseList(head): # pre表示已经翻转完的,p表示待翻转的头,1-2-3转为3-2-1 pre, p = None, head tail = head # 翻转完的尾 while p: tmp = p.next p.next = pre pre = p p = tmp return pre, tail dummy = ListNode(0, head) pre, tail, head = dummy, dummy, dummy.next while pre: for i in range(k): tail = tail.next # tail=3 if not tail: return dummy.next nxt = tail.next # 4 tail.next = None # 3截断,4-5游离 head_new, tail_new = reverseList(head) # 1-2-3/head=3,tail=1 pre.next = head_new # 前接回 tail_new.next = nxt # 后接回 pre = tail_new # pre=1 head = nxt # head=4 tail = pre 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 ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字。
返回同样按升序排列的结果链表。
二、代码:
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: """ pre指向处理完的节点,p指向待处理的节点 如果p与前面不重复且与后面不重复则接到pre后面,注意pre.next为None 否则p往后走,前面的值也要更新 """ dummy = ListNode() last_val = float('inf') p, pre = head, dummy while p: if p.val != last_val and (not p.next or p.val != p.next.val): last_val = p.val pre.next = p pre = p p = p.next pre.next = None else: last_val = p.val p = p.next return dummy.next return p.next """ 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 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
二、代码:
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]: """ 拆成2个链表,一个<x一个>=x,然后再合并 """ dummy1, dummy2 = ListNode(), ListNode() p, p1, p2 = head, dummy1, dummy2 while p: if p.val < x: p1.next = p p1 = p1.next p = p.next p1.next = None else: p2.next = p p2 = p2.next p = p.next p2.next = None p1.next = dummy2.next return dummy1.next """ 慢指针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】
一、题目:环形链表
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 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) 空间解决此题?
二、代码:

# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: """ p1走一步,p2走2步,p1和p2相遇时p2走的距离是p1的2倍,a+n(b+c)+b=2(a+b) -> a=c+(n-1)(b+c),说明p1\p2相遇时,一个指针从头走,会与p1在环入口相遇 """ 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-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) -> Optional[ListNode]: """ 分为3种情况 1.不相交,都到头退出 2.相交&长度相等,会同时到头但未走到终点即相遇 3.相交&长度不等,不会同时到头,重新走会相遇 """ 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
浙公网安备 33010602011771号