leetcode 220. Contains Duplicate III | 220. 存在重复元素 III (Treeset解法+分桶解法)
題目
https://leetcode.com/problems/contains-duplicate-iii/
題解
方法1:Treeset 解法,滑動窗口 & 二分
思路參考:https://leetcode-cn.com/problems/contains-duplicate-iii/solution/gong-shui-san-xie-yi-ti-shuang-jie-hua-d-dlnv/
用 Treeset 維護滑動窗口。Treeset 基于紅黑樹,插入和查找都有折半的效率。
import java.util.Arrays; import java.util.TreeSet;class Solution {public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {TreeSet<Long> set = new TreeSet<>();for (int i = 0; i < nums.length; i++) {Long floor = set.floor((long) nums[i]); // 小于的里面的最大的if (floor != null && floor >= (long) nums[i] - t) return true;Long ceiling = set.ceiling((long) nums[i]); // 大于的里面的最小的if (ceiling != null && ceiling <= (long) nums[i] + t) return true;set.add((long) nums[i]);if (i - k >= 0) set.remove((long) nums[i - k]);}return false;} }方法2:分桶解法
參考:https://leetcode-cn.com/problems/contains-duplicate-iii/solution/c-li-yong-tong-fen-zu-xiang-xi-jie-shi-b-ofj6/
將 t+1 作為桶的模:
核心思路
我們從頭開始遍歷數組,對于當前下標i,有效的桶是下標為[i-k,i+k]的元素構造的桶,對于每一個i我們只需要看前面是否有無效的桶并刪除即可,后面的元素我們沒遍歷到,自然也不會產生桶,所以 [i-k,i] 的桶是有效的,如果 nums[i-(k+1)] 產生的桶存在,我們要把其刪除掉。因為 abs(i-(i-(k+1))) = abs(k+1) = k+1 > k。這是不在我們下標范圍內的元素產生的桶,我們不需要判斷是否滿足條件,直接把這個桶刪除了。
對于遍歷到的元素 nums[i] 進行分桶,獲取當前桶 ID,如果當前桶中已經有元素了,那么說明能找到符合條件的元素,直接返回true(因此,我們每個桶中最多只可能有一個元素,多了我們會直接返回結果)。如果當前桶沒有元素,那么看看前相鄰的桶有沒有元素,如果有元素,那么進行做差比較,判斷是否滿足條件,滿足則返回true。如果沒有找到,那么把這個元素裝入桶中,供別的元素判斷。如果到最后都沒有找到滿足條件的元素,我們就返回false;
class Solution { public:long getID(long x, long t){//如果x元素大于等于零,直接分桶if(x>=0){return x / ( t + 1 );}else{//如果x元素小于零,偏移后再分桶return ( x + 1 )/( t + 1 ) - 1 ;}return 0;}bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {int n = nums.size();//我們用unordered_map來實現桶,其底層實現是一個哈希表.unordered_map<int,int> m;for(int i = 0 ; i < n; i++ ){//當前元素long x = nums[i];//給當前元素生成id,這里我們同一個id的桶內元素滿足abs(nums[i] - nums[j]) <= tint id = getID(x,t);//前面的i-(k+1)是超出了范圍的桶,我們把它提前刪除,以免影響判斷if( i-(k+1) >= 0 ){//把下標不滿足我們判斷范圍的桶刪除了m.erase(getID(nums[i-(k+1)],t));}//看看當前元素屬于的桶中有沒有元素if(m.find(id)!=m.end()){return true;}//看看前面相鄰桶有沒有符合條件的if(m.find(id - 1) != m.end() && abs(m[id-1]-x) <= t){return true;}//看看后面相鄰桶有沒有符合條件的if(m.find(id + 1) != m.end() && abs(m[id+1]-x) <= t){return true;}//分桶,把這個元素放入其屬于的桶m[id] = x;}return false;} };Q&A
1、每個桶只存放一個元素,夠用嗎?
桶的解法相當凝練,不過有一點可以啰嗦兩句。不知道有沒有人疑惑,在比較id - 1和id + 1這兩個相鄰桶時,只比較了一個元素,這足夠嗎?哈希表的行為不是會用新元素覆蓋舊元素,一個桶里有多個元素怎么辦?
其實是覆蓋根本不會發生…因為一旦要覆蓋,就說明存在兩個元素同屬一個桶,直接返回true了。這就是題解說的“一個桶內至多只會有一個元素”——數組輸入里當然可以有多個元素屬于同一個桶,但是一旦出現一對,算法就結束了。
2、 i-(k+1) 是超出了范圍的桶,我們把它提前刪除的話,會不會誤傷有效范圍內的桶?
誤傷根本不會發生。假設有一個序列是 5, 7, 9, 1_a, [3, 5, 1_b, 1_c] 的話(括號內是當前窗口),我們會擔心刪除 1_a 的時候會誤傷 1_b 的桶。而實際上,不會存在這種誤傷問題。因為只有相同桶里的元素才能被誤傷,而既然有兩個元素屬于同一個桶,算法早就應該結束了。
總結
以上是生活随笔為你收集整理的leetcode 220. Contains Duplicate III | 220. 存在重复元素 III (Treeset解法+分桶解法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: leetcode 216. Combin
- 下一篇: leetcode 221. Maxima