題目:Contains Duplicate
Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.
Input:
- 數組 :: int[]
Output:
- 數組是否有重復的數 :: boolean
Intuition:
最最直接的想法是用set,因為這是set最最明顯的性質了。如果某個數無法加入set中那么就是duplicates了。注意set里的search與insert都是constant time。
Code:
TC: O(n) SC: O(n)
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int n: nums){
if (set.contaiAns(n)){
return true;
}
set.add(n);
}
return false;
}
題目:Contains Duplicate II
Given an array of integers and an integer k, find out whether there are two distinct indices i and j in the array such that nums[i] = nums[j] and the absolute difference between i and j is at most k.
Input:
- 數組 :: int[]
- 兩duplicates的index差最多為k :: int
Output:
- 數組是否有重復的數 :: boolean
Intuition:
沿用之前題目的使用set的思想。但此時,我們不僅要往set里放值,而且還要往外拿。為什么?因為當set里的值的index與當前值的index大于k時,他對于解就沒有價值了,那么干啥還要留著他捏?所以我們保持一個大小為k的Hashset就夠了。另外remove() 的時間復雜度也是constant的。
Code:
TC:O(n) SC: O(min(n, k))
public boolean ContainsDuplicateII(int[] nums, int k){
Set<Integer> set = new HashSet<>();
for (int n: nums) {
if (set.contains(n)){
return true;
}
set.add(n);
//Sliding window
if (set.size() > k) {
set.remove(nums[i - k]);
}
}
return false;
}
題目:Contains Duplicate III
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.
Input:
- 數組 :: int[]
- 兩duplicates的index差最多為k :: int
- 兩duplicates的值差最多為t :: int
Output:
- 數組是否有重復的數 :: boolean
Intuition:
這回不僅在index做了限制,連值上也做了限制。那最直接的想法就是在確保一個條件滿足的情況下,去檢查另一個條件是否滿足。
如果用treeset的話,因為已經是sorted的情況,那么就檢查某一個值的相鄰最近的值(ceiling和floor)滿不滿足值差最多為t的條件。注意Treeset的sort復雜度是nlg(n), 增刪改查的復雜度是lg(n).同樣的使用sliding window的思路。
Code
TC:O(nlog(min(n,k))) SC:O(nlog(min(n,k)))
public boolean ContainsDuplicatesIII(int[]nums, int k, int t){
Set<Integer> treeset = new TreeSet<>();
for (int i = 0; i < nums.length; i++){
//check ceiling
int ceiling = set.ceiling(nums[i]);
if (ceiling != null && ceiling - t <= nums[i]){
return true;
}
//check floor
int floor = set.floor(nums[i]);
if(floor != null && floor + t >= nums[i]){
return true
}
set.add(nums[i]);
//sliding window
if(set.size() > k){
set.remove(nums[i - k]);
}
}
return false;
}
有沒有O(n)的解法呢?想想看在O(n)內可以完成sort的算法是什么?桶排序對不對?當然我們這題沒有必要完全sort整個數組,只不過利用了每個桶中數值都在設定范圍內這一特性。
我們設桶的size為t,那么可以再k范圍內扔進一個桶的數一定能滿足條件。另外需要考慮的兩個地方就是這個桶兩邊的桶,也可能還有值差小于t的情況,要分別檢查下~
要注意的tricky的地方在于,對于負數,桶的選擇要先加1除以桶的size再減一。為什么這么做呢? 舉個??,在Java里,-3/5是0,而它應該是在index為-1的桶中。那么就需要這么做修正下。當然如果用python等別的語言不存在這個顧慮就不用考慮這個情況了。
Code
TC:O(nlog(min(n,k))) SC:O(nlog(min(n,k)))
public boolean ContainsDuplicatesIII(int[] nums, int k, int t){
Map<Long, Long> map = new HashMap<>();
int size = t + 1 // in case t == 0, we need to add extra 1
for (int i = 0; i< nums.length; i++){
int idx = getIdx(nums[i], size);
//duplicates are in the same bucket
if(map.containsKey(idx)){
return true;
}
//duplicates are in neighbour buckets
if (map.containsKey(idx + 1) && Math.abs(nums[i] - map.get(idx + 1))){
return ture;
}
if (map.containsKey(idx - 1) && Math.abs(nums[i] - map.get(idx - 1))){
return ture;
}
map.put(idx, (long)(nums[i]));
if(map.size() > k){
map.remove(getIdx(nums[i - k], size));
}
}
}
public int getIdx(int x, int size){
if(x < 0){
return (x - 1) / size + 1;
}
return x / size;
}
Reference
https://leetcode.com/problems/contains-duplicate/
https://leetcode.com/problems/contains-duplicate-ii/solution/
https://leetcode.com/problems/contains-duplicate-iii/solution/