双指针算法总结

Posted 楊木木8023

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双指针算法总结相关的知识,希望对你有一定的参考价值。

      (1) 分析:双指针从广义上来说,是指用两个变量在线性结构上遍历而解决的问题。狭义上说:对于数组,指两个变量在数组上相向移动解决的问题;对于链表,指两个变量在链表上同向移动解决的问题,也称为“快慢指针”问题。

       (2) 双指针主要有以下几种类型:

       快慢指针:指两个指针从同一侧开始遍历数组,将两个指针按照不同的策略移动,一快一慢,如快指针每次移动两个,慢指针一次移动一个。常见的如删除数组的重复项、判断链表的环路问题、求链表倒数第k个元素等。

       删除有序数组的重复项(26,80):给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现k ,返回删除后数组的新长度。

def removeDuplicates(self, nums, k):
    if len(nums) <= k:
        return len(nums)
    fast = slow = k
    while fast < len(nums):
        if nums[fast] != nums[slow - k]:
            nums[slow] = nums[fast]
            slow += 1
        fast += 1
    return slow     

           链表环的入口节点(142):

def detectCycle2(self, head: ListNode) -> ListNode:
    if not head:
        return None
    new_head, fastNode, slowNode = head, head, head
    while fastNode and fastNode.next:
        fastNode = fastNode.next.next
        slowNode = slowNode.next
        if fastNode == slowNode:
            while new_head != fastNode:
                new_head = new_head.next
                fastNode = fastNode.next
            return new_head
    return None

        链表的倒数第k个元素(19):

def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
    new_head = ListNode(0, None)
    new_head.next = head
    pre_node = new_head
    post_node = head
    while n:
        post_node = post_node.next
        n -= 1
    while post_node:
        pre_node = pre_node.next
        post_node = post_node.next
    pre_node.next = pre_node.next.next
    return head

       碰撞指针:对撞指针是指在数组中,将指向最左侧的索引定义为左指针,最右侧的定义为右指针,然后从两头向中间进行数组遍历(while left < right)。如快速排序、二分查找、n个数目标和问题等。

       两数之和(167):给定一个已按照 非递减顺序排列  的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target。

def twoSum(self, numbers, target: int):
    left, right = 0, len(numbers) - 1
    while left < right:
        if numbers[left] + numbers[right] > target:
            right -= 1
        elif numbers[left] + numbers[right] < target:
            left += 1
        else:
            return [left + 1, right + 1]
    return []

        三数之和(15\\16\\18):给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a、b、c,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

def threeSum(self, nums):
    if len(nums) < 3:
        return []
    nums = sorted(nums)
    res = []
    left, right = 0, len(nums)-1
    while left < right:
        total = 0
        for i in range(left+1, right):
            total = nums[left] + nums[right] + nums[i]
            if total == 0:
                tmp = [nums[left], nums[right], nums[i]]
                if tmp not in res:
                    res.append(tmp)
        if total < 0:
            left += 1
        if total > 0:
            right -= 1
    return res

       反转字符串中的元音字母(345):给你一个字符串 s ,仅反转字符串中的所有元音字母,并返回结果字符串。

def reverseVowels(s: str) -> str:
    alp = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']
    left, right = 0, len(s) - 1
    s = list(s)
    while left < right:
        if s[left] in alp:
            if s[right] in alp:
                s[left], s[right] = s[right], s[left]
                left += 1
                right -= 1
            else:
                right -= 1
        else:
            left += 1
    return "".join(s)

        滑动窗口:两个指针,一前一后组成滑动窗口,并计算滑动窗口中的元素的问题。例如、字符串匹配问题、子数组问题等。

       无重复字符的最长子串(3):给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

def lengthOfLongestSubstring(self, s: str) -> int:
    if len(s) == 0:
        return 0
    if len(s) == 1:
        return 1
    left, right = 0, 1
    s = list(s)
    max_len, tmp = 1, []
    tmp.append(s[left])
    while right < len(s):
        if s[right] not in tmp:
            tmp.append(s[right])
            right += 1
            tmp_len = len(tmp)
            if tmp_len > max_len:
                max_len = tmp_len
        else:
            tmp_len = len(tmp)
            print(max_len)
            index = tmp.index(s[right])
            tmp.append(s[right])
            left = index + 1
            right += 1
            tmp = tmp[left:]
            if tmp_len > max_len:
                max_len = tmp_len
    return max_len

       字符串的排列(567):给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。

def checkInclusion(self, s1: str, s2: str) -> bool:
    s1, s2 = sorted(list(s1)), list(s2)
    len1, len2 = len(s1), len(s2)
    if len2 < len1:
        return False
    left, right = 0, len1
    while right <= len2:
        tmp = sorted(s2[left:right])
        if tmp == s1:
            return True
        left += 1
        right += 1
    return False

以上是关于双指针算法总结的主要内容,如果未能解决你的问题,请参考以下文章

双指针算法总结

双指针算法总结

双指针算法总结

算法练习高频「双指针」类型题目总结

LeetCode刷题总结-双指针位运算和分治法篇

算法双指针算法 ( 有效回文串 II )