Task 05: 雙指針

第11-12天打卡,附上學習鏈接

1 學習內(nèi)容

1.1 雙指針(Two Pointers)

雙指針指的是在遍歷元素的過程中,使用兩個指針,方向相反稱之為對撞指針,方向相同則稱之快慢指針,如果屬于不同的數(shù)組/鏈表,則稱之為分離雙指針。在數(shù)組的區(qū)間問題上,雙指針可以將暴力算法的時間復雜度O(n2)降低到O(n)。

1.2 對撞指針

實現(xiàn)步驟:

  • (1)left指針指向第一個元素,right指針指向最后一個元素;

  • (2)循環(huán)體中,滿足條件A,left指針右移;滿足條件B,right指針左移;

  • (3)直到left==right,即相撞時,或其他條件,跳出循環(huán)體。

試用范圍:

  • 查找有序數(shù)組中滿足某些約束條件的一組元素:如二分查找/數(shù)字之和等問題;

  • 字符串反轉問題,如反轉字符串、回文數(shù)、顛倒二進制等問題。

示例習題1:0167 兩數(shù)之和II - 輸入有序數(shù)組 *

題目描述:給一個已按照非遞減順序排列的整數(shù)數(shù)組numbers,從數(shù)組中找出兩個數(shù)滿足相加之和等于目標數(shù)target。函數(shù)應該以長度為2的整數(shù)數(shù)組的形式返回這兩個數(shù)的下標值。numbers的下標從1開始計數(shù),所以答案數(shù)組應當滿足1<=answer[0]<answer[1]<=numbers.length??杉僭O每個輸入只對應唯一的答案,而且你不可以重復使用相同的元素。 樣例1:輸入為numbers=[2, 7, 11, 15],target=9,輸出為[2, 7]; 樣例2:輸入為numbers=[2, 3, 4],target=6,輸出為[1, 3]; 樣例3:輸入為numbers=[-1, 0],target=-1,輸出為[1, 2]。

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

示例習題2:0125 驗證回文串 *

題目描述:給定一個字符串,判斷是否為回文串(只考慮字符串中的字母和數(shù)字字符,且忽略字母的大小寫)?;匚拇刚x和反讀是一樣的。 樣例1:輸入為“A man, a plan, a canal: Panama",輸出為true; 樣例2:輸入為“race a car”, 輸出為false。

解題思路:left指針 == right指針,相等則left+1, right-1,否則返回false。

class Solution:
    def isPalindrome(self, s: str) -> bool:
        left = 0
        right = len(s) - 1
        while left < right:
            if not s[left].isalnum():
                left += 1
                continue
            if not s[right].isalnum():
                right -= 1
                continue
                
            if s[left].lower() == s[right].lower():
                left += 1
                right -= 1
            else:
                return False
        return True

示例習題3:0011 盛最多水的容器 **

題目描述:給定n個非負整數(shù)a1, a2, a3, ..., an, 每個數(shù)代表坐標中的一個點(i, ai)。在坐標內(nèi)畫n條垂直線,垂直線i的兩個端點分別為(i, ai)和(i, 0)。要求找出其中的兩條垂直線,使得它們與x軸共同構成的容器可以容納最多的水。 樣例1:輸入為[1, 8, 6, 2, 5, 4, 8, 3, 7],輸出為49。

解題思路:水量的大小直接受兩條線中較低的那條(比較left和right的高度),循環(huán)體內(nèi)計算面積值時,同時維護更新最大面積值。

class Solution:
    def maxArea(self, height: List[int]) -> int:
        left = 0
        right = len(height) - 1
        ans = 0
        while left <= right:
            area = min(height[left], height[right]) * (right - left)
            ans = max(ans, area)
            if height[left] < height[right]:
                left += 1
            else:
                right -= 1
        return ans
1.4 快慢指針

快慢指針指的是兩個指針從同一側開始遍歷,但移動步長一個快(fast)一個慢(slow),停止的條件可以是快指針移動到數(shù)組尾端,也可以是兩個指針相交,也可以是滿足其他特殊條件。

實現(xiàn)步驟:

  • (1)slow一般指向第一個元素,即slow=0;fast一般指向第二個元素,即fast=1;

  • (2)循環(huán)體內(nèi),滿足條件A,slow+1,滿足條件B或者無條件,fast+1;

  • (3)結束條件,停止循環(huán)。

適用范圍:

  • 一般用于處理數(shù)組的移動、刪除元素等問題,或者鏈表中的判斷是否有環(huán)、長度問題。

示例習題1:0026 刪除有序數(shù)組中的重復項 *

題目描述:給一個有序數(shù)組nums,原地刪除重復出現(xiàn)的元素,使每個元素只出現(xiàn)一次,返回刪除后數(shù)組的新長度。 樣例1:輸入為nums=[1, 1, 2],輸出為2,nums=[1, 2]; 樣例2:輸入為nums=[0, 0, 1, 1, 1, 2, 2, 3, 3, 4],輸出為5,nums=[0, 1, 2, 3, 4]。

解題思路:slow表示去除重復元素后的數(shù)組的末尾位置,slow=0,fast指向當前元素, fast=1。比較slow和fast上的元素是否相等,如果不等,則slow后移動1位,fast指向的元素復制到slow位置上,fast右移一位。重復,直到fast等于數(shù)組長度,返回slow+1即為新數(shù)組的長度。

class Solution:
    def removeDuplicates(self, nums= List[int]) -> int:
        if len(nums) <= 1:
            return len(nums)
        slow, fast = 0, 1
        while fast < len(nums):
            if nums[slow] != nums[fast]:
                slow += 1
                nums[slow] = nums[fast]
            fast += 1
        return slow + 1
1.5 分離雙指針

實現(xiàn)步驟:

  • (1)left_1指向第一個數(shù)組的第一個元素,left2指向第二個數(shù)組的第一個元素;

  • (2)滿足條件A,left_1 + 1, left_2 + 1;

  • (3)滿足條件B,left_1 + 1;

  • (4)滿足條件C,left_2 + 1;

  • (5)遍歷結束一個數(shù)組或其他條件,結束循環(huán)。

適用范圍:

  • 一般用于處理有序數(shù)組合并,求交集、并集問題。

示例習題1:0349 兩個數(shù)組的交集 *

題目描述:給定兩個數(shù)組,編寫函數(shù)實現(xiàn)計算它們的交集。 樣例1:輸入為nums1=[1, 2, 2, 1],nums2=[2, 2],輸出為[2]; 樣例2:輸入為nums1=[4, 9, 5], nums2=[9, 4, 9, 8, 4],輸出為[9, 4]。

解題思路:排序;left_1=0, left_2=0;當相等時,去重并加入輸出答案數(shù)組,left_1+1,left_2+1;left_1<left_2,則left_1+1;left_1>left_2,則left_2+1;輸出。

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        nums1.sort()
        nums2.sort()
        
        left_1 = 0
        left_2 = 0
        res = []
        while left_1 < len(nums1) and left_2 < len(nums2):
            if nums1[left_1] == nums2[left_2]:
                if nums1[left_1] not in res:
                    res.append(nums1[left_1])
                left_1 += 1
                left_2 += 1
            elif nums1[left_1] < nums2[left_2]:
                left_1 += 1
            elif nums1[left_1] > nums2[left_2]:
                left_2 += 1
        return res

2 練習題目

2.1 0344 反轉字符串 *

題目描述:將輸入的字符串反轉。 樣例1:輸入為s=["h", "e", "l", "l", "o"],輸出為["o", "l", "l", "e", "h"]; 樣例2:輸入為s=["H", "a", "n", "n", "a", "h"],輸出為["h", "a", "n", "n", "a", "H"]。

解題思路: 交換前后的字符。

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        left = 0
        right = len(s) - 1

        while left < right:
            s[left], s[right] = s[right], s[left]
            left += 1
            right -= 1
2.2 0015 三數(shù)之和 **

題目描述:給一個包含n個整數(shù)的數(shù)組nums,判斷nums中是否存在三個元素a, b, c,使得a+b+c=0,找出所有和為0且不重復的三元組。 樣例1:輸入為nums=[-1, 0, 1, 2, -1, -4],輸出為[[-1, -1, 2], [-1, 0, 1]]; 樣例2:輸入為nums=[],輸出為[]; 樣例3:輸入為nums=[0],輸出為[]。

解題思路:沒有想明白。待填空。

2.3 0080 刪除有序數(shù)組中的重復項 II **

題目描述:與0026類似,但允許每個元素最多出現(xiàn)兩次。 樣例1:輸入為nums = [1,1,1,2,2,3],輸出為5, nums = [1,1,2,2,3]; 樣例2:輸入為nums = [0,0,1,1,1,1,2,3,3],輸出為7, nums = [0,0,1,1,2,3,3]。

解題思路:數(shù)量進行了限制,比較的時候需要加上前一項。

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        if len(nums) <= 2:
            return len(nums)
        
        slow = 2
        fast = 2
        while fast < len(nums):
            if nums[slow - 2] != nums[fast]:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        return slow
2.4 0283 移動零 *

題目描述:給定一個數(shù)組nums,將所有0移動到數(shù)組的末尾,同時保持非零元素的相對順序。 樣例1:輸入為[0, 1, 0, 3, 12],輸出為[1, 3, 12, 0, 0]。

解題思路:左指針左邊都為非零數(shù),左指針到右指針間都為0。

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        n = len(nums)
        left = right = 0
        while right < n:
            if nums[right] != 0:
                nums[left], nums[right] = nums[right], nums[left]
                left += 1
            right += 1

時間復雜度:O(n);空間復雜度:O(1)。

滑動窗口見

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容