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=0j=len(s)-1while(i<j):s[i],s[j]=s[j],s[i]i+=1j-=1return s
1.2.2數組拆分
給定長度為2n的數組,將這些數字分為n對,例如(a1,b1),(a2,b2),...,(an,bn)(a_1,b_1),(a_2,b_2),...,(a_n,b_n)(a1?,b1?),(a2?,b2?),...,(an?,bn?),使得從1-n的min(ai,bi)min(a_i,b_i)min(ai?,bi?)總和最大。
舉例:a1,a2,a3,a4,a5,a6a_1,a_2,a_3,a_4,a_5,a_6a1?,a2?,a3?,a4?,a5?,a6?升序排列
6個數分三對,能出現在和計算式中的最大數為a5a_5a5?(此時a5和a6a_5和a_6a5?和a6?配對),同理剩下的4個數中,依次出現在和式中的為a1,a3a_1,a_3a1?,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<index2(索引下標從1開始)
一個輸入只有一對答案,不能重復使用個數組中的元素。
雙指針求解:
if (nums[i]+nums[j]==target): return(i+1,j+1)
if(nums[l]+nums[r]>target):r-=1
if(nums[l]+nums[r]<target):l+=1
class Solution(object):def twoSum(self, numbers, target):""":type numbers: List[int]:type target: int:rtype: List[int]"""l=0r=len(numbers)-1while(l<r):if numbers[l]+numbers[r]==target:return [l+1,r+1]if numbers[l]+numbers[r]<target:l+=1if numbers[l]+numbers[r]>target:r-=1return -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=0for i in range(n):if nums[i]!=val:nums[j]=nums[i]j+=1return 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=0max_count=0for i in range(n):if nums[i]==1:count+=1if nums[i]==0:max_count=max(max_count,count)count=0return 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+1for i in range(n):temp=0for 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 0else: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+1temp_sum=0left=0for 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 0else:return res
(2.2.1 和2.2.3例題的雙指針技巧都解的不充分。