1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class Solution { //1.bf超时 //2.基于条件分析: //abs(nums[i] - nums[j]) <= t //abs(i - j) <= k //可知我们需要控制两个地方,一个是nums的值、另一个是下标 //BF最耗时的地方,每次都要从[i-k,i][i,i+k],开始查找并判断大小,因为取的是绝对值nums[i] - nums[j]和nums[j] - nums[i]一样(i和j同理),所以只需要维护一个方向 //所以使用大小为k的有序集合TreeSet能有效解决这个问题 //维护一个大小为k的TreeSet存储nums[i]的值,大小为k是为了控制下标,值有序我们可以快速的取出比当前大的值(不像BF需要一个一个比较) //遍历nums计算出当前nums[j]的可取范围,在TreeSet中ceiling出(nums[i]-t),就是在TreeSet查找比nums[i]-t大的数, //如果有比nums[i]-t大的,且小于nums[i]+t直接返回true,在遍历的同时维护TreeSet大小为k //nums[j]取值范围:上限nums[i]+t,下限nums[i]-t, // //1.为什么nums[j]上限是nums[i]+t,下限是nums[i]-t,通过解开绝对值就可得出. public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { int n = nums.length; TreeSet<Long> set = new TreeSet<Long>(); for (int i = 0; i < n; i++) { //查找比nums[i]-t大的数 Long ceiling = set.ceiling((long) nums[i] - (long) t); //如果有比nums[i]-t大的,且小于nums[i]+t直接返回true if (ceiling != null && ceiling <= (long) nums[i] + (long) t) { return true; } //添加进集合 set.add((long) nums[i]); if (i >= k) {//维护大小为k的有序集合 set.remove((long) nums[i - k]); } } return false; } public boolean containsNearbyAlmostDuplicateBF(int[] nums, int k, int t) { int n =nums.length; for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ if(Math.abs(i-j)>k)continue; if(Math.abs(((long)nums[i] - (long)nums[j]))<=t)return true; } } return false; } }
|