220. 存在重复元素 III
题目:
给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ。
示例 1:
输入: nums = [1,2,3,1], k = 3, t = 0
输出: true
示例 2:
输入: nums = [1,0,1,1], k = 1, t = 2
输出: true
示例 3:
输入: nums = [1,5,9,1,5,9], k = 2, t = 3
输出: false
解答:
首先这题用例挺TM蠢的,题目说了t和k为绝对值,居然还有k为负数的用例,劳资又不是ACM选手,只是想刷个算法题而已。。
1.桶排序:
照着官方题解写的。不过有几个用例过不去,如t==0的特殊情况,利用len(list)!=len(set(list))可判断,还有t<0、k<0的(sb)用例额外判断一下,以及某些极其分散的用例,如[200000000000,-2222222222222222],2,2这样的。我是判断一下llog(l)和max-min的大小关系(l是数组长度,max、min分别为数组最大最小数),若llogl小,那就直接排序解决,不然用桶排序的话要生成的桶太多了,而且几乎全部是无用的桶。
复杂度O(n)
代码:
1 from math import log 2 class Solution: 3 def containsNearbyAlmostDuplicate(self, nums, k, t) : 4 l=len(nums) 5 if l<2 or t<0 or k<0: 6 return False 7 if (t==0): 8 return len(nums)!=len(set(nums)) 9 _max=max(nums) 10 _min=min(nums) 11 if l*log(l)<_max-_min: 12 for i in range(l): 13 for j in range(max(i-k,0),i): 14 if abs(nums[i]-nums[j])<=t: 15 return True 16 return False 17 hashtable=[[]for i in range((_max-_min)//t+1)] 18 for i in range(l): 19 x=nums[i] 20 m=(x-_min)//t 21 for p in hashtable[m]: 22 if abs(p[0]-i)<=k and abs(p[1]-x)<=t: 23 return True 24 le,ri=m-1,m+1 25 if le>=0: 26 for y in hashtable[le]: 27 if abs(y[0]-i)<=k and abs(y[1]-x)<=t: 28 return True 29 if ri<len(hashtable): 30 for z in hashtable[ri]: 31 if abs(z[0]-i)<=k and abs(z[1]-x)<=t: 32 return True 33 hashtable[m].append((i,x)) 34 return False
2.二叉搜索树+滑动窗口:
由于对于两个数的索引差有绝对值<=k的限制,所以考虑维护一个长度k的窗口进行滑动。但由于窗口内的元素是无序的,如果对于每个窗口我们都进行排序,复杂度会太高。所以考虑用有序集合(C++里的set或者multi_set),窗口大小k由我们自己维护,窗口内的有序性交给set进行维护。每当我们滑动窗口时,考察右边移入窗口的新数字nums[i],因为窗口内的数字和当前索引i的索引差的绝对值一定满足<=k的要求,那么如果窗口内有相同的数字就可以返回true。如果没有,查找窗口内有无满足大小介于[nums[i]-t,nums[i]+t]范围内的数字,如果有则返回true。这里利用C++的lower_bound和upper_bound函数。
map/set.lower_bound(num),返回大于等于num的第一个迭代器
map/set.upper_bound(num),返回大于num的第一个迭代器
带模板的lower_bound格式是这样的:lower_bound<容器迭代器类型,容器元素类型>(起始迭代器,尾迭代器,元素),如:
1 lower_bound<vector<int>::iterator,int>(p.begin(),p.end(),2);
upper_bound模板函数类似。
这个方法还是挺巧妙的,以前没有见过,记录下,滑动窗口不一定专属于线性结构。
复杂度:O(n logk)
代码:
比较坑爹的是有几个大数用例,得加long,不然AC不了。
1 class Solution { 2 public: 3 bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) { 4 if(t<0 or k<0){return false;} 5 set<long> st; 6 for (int i = 0; i < nums.size(); ++i) { 7 if (st.count(nums[i])) { 8 return true; 9 } 10 auto it = st.upper_bound(nums[i]); 11 if (it != st.end() and *it - nums[i] <= t) { 12 return true; 13 } 14 it = st.lower_bound(long(nums[i]) - t); 15 if (it != st.end() and *it<nums[i]) { 16 return true; 17 } 18 st.insert(nums[i]); 19 if (st.size() == k+1) { 20 st.erase(nums[i-k]); 21 } 22 } 23 return false; 24 } 25 };
2020-02-17 15:30:19

浙公网安备 33010602011771号