break algorithm---双指针1:快慢指针


😡😡😡


声明:
算法基于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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killingwill

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值