【LeetCode】滑動窗口、雙指針、單調隊列和單調棧(持續更新。。。)

167. 兩數之和 II - 輸入有序數組

思路:

  • 一般雙指針的主要思路是先找到暴力解法,然後考慮有沒有單調性之類的性質可以利用,再進行優化
  • 使用i,j兩個指針,初始位置在0和數組末尾,若相加的結果大於target則說明當前的結果需要減小,則j往前移;若相加的結果小於target則說明當前的結果需要增大,則i往後移。
class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        n = len(numbers)
        i, j = 0, n-1
        while i<j:
            if numbers[i] + numbers[j] < target:
                i += 1
            elif numbers[i] + numbers[j] > target:
                j -= 1
            else:
                return [i+1, j+1]

88. 合併兩個有序數組

思路:

  • 這道題就是基本的歸併思想
  • 由於題目要求的是把結果存入nums1中,則要注意不能從前開始比較合併,要從後面開始
  • 這裏需要注意的是如果p1,p2賦初值爲m-1,n-1,可能就取不到下標爲0的那個數
class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        # nums1的最大數指針 nums2的最大數指針 結果集的最大數指針
        p1, p2, p3 = m, n, m+n
        while p1 and p2:
            if nums1[p1-1] >= nums2[p2-1]:
                nums1[p3-1] = nums1[p1-1]
                p1 -= 1
            else:
                nums1[p3-1] = nums2[p2-1]
                p2 -= 1
            p3 -= 1
        while p2:
            nums1[p3-1] = nums2[p2-1]
            p2 -= 1
            p3 -= 1

26. 刪除排序數組中的重複項

思路:

  • 由於不能申請額外空間,考慮直接在數組上進行操作。
  • 設置兩個指針,一個指向當前需要存儲數的位置k,一個對數組進行掃描i
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        if not nums:
            return 0
        k = 1
        for i in range(1, len(nums)):
            if nums[i] != nums[i-1]:
                nums[k] = nums[i]
                k += 1
        return k

76. 最小覆蓋子串

思路:

  • 首先一樣的步驟,考慮暴力解法,會需要O(n^2)的時間複雜度
  • 然後考慮單調性,我們可以使用兩個指針,i,j指示答案字符串的首尾。當i逐漸往後移,j必定只能往後增加,不可能往前,因爲那樣會包含了最佳答案在裏面,不可能得到最短的。
  • 這樣的話,維護一個hash表,記錄t字符串每個字符出現的次數,最後考慮的就是i依次往後遍歷,j從起點開始,i往後一格,將hash對應位置-1,j也往後,若當前所指的位置hash表中對應結果小於0了,說明這個字符不在答案中,j往後移
  • 再維護一個答案t所需要幾個不同的字符,當都得到了,比較一下當前s[j:i+1]的長度,用res記錄最短的即是答案
class Solution:
    def minWindow(self, s: str, t: str) -> str:
        hash_table = {}
        for ch in t:
            hash_table[ch] = hash_table.get(ch, 0) + 1
        cnt = len(hash_table.items())

        res = ""
        c, j = 0, 0
        for i in range(len(s)):
            num = hash_table.get(s[i], 0)
            if num == 1:
                c += 1
            elif num==0:
                hash_table[s[i]] = hash_table.get(s[i], 0)
            hash_table[s[i]] -= 1
            # j從前往後
            while hash_table[s[j]] < 0 and j<i:
                hash_table[s[j]] += 1
                j += 1
            if c==cnt:
                if not res or len(res)>i-j+1:
                    res = s[j:i+1]
        return res

32. 最長有效括號

思路:

  • 首先需要記住括號序列的一個重要性質:假如將(當做數字1,)當做數字-1;則合法的括號序列前綴和一定是>=0的,並且整個序列的最終結果肯定是0
  • start枚舉當前這一段的開頭,cnt記錄前綴和。
  • 若是當前的cnt<0了,說明這一段是不合法的,start=i+1,cnt=0
  • 若是當前的cnt>0,繼續做
  • 若是當前的cnt==0,說明當前的這一段是合法的,比較和res的長度,若大於則更新res
  • 注意,爲了防止出現((())這種情況,也就是最後的和不會等於0的情況,所以還需要反過來再做一遍
  • (和)的ascii碼二進制相差一位,可以直接異或處理
class Solution:
    def longestValidParentheses(self, s: str) -> int:
        reverse_s = list(s[::-1])
        for index, ch in enumerate(reverse_s):
            reverse_s[index] = chr(ord(ch)^1)
        return max(self.work(s), self.work("".join(reverse_s)))
    
    def work(self, s):
        """
        返回當前子串的最長長度
        """
        start, cnt = 0, 0
        n = len(s)
        res = 0
        for i in range(n):
            if s[i] == "(":
                cnt += 1
            else:
                cnt -= 1
                if cnt < 0:
                    start = i+1
                    cnt = 0
                elif cnt == 0:
                    res = max(res, i-start+1)
        return res

155. 最小棧

思路:

  • 這個題有點類似於前綴和,始終要維護一個前綴和的最小數。
  • 用兩個棧,一個是模擬棧操作的,一個是始終保存當前棧中最小的數字
class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []
        self.stack_min = []


    def push(self, x: int) -> None:
        self.stack.append(x)
        if not self.stack_min:
            self.stack_min.append(x)
        else:
            self.stack_min.append(min(self.stack_min[-1], x))

    def pop(self) -> None:
        self.stack.pop()
        self.stack_min.pop()


    def top(self) -> int:
        return self.stack[-1]


    def getMin(self) -> int:
        return self.stack_min[-1]


# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章