😡😡😡
声明:
算法基于https://labuladong.github.io/
同步git地址:https://github.com/muxintong/break-algorithm/
python语言实现
双指针解决如下问题:
快慢指针:链表、归并排序找中点
list-to-linkedlist template
19. Remove Nth Node From End of List
21. Merge Two Sorted Lists
876. Middle of the Linked List
26. Remove Duplicates from Sorted Array
160. Intersection of Two Linked Lists
27. Remove Element
linkedlist-has-circle
😡😡😡
快慢指针:链表、归并排序找中点
list-to-linkedlist template
python:
from typing import Optional
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
def list2link(list_):
head = ListNode(list_[0])
p = head
for i in range(1, len(list_)):
p.next = ListNode(list_[i])
p = p.next
return head
def print_link_list(head: Optional[ListNode]) -> Optional[ListNode]:
p = head
while p:
print(p.val)
p = p.next
return head
if __name__ == "__main__":
old_list = [1, 2, 3, 4, 5]
link = list2link(old_list)
# Input: list1 = [1,2,4], list2 = [1,3,4]
# Output: [1,1,2,3,4,4]
# list1 = [1, 2, 4]
list2 = [1, 3, 4]
# link1 = list2link(list1)
link2 = list2link(list2)
print_link_list(link2)
linkedlist-has-circle template
python
"""
链表成环判定:使用双指针中的快慢指针解决
procedure:
每当慢指针 slow 前进一步,快指针 fast 就前进两步。
如果 fast 最终遇到空指针,说明链表中没有环;
如果 fast 最终和 slow 相遇,那肯定是 fast 超过了 slow 一圈,说明链表中含有环。
"""
from typing import Optional
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
# 链表成环判定:快慢指针技巧,含环返回True,不含返回False
def linkedlist_hasCircle(head: Optional[ListNode]) -> bool:
fast = head
slow = head
# 终止条件:快指针走到末尾时停止
while fast and fast.next:
# 过程:快走两步,慢走一步,若此过程中二者相遇则说明链表含环
slow = slow.next
fast = fast.next.next
if fast == slow:
return True
return False
# 含环链表返回环起点
def linkedlist_circle_point(head: Optional[ListNode]) -> Optional[ListNode]:
fast = head
slow = head
# 成环判定:快两步,慢一步,二者相等时即含环
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 【相遇点】快慢指针相遇=>含环=>在快慢指针相遇点终止循环
if slow == fast: break
if fast == None or fast.next == None:
# fast与空指针说明无环
return None
# 【环起点】使慢指针重新指向链表头,二者同步前进,再次相交点就是环起点
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
19. Remove Nth Node From End of List
https://leetcode.com/problems/remove-nth-node-from-end-of-list/
from typing import Optional
# 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: Optional[ListNode], n: int) -> Optional[ListNode]:
# NOTE:虚拟头结点的使用,否则对于特殊边界情况需特殊处理
dummy = ListNode(-1)
dummy.next = head
# Note:删除节点n时需找到节点n的前驱,由于是倒数,故其前一个节点是n+1,而不是n-1
precusor_n = self.findNthFromEnd(dummy, n + 1)
precusor_n.next = precusor_n.next.next
return dummy.next
def findNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
p1 = head
for i in range(n):
p1 = p1.next
p2 = head
while p1:
p1 = p1.next
p2 = p2.next
return p2
def list2link(list_):
head = ListNode(list_[0])
p = head
for i in range(1, len(list_)):
p.next = ListNode(list_[i])
p = p.next
return head
def print_link_list(head: Optional[ListNode]) -> Optional[ListNode]:
p = head
while p:
print(p.val)
p = p.next
return head
def main():
# Input: head = [1,2,3,4,5], n = 2
# Output: [1,2,3,5]
solution1 = Solution()
head = solution1.removeNthFromEnd(list2link([1, 2, 3, 4, 5]), 2)
print_link_list(head)
print('---')
# Input: head = [1], n = 1
# Output: []
solution2 = Solution()
head = solution2.removeNthFromEnd(list2link([1]), 1)
print_link_list(head)
print('---')
# Input: head = [1, 2], n = 2
# Output: [2]
solution3 = Solution()
head = solution3.removeNthFromEnd(list2link([1, 2]), 2)
print_link_list(head)
print('---')
# Input: head = [1,2], n = 1
# Output: [1]
solution4 = Solution()
head = solution4.removeNthFromEnd(list2link([1, 2]), 1)
print_link_list(head)
if __name__ == '__main__':
main()
21. Merge Two Sorted Lists
https://leetcode.com/problems/merge-two-sorted-lists/
from typing import Optional
# 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, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(-1)
p = dummy
p1 = list1
p2 = list2
while p1 and p2:
if p1.val > p2.val:
p.next = p2
p2 = p2.next
else:
p.next = p1
p1 = p1.next
p = p.next
if p1:
p.next = p1
if p2:
p.next = p2
return dummy.next
def print(self, head: ListNode):
p = head
while p:
print(p.val)
p = p.next
def list2link(list_):
if list_:
head = ListNode(list_[0])
p = head
for i in range(1, len(list_)):
p.next = ListNode(list_[i])
p = p.next
return head
def main():
# Input: list1 = [1,2,4], list2 = [1,3,4]
# Output: [1,1,2,3,4,4]
list1 = [1, 2, 4]
list2 = [1, 3, 4]
link1 = list2link(list1)
link2 = list2link(list2)
solution1 = Solution()
head1 = solution1.mergeTwoLists(link1, link2)
solution1.print(head1)
if __name__ == '__main__':
main()
23. Merge k Sorted Lists
https://leetcode.com/problems/merge-k-sorted-lists/
from typing import Optional, List
# 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[Optional[ListNode]]) -> Optional[ListNode]:
arr = []
for member in lists:
while member:
arr.append(member.val)
member = member.next
arr.sort()
res = ListNode(-1)
p = res
for i in arr:
p.next = ListNode(i)
p = p.next
print(p.val)
return res.next
def list2link(list_):
head = ListNode(list_[0])
p = head
for i in range(1, len(list_)):
p.next = ListNode(list_[i])
p = p.next
return head
def main():
# Input: lists = [[1,4,5],[1,3,4],[2,6]]
# Output: [1,1,2,3,4,4,5,6]
# Explanation: The linked-lists are:
# [
# 1->4->5,
# 1->3->4,
# 2->6
# ]
# merging them into one sorted list:
# 1->1->2->3->4->4->5->6
solution1 = Solution()
solution1.mergeKLists([list2link([1, 4, 5]), list2link([1, 3, 4]), list2link([2, 6])])
print('---')
# Input: lists = []
# Output: []
solution2 = Solution()
solution2.mergeKLists([])
print('---')
# Input: lists = [[]]
# Output: []
solution3 = Solution()
solution3.mergeKLists([[]])
if __name__ == '__main__':
main()
876. Middle of the Linked List
https://leetcode.com/problems/middle-of-the-linked-list/
from typing import Optional
# Definition for singly-linked list.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 快慢指针的使用:
# 二者同时从头出发,快指针每次前进两步,慢指针每次前进一步,
# 当快指针到达链表尾部时,慢指针正好到达链表中点。
fast = head
slow = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
return slow
def list2link(list_):
head = ListNode(list_[0])
p = head
for i in range(1, len(list_)):
p.next = ListNode(list_[i])
p = p.next
return head
def print_link_list(head: Optional[ListNode]) -> Optional[ListNode]:
p = head
while p:
print(p.val)
p = p.next
return head
def main():
# Input: head = [1,2,3,4,5]
# Output: [3,4,5]
# Explanation: The middle node of the list is node 3.
solution1 = Solution()
head = solution1.middleNode(list2link([1, 2, 3, 4, 5]))
print_link_list(head)
print('---')
# Input: head = [1,2,3,4,5,6]
# Output: [4,5,6]
# Explanation: Since the list has two middle nodes with values 3 and 4, we return the second one.
solution2 = Solution()
head = solution2.middleNode(list2link([1, 2, 3, 4, 5, 6]))
print_link_list(head)
if __name__ == '__main__':
main()
26. Remove Duplicates from Sorted Array
https://leetcode.com/problems/remove-duplicates-from-sorted-array/
from typing import List
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
slow = 0
fast = 0
while fast < len(nums):
if nums[fast] != nums[slow]:
slow += 1
# 保持nums[0-slow]无重复
nums[slow] = nums[fast]
fast += 1
return slow + 1
def main():
# Input: nums = [1,1,2]
# Output: 2, nums = [1,2,_]
solution1=Solution()
print(solution1.removeDuplicates([1,1,2]))
print('---')
# Input: nums = [1,1,2]
# Output: 2, nums = [1,2,_]
solution1=Solution()
print(solution1.removeDuplicates([1,1,2]))
if __name__=='__main__':
main()
160. Intersection of Two Linked Lists
https://leetcode.com/problems/intersection-of-two-linked-lists/
from typing import Optional
# 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]:
p1 = headA
p2 = headB
# NOTE:use is or ==
while p1 != p2:
if p1 == None:
p1 = headB
else:
p1 = p1.next
if p2 == None:
p2 = headA
else:
p2 = p2.next
return p2
def list2link(list_):
head = ListNode(list_[0])
p = head
for i in range(1, len(list_)):
p.next = ListNode(list_[i])
p = p.next
return head
def print_link_list(head: Optional[ListNode]) -> Optional[ListNode]:
p = head
while p:
print(p.val)
p = p.next
return head
def main():
# intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
# Output: Intersected at '8'
# Explanation: The intersected node's value is 8 (note that this must not be 0 if the two lists intersect).
# From the head of A, it reads as [4,1,8,4,5]. From the head of B, it reads as [5,6,1,8,4,5].
# There are 2 nodes before the intersected node in A;
# There are 3 nodes before the intersected node in B.
solution1 = Solution()
intersect_head = solution1.getIntersectionNode(list2link([4, 1, 8]), list2link([5, 8]))
print_link_list(intersect_head)
if __name__ == '__main__':
main()
27. Remove Element
https://leetcode.com/problems/remove-element/
from typing import List
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
slow = 0
fast = 0
# NOTE:结束条件!!!结束条件需为fast可以取到列表最后一个元素
while fast <= len(nums) - 1:
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
fast += 1
# if slow == 0: return 1, nums[0]
return slow, nums[0:slow]
def main():
# Input: nums = [3,2,2,3], val = 3
# Output: 2, nums = [2,2,_,_]
solution1 = Solution()
print(solution1.removeElement([3, 2, 2, 3], 3))
print('---')
# Input: nums = [0,1,2,2,3,0,4,2], val = 2
# Output: 5, nums = [0,1,4,0,3,_,_,_]
solution2 = Solution()
print(solution2.removeElement([0, 1, 2, 2, 3, 0, 4, 2], val=2))
print('---')
# Input: nums = [2], val = 3
# Output: [2]
#
# while fast < len(nums) - 1:
# (0, []) 错,reason:快指针没有取到最后一个元素len-1
# while fast < len(nums):
# (1, [2]) 对
solution3 = Solution()
print(solution3.removeElement([2], val=3))
if __name__ == '__main__':
main()
linkedlist-has-circle
"""
链表成环判定:使用双指针中的快慢指针解决
procedure:
每当慢指针 slow 前进一步,快指针 fast 就前进两步。
如果 fast 最终遇到空指针,说明链表中没有环;
如果 fast 最终和 slow 相遇,那肯定是 fast 超过了 slow 一圈,说明链表中含有环。
"""
from typing import Optional
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
# 链表成环判定:快慢指针技巧,含环返回True,不含返回False
def linkedlist_hasCircle(head: Optional[ListNode]) -> bool:
fast = head
slow = head
# 终止条件:快指针走到末尾时停止
while fast and fast.next:
# 过程:快走两步,慢走一步,若此过程中二者相遇则说明链表含环
slow = slow.next
fast = fast.next.next
if fast == slow:
return True
return False
# 含环链表返回环起点
def linkedlist_circle_point(head: Optional[ListNode]) -> Optional[ListNode]:
fast = head
slow = head
# 成环判定:快两步,慢一步,二者相等时即含环
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 【相遇点】快慢指针相遇=>含环=>在快慢指针相遇点终止循环
if slow == fast: break
if fast == None or fast.next == None:
# fast与空指针说明无环
return None
# 【环起点】使慢指针重新指向链表头,二者同步前进,再次相交点就是环起点
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow