LeetCode刷题碎碎念(七):Linked List
- 单向链表
- 206. Reverse Linked List
- 92. Reverse Linked List II
- 21. Merge Two Sorted Lists (Easy)
- 24. Swap Nodes in Pairs (medium)
- 2. Add Two Numbers (medium)
- 445. Add Two Numbers II
- 234. Palindrome Linked List (medium)
- 143. Reorder List (medium)
- 203. Remove Linked List Elements
- 141. Linked List Cycle
- 142. Linked List Cycle II
- 25. Reverse Nodes in k-Group (hard)
- 86. Partition List (Medium)
- 61. Rotate List
单向链表
https://blog.csdn.net/haiyu94/article/details/79406082
单链表结构:
class Node:
'''
data: 节点保存的数据
next: 保存下一个节点对象
'''
def __init__(self, data, _next=None):
self.data = data
self._next = _next
206. Reverse Linked List
1 -> 2 -> 3 -> 4 -> null 反向变成
null <- 1 <- 2 <- 3 <- 4
必须要知道一个node的current,previous,next结点是谁
起始:prev = null, curr = head
class Solution(object):
def reverseList(self, head):
prev = None
curr = head
while curr:
# 反转
nxt = curr.next # 暂时存起来
curr.next = prev # 反向:本身是往后的指针改为向前指
# 沿链表向前推进
prev = curr
curr = nxt
return prev # 返回当前节点 因为prev = curr
92. Reverse Linked List II
class Solution:
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
dummy = ListNode(0)
dummy.next = head
prev = dummy
# 因为这次交换不是从头开始,prev不是None,所以需要用dummy把prev引入前m的链表遍历中
for i in range(m-1):
prev = prev.next
reverse = None # 用来代替prev,因为prev后面要用
curr = prev.next
for i in range(n-m+1):
nxt = curr.next # 保存下一节点,因为curr.next马上就要变了
curr.next = reverse
reverse = curr
curr = nxt
# prev没有进入reverse的循环,所以是reverse前的那个node
prev.next.next = curr # reverse部分和后面重新连接
prev.next = reverse # reverse部分和前面重新连接
return dummy.next # listnode的第一个节点
21. Merge Two Sorted Lists (Easy)
- Recursion
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if not l1: return l2
elif not l2: return l1
elif l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
- Iteration
每次对 l1 和 l2 比较大小,小的放入prehead,并且next后移
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
prehead = ListNode(0)
prev = prehead # prev是指向当前append的最后一位的指针
while l1 and l2:
if l1.val <= l2.val:
prev.next = l1
l1 = l1.next
else:
prev.next = l2
l2 = l2.next
prev = prev.next
if not l1:
prev.next = l2
elif not l2:
prev.next = l1
return prehead.next
24. Swap Nodes in Pairs (medium)
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
dummy = ListNode(0)
dummy.next = head # 链表的前一个位置的索引
curr = dummy
while curr.next and curr.next.next: # 有两个node可以交换
first = curr.next
second = curr.next.next
curr.next = second # curr链接后一个
first.next = second.next # 前一个链接后一个的下一个node(取代后一个的链接)
second.next = first # 后一个指向前一个
curr = curr.next.next # curr指针后移
return dummy.next
2. Add Two Numbers (medium)
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
dummy = tail = ListNode(0)
carry = 0
while l1 or l2 or carry:
v1 = v2 = 0
if l1:
v1 = l1.val
l1 = l1.next
if l2:
v2 = l2.val
l2 = l2.next
carry, val = divmod(v1 + v2 + carry, 10)
tail.next = ListNode(val)
tail = tail.next
return dummy.next
445. Add Two Numbers II
Combine reverseList and addTwoumbers
class Solution:
def reverseList(self, head: ListNode):
prev = None
while head:
nxt = head.next
head.next = prev
prev = head
head = nxt
return prev
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
l1 = self.reverseList(l1)
l2 = self.reverseList(l2)
dummy = tail = ListNode(0)
carry = 0
while l1 or l2 or carry:
v1 = v2 = 0
if l1:
v1 = l1.val
l1 = l1.next
if l2:
v2 = l2.val
l2 = l2.next
carry, val = divmod(v1 + v2 + carry, 10)
tail.next = ListNode(val)
tail = tail.next
dummy = self.reverseList(dummy.next)
return dummy
234. Palindrome Linked List (medium)
快慢指针
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
reverse = None
slow = fast = head
while fast and fast.next:
fast = fast.next.next # fast走到头
nxt = slow.next # slow走到中间,同时进行反转
slow.next = reverse # 完成对前半部分的反转
reverse = slow
slow = nxt
if fast:
slow = slow.next # 中间往后一位,后半部分的第一位
while reverse and reverse.val == slow.val:
slow = slow.next
reverse = reverse.next
return not reverse
143. Reorder List (medium)
利用双指针,把链表分成前半部分和后半部分,然后后半部分reverse和前部部分合并。
1->2->3->4->5->6->7->8->None
前般+后半:
1->2->3->4->None
5->6->7->8->None
后半reverse:
1->2->3->4->None
8->7->6->5->None
合并
class Solution:
def reorderList(self, head: ListNode) -> None:
"""
Do not return anything, modify head in-place instead.
"""
if not head: return
# slow是后半的第一个node
# head是前半的第一个node
slow = fast = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
# reverse后半段
reverse = None
curr = slow
while curr:
reverse, curr.next, curr = curr, reverse, curr.next
# merge前半段和后半段
first = head
second = reverse
while second.next:
first.next, first = second, first.next
second.next, second = first, second.next
return
reverse, curr.next, curr = curr, reverse, curr.next
==顺序是影响的!!!==不能先改变curr的值,这样curr.next也会同时发生变化。所以curr和curr.next先改变curr.next的值!
203. Remove Linked List Elements
要判断curr.next是否等于val,因为当前curr已经无法跳过了
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
dummy = ListNode(0)
dummy.next = head
curr = dummy
while curr.next:
if curr.next.val == val:
curr.next = curr.next.next # 跳过curr.next
else:
curr = curr.next
return dummy.next
141. Linked List Cycle
判断是否有环:
利用快慢指针,如果两个指针会相遇(快指针先进入环内绕圈,之后遇见慢指针),那么有环;
如果两个指针不相遇,一直到fast.next == None,走到了头,没有环
class Solution:
def hasCycle(self, head: ListNode) -> bool:
fast = head
slow = head
while (fast != None and fast.next != None):
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *slow = head;
ListNode *fast = head;
while (fast && fast -> next)
{
slow = slow -> next;
fast = fast -> next -> next;
if (fast == slow)
{
return true;
}
}
return false;
}
};
142. Linked List Cycle II
链表中环的入口节点
https://www.cnblogs.com/hiddenfox/p/3408931.html
设:链表头是X,环的第一个节点是Y,slow和fast第一次的交点是Z。各段的长度分别是a,b,c,如图所示。环的长度是L。slow和fast的速度分别是qs,qf。
a == c
slow fast第一次交点z,然后让一个指针(cur)从起点开始走,每次一个next,因为a == c,所以slow从z走到y和cur从x走到花费相同步数,正好相交在y
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
slow = head
fast = head
while (fast and fast.next):
slow = slow.next
fast = fast.next.next
if slow == fast:
break
else:
return None
cur = head;
while (cur != slow):
cur = cur.next
slow = slow.next
return cur
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *slow = head;
ListNode *fast = head;
bool flag = false;
while (fast && fast -> next)
{
slow = slow -> next;
fast = fast -> next -> next;
if (fast == slow)
{
flag = true;
break;
}
}
if (!flag)
{
return NULL;
}
ListNode *cur = head;
while (cur != slow)
{
cur = cur -> next;
slow = slow -> next;
}
return cur;
}
};
25. Reverse Nodes in k-Group (hard)
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
if head == None or head.next == None:
return head
count = 0
cur = head
while cur != None and count != k: # 前进k步
cur = cur.next
count += 1
if count == k:
cur = self.reverseKGroup(cur, k) # 第一个k部分找到,递归处理后面的部分
while count > 0: # reverse linked list
count -= 1
temp = head.next
head.next = cur
cur = head
head = temp
head = cur
return head
86. Partition List (Medium)
class Solution:
def partition(self, head: ListNode, x: int) -> ListNode:
# 用两个linked list分别储存大于等于x的和小于x的
small = ListNode(0)
cur1 = small
big = ListNode(0)
cur2 = big
while head:
tmp = ListNode(head.val) # 只是要加入一个跟head的值一样的节点
# 不要真的连到原始的linked list的head上
# 会形成linked list 的环
if head.val < x:
cur1.next = tmp
cur1 = cur1.next
else:
cur2.next = tmp
cur2 = cur2.next
head = head.next
cur1.next = big.next # 把大小两个linked list首尾相连
return small.next
61. Rotate List
class Solution:
def rotateRight(self, head: ListNode, k: int) -> ListNode:
if not head or not head.next:
return head
index = head
length = 1
while index.next: # 走到头
index = index.next
length += 1
index.next = head # index 为最后一个node,让他指向第一个node(head)
for i in range(1, length - k % length): # 找到Linked List断开的恰当地方
head = head.next # 同时解决rotate位数大于list长度
res = head.next # 找到现在的第一个node(现在还是环),最后一个node的下一个node
head.next = None # 断开
return res