题目:Contains Duplicate
给定整数数组,查找数组是否包含任何重复项。 如果数组中的任何值至少出现两次,则函数应返回true,如果每个元素都不同,则返回false。
思路:
可以使用桶排序的思想来,遍历所有元素,通过元素值直接访问标志,当第一次遇到则设标志,第二次遇到就跳出循环。
但是,这样空间复杂度很高,int有32位需要2^32byte;那么就可以考虑使用map;
其实只需要知道有没有重复元素就可以,不一定要找到,可以有更简单的方法;使用set,将数组元素放入set,有重复元素只会存放一遍,最后比较长度就能知道有没有重复。
bool LeetCode::containsDuplicate(vector<int>& nums){ set<int>nondup(nums.begin(),nums.end());//保存所有所有元素一次,如果有重复则只保存一次 return nondup.size() < nums.size();//有重复长度变短 }
题目:Contains DuplicateII
这次是找数组的k个元素中是否有重复。
思路:
和上面类似,只是不需要整个数组,只顺序选其中k个元素。
bool LeetCode::containsNearbyDuplicate(vector<int>& nums, int k){ if (k >= nums.size() || nums.size() < 2){ set<int>nondup(nums.begin(), nums.end());//保存所有所有元素一次,如果有重复则只保存一次 return nondup.size() < nums.size();//有重复长度变短 } auto head = nums.begin(); auto tail = nums.begin() + k + 1; set<int>nondup(head, tail); while (tail != nums.end() && nondup.size() == k + 1){ auto pos = nondup.find(*head); nondup.erase(pos); nondup.insert(*tail); ++head; ++tail; } if (nondup.size() <= k)return true; return false; }
题目:Contains DuplicateIII
这次是找数组的k个元素中是否有差的绝对值不超过的t的2个以上的元素。
思路:
知道使用lower_bound函数就能很快做出来,可以通过lower_bound找到set中满足x >= nums[i] - t的下界,这样就可以按照上面的思路来解决。
bool LeetCode::containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t){ set<long long>nondup; long long tL = t; for (size_t i = 0; i < nums.size();++i){ if (i > k)nondup.erase(nums.at(i - k - 1));//k个元素以上时,每次删除第一个 auto pos = nondup.lower_bound(nums.at(i) - t);//找到x >= nums[i] - t的下界 if (pos != nondup.end() && *pos - nums.at(i) <= t)return true;//检测x <= nums[i] + t的上界 nondup.insert(nums.at(i));//插入新的元素 } return false; }
思路2:
要求差的绝对值<=t。可以用这样的算法来确定:
假设有m和n满足上面的要求,则m/t = n/t或者m/t = n/t + 1或者m/t = n/t - 1;
当n = k*t,m = k*t - a(0 < a < t)时,m/t = n/t - 1;
这样就能按照前面的思路来求解,但是要注意一些特殊情况:
1.负数的情况,可以减去MIN_INT;
2.可能会溢出,使用long long类型;
3.t < 0或k<1的情况。
bool LeetCode::containsNearbyAlmostDuplicate2(vector<int>& nums, int k, int t){ if (k < 1 || t < 0) return false; if (nums.size() < 2)return false; map<long long, long long>nondup; int MIN_INT = -2147483647 - 1;//不能直接将写-2147483648,因为便一起会先将2147483648转成int,再取负然后赋值 long long tL = (long long)t + 1; for (size_t i = 0; i < nums.size(); ++i){ long long value = ((long long)nums.at(i) - MIN_INT); long long bucket = value / tL; auto pre = nondup.find(bucket - 1);//n = k*tL m = k*tL - a;(0 < a < t) auto post = nondup.find(bucket + 1);//n = k*tL m = k*tL + a;(0 < a < t) if (nondup.find(bucket) != nondup.end() || (pre != nondup.end() && value - pre->second <= t) || (post != nondup.end() && post->second - value <= t))return true; if (i >= k){ long long temp = ((long long)nums.at(i - k) - MIN_INT) / tL; nondup.erase(temp);//k个元素以上时,每次删除第一个 } nondup[bucket] = value;//插入新的元素,通过n/(t+1)使t的间隔消失 } return false; }