第85期-基礎技巧:滑動視窗 存在重複元素 II
1 問題描述
給定一個整數陣列和一個整數k,判斷陣列中是否存在兩個不同的索引i和j,使得nums [i] = nums [j],並且 i 和 j的差的 絕對值 至多為 k。
示例 1:
輸入:nums = [1,2,3,1], k = 3
輸出:true
示例 2:
輸入:nums = [1,0,1,1], k = 1
輸出:true
示例 3:
輸入:nums = [1,2,3,1,2,3], k = 2
輸出:false
初始程式碼
from typing import List class Solution: def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:View Code#在此之間填寫程式碼 print(Solution().containsNearbyDuplicate([1,2,3,1],3)) print(Solution().containsNearbyDuplicate([1,0,1,1],1)) print(Solution().containsNearbyDuplicate([1,2,3,1,2,3],2))
2 解題思路
- 標籤:滑動視窗
- 採用滑動視窗,視窗長度最長為k,若長度不超過k只移動right邊界即可
- 若長度超過k,則需要同時移動left。要遍歷視窗內的每一個元素來判斷是否和right相等。
#3 解題方法
fromView Codetyping import List class Solution: def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool: a=[] i,j,b=0,0,len(nums) while i<b: if nums[i] in a:return True a.append(nums[i]) i+=1 if j==k: a.pop(0)else:j+=1 return False print(Solution().containsNearbyDuplicate([1,2,3,1],3)) print(Solution().containsNearbyDuplicate([1,0,1,1],1)) print(Solution().containsNearbyDuplicate([1,2,3,1,2,3],2))
第1-3,15-17行:題目中已經給出的資訊,執行程式碼時要根據這些程式碼進行編輯
第4行:定義空列表a用於存放nums中的元素
第5行:定義變數i,j,b分別賦值0,0和nums列表的長度
第6行:當i小於列表長度時,執行迴圈
第7行:判斷nums中索引為i的元素是否在列表a中,若在,則返回true
第8-9行:若不在,則在列表中新增該元素,並令索引i加一
第10行:判斷此時列表a長度是否小於k
第11行:若等於k,則需要刪除a視窗第一個元素
第12行:若不等於k則小於k,則令j加一代表視窗長度加一
第13行:若一直未返回True,則沒有滿足題意的,返回False
程式碼執行結果為:
#演算法講解
這裡用到了基礎技巧:滑動視窗,簡單講解下這個技巧:
什麼是滑動視窗
滑動視窗,顧名思義,就是有一個大小可變的視窗,左右兩端方向一致的向前滑動(右端固定,左端滑動;左端固定,右端滑動)。
可以想象成佇列,一端在push元素,另一端在pop元素,如下所示:
假設有陣列[a b c d e f g h]
一個大小為3的滑動視窗在其上滑動,則有:
[a b c]
[b c d]
[c d e]
[d e f]
[e f g]
[f g h]
適用範圍
- 1、一般是字串或者列表
- 2、一般是要求最值(最大長度,最短長度等等)或者子序列
演算法思想
- 1、在序列中使用雙指標中的左右指標技巧,初始化 left = right = 0,把索引閉區間 [left, right] 稱為一個視窗。
- 2、先不斷地增加 right 指標擴大視窗 [left, right],直到視窗中的序列符合要求。
- 3、此時,停止增加 right,轉而不斷增加 left 指標縮小視窗 [left, right],直到視窗中的序列不再符合要求。同時,每次增加 left前,都要更新一輪結果。
- 4、重複第 2 和第 3 步,直到 right 到達序列的盡頭。
思路其實很簡單:第 2 步相當於在尋找一個可行解,然後第 3 步在優化這個可行解,最終找到最優解。左右指標輪流前進,視窗大小增增減減,視窗不斷向右滑動。