算法(6)-leetcode-explore-learn-数据结构-数组字符串的双指针技巧

leetcode-explore-learn-数据结构-数组4-双指针技巧

  • 1.双指针技巧--适用情形1
    • 1.1概述
    • 1.2 例题
      • 1.2.1 反转字符串
      • 1.2.2数组拆分
      • 1.2.3 两数之和2
  • 2双指针技巧-适用情形2
    • 2.1概述
    • 2.2例题
      • 2.2.1 移除元素
      • 2.2.2 最大连续1的个数
      • 2.2.3长度最小的子数组

本系列博文为leetcode-explore-learn子栏目学习笔记,如有不详之处,请参考leetcode官网:https://leetcode-cn.com/explore/learn/card/array-and-string/198/introduction-to-array/768/

所有例题的编程语言为python
在一般的数组问题中,我们只采用从第一个元素开始到最后一个元素结束的一个指针来进行迭代。

有些时候需要用两个指针来迭代数组

1.双指针技巧–适用情形1

1.1概述

最简单的例题–反转数组中的元素(利用连个指针来完成迭代,一个指针从第一个元素开始,另一个指针从末尾开始,持续交换他们所指向的元素,直至俩个指针相遇)
双指针技巧的经典应用场景之一:从两端向中间迭代数组,这个技巧经常在排序的数组中使用

1.2 例题

1.2.1 反转字符串

原地修改给定的输入字符串数组
数据格式:

输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]

class Solution(object):
    def reverseString(self, s):
        """
        :type s: List[str]
        :rtype: None Do not return anything, modify s in-place instead.
        """
        i=0
        j=len(s)-1
        while(i<j):
            s[i],s[j]=s[j],s[i]
            i+=1
            j-=1
        return s

1.2.2数组拆分

给定长度为2n的数组,将这些数字分为n对,例如 ( a 1 , b 1 ) , ( a 2 , b 2 ) , . . . , ( a n , b n ) (a_1,b_1),(a_2,b_2),...,(a_n,b_n) (a1,b1),(a2,b2),...,(an,bn),使得从1-n的 m i n ( a i , b i ) min(a_i,b_i) min(ai,bi)总和最大。

举例: a 1 , a 2 , a 3 , a 4 , a 5 , a 6 a_1,a_2,a_3,a_4,a_5,a_6 a1,a2,a3,a4,a5,a6升序排列
6个数分三对,能出现在和计算式中的最大数为 a 5 a_5 a5(此时 a 5 和 a 6 a_5和a_6 a5a6配对),同理剩下的4个数中,依次出现在和式中的为 a 1 , a 3 a_1,a_3 a1,a3

解题思路:先对数组排序,然后依次叠加偶数索引元素。

class Solution(object):
    def arrayPairSum(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n=len(nums)
        res=0
        # nums.sort()
        for i in range(n):
            if i%2==0:
                res+=nums[i]
        return res
            

1.2.3 两数之和2

给定一个按升序排列的有序数组,找到两个数字使得他们相加的和等于目标数
返回两个数字的下标,index1 一个输入只有一对答案,不能重复使用个数组中的元素。

双指针求解:
if (nums[i]+nums[j]==target): return(i+1,j+1)
if(nums[l]+nums[r]>target):r-=1
if(nums[l]+nums[r]

class Solution(object):
    def twoSum(self, numbers, target):
        """
        :type numbers: List[int]
        :type target: int
        :rtype: List[int]
        """
        l=0
        r=len(numbers)-1
        while(l<r):
            if numbers[l]+numbers[r]==target:
                return [l+1,r+1]
            if numbers[l]+numbers[r]<target:
                l+=1
            if numbers[l]+numbers[r]>target:
                r-=1
        return  -1

2双指针技巧-适用情形2

2.1概述

适用快慢两个不同步的指针来解决问题。

经典问题:给定一个数组和一个值,原地删除该值的所有实例并返回新的长度。空间复杂度要求–原地操作
思路1:快指针用于迭代遍历数组,慢指针用于指向下一次添加的位 置。

2.2例题

2.2.1 移除元素

题目如概述中

class Solution(object):
    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        n=len(nums)
        j=0
        for i in range(n):
            if nums[i]!=val:
                nums[j]=nums[i]
                j+=1
        return j

2.2.2 最大连续1的个数

给定一个二进制数组,计算其中最大连续1的个数。
k,m=0,0
快指针遇到1一直加,直至遇到0,统计一下当前1的个数,更新慢指针的位置。
慢指针指向连续1的开头,快指针指向连续1的结尾。
当快指针遇到0之后,统计一下结果。当遇到下一个1时慢指针才更新。

class Solution(object):
    def findMaxConsecutiveOnes(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n=len(nums)
        count=0
        max_count=0
        for i in range(n):
            if nums[i]==1:
                count+=1
            if nums[i]==0:
                max_count=max(max_count,count)
                count=0
        return max(max_count,count)               

2.2.3长度最小的子数组

给定一个含有n个正整数的数组和一个正整数s,找出该u数组中满足其和》=s的长度最小的子数组,并返回其长度。如果不存在符合条件的连续子数组,返回0.

子数组是一个连续的序列
解法1-暴力法

class Solution(object):
    def minSubArrayLen(self, s, nums):
        """
        :type s: int
        :type nums: List[int]
        :rtype: int
        """
        n=len(nums)
        res=n+1
        for i in range(n):
            temp=0
            for j in range(i,n):
                temp+=nums[j]
                if temp>=s:
                    res=min(res,j-i+1)
                    break
        #print (res)
        if res==n+1:
            return 0
        else:
            return res

解法2-双指针
以上思路是保持子数组的左端点不动,去寻找右端点。其实一旦知道这个位置开始的子数组不是最优答案,我们就可以移动左端点。使用两个指针,一个指向数组的开始位置,一个指向数组的最后位置。维护区间内的和>=s,且长度最小。

class Solution(object):
    def minSubArrayLen(self, s, nums):
        """
        :type s: int
        :type nums: List[int]
        :rtype: int
        """
        n=len(nums)
        res=n+1
        temp_sum=0
        left=0
        for i in range(n):
            temp_sum+=nums[i]
            while(temp_sum>=s):
                res=min(res,i-left+1)
                temp_sum-=nums[left]
                left+=1
        #print (res)
        if res==n+1:
            return 0
        else:
            return res

(2.2.1 和2.2.3例题的双指针技巧都解的不充分。

你可能感兴趣的:(算法)