题目
给你一个整数数组 nums
和两个整数 k
和 t
。请你判断是否存在 两个不同下标 i
和 j
,使得 abs(nums[i] - nums[j]) <= t
,同时又满足 abs(i - j) <= k
。
如果存在则返回 true
,不存在返回 false
。
示例 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
提示:
0 <= nums.length <= 2 * 104
-231 <= nums[i] <= 231 - 1
0 <= k <= 104
0 <= t <= 231 - 1
注意:本题与主站 220 题相同: 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
LCR 057. 存在重复元素 III - 力扣(LeetCode)
题解
思路一:暴力,看x的前k个元素有没有满足条件的,挨个判断。复杂度太高
思路二:题目可以转化为:在当前元素nums[i]下,寻找前k个元素中有没有元素使得其在区间[nums[i]-t,nums[i]+t]之间。这需要一个数据结构:1.支持新增和删除元素,维护滑动窗口。2.内部元素有序,可以判断是否有区间内元素。有序集合TreeSet,内部由红黑树实现。
代码:
class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
TreeSet<Long> set=new TreeSet<Long>();
for(int i=0;i<nums.length;i++) {
Long tmp=set.ceiling((long)nums[i]-t);
if(tmp!=null&&tmp<=(long)nums[i]+(long)t) return true;
set.add((long)nums[i]);
if(i>=k) set.remove((long)nums[i-k]);
}
return false;
}
}
tips:一般写List=new ArrayList,即抽象而不是实现,后续无论是array还是linked,都可以解耦修改。但是当需要用到ArrayList特有的方法时就只能写ArrayList=。例如本题目中的ceiling,floor方法
思路三:桶排序,每t+1个元素放在一个桶中,这样桶中差值最大即为t(例如0,1,2最大差值为2,t=2但总数=3).然后当前元素x,如果k内有同桶元素即true,若没有则查看相邻桶再做判断。因为区间为[x-t,x+t],因此最大最小可能绝对不会出相邻桶。关于分桶,x>0,[0,t]=0(特殊情况,不套n),[t+1,2t+1]=1,[(n)t+1,(n+1)t+1]=n。x<0,[-t,-1]=-1,[-t-1,-2t-1]=-2,[-(n+1)t-1,-(n)t-1]=-n.所以x>0时桶号n=x/t+1=x/w。x<0时,桶号n=x+1/t=x+1/w-1。除法会自动向上取整,正负数的上不一样,即向0靠近。
用map<Long,Long>表示<桶号,桶>因为一个桶有两个元素就会返回true,因此一个桶只有一个元素,可以用哈希表的一条key-value表示桶
为什么只留一个值可以确保?比如桶[1][3],[1][4]当桶里只有一个元素时,t=2,[0,1,2][3,4,5].查1时3满足,4不满足.若nums没有3或13距离过远,则不考虑;若有3且满足下标差<k,这时14判断false,但是遍历到3时会和4true。如果想不明白,map的value存一个collection也可以。
下标的话,只保留x之前k个元素的值在桶里,因此只要桶里有,就true
代码:
class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
long w = (long) t + 1;
Map<Long, Long> map = new HashMap<Long, Long>();
for (int i = 0; i < nums.length; i++) {
long id = getID(nums[i], w);
if (map.containsKey(id)) return true;
if (map.containsKey(id - 1) && Math.abs(nums[i] - map.get(id - 1)) <= t) return true;
if (map.containsKey(id + 1) && Math.abs(nums[i] - map.get(id + 1)) <= t) return true;
map.put(id, (long) nums[i]);
if (i >= k) map.remove(getID(nums[i - k], w));
}
return false;
}
public long getID(long x, long w) {
if (x >= 0) return x / w;
else return (x + 1) / w - 1;
}
}