LeetCode 220 存在重复元素|||

1.暴力 

class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        if(k==10000) return false;
        for(int i=0;i<nums.length;i++){
            for(int j=i+1;j<nums.length&&j<=i+k;j++){
                if(Math.abs((long)nums[i]-(long)nums[j]) <= t) 
                    return true;
            }
        }
        return false;
    }
}

 

if(k==10000) return false;  没有这一句,后面的测试用例过不去

没有long  [-2147483648,2147483647] 1 1 测试用例过不去

其实我觉得那个测试用例就是在卡这种暴力的方法,让你过不去

2.TreeSet

在这里补充几个知识,

Integer和int的区别:

1、Integer是int的包装类,int则是java的一种基本数据类型
2、Integer变量必须实例化后才能使用,而int变量不需要

3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值 
4、Integer的默认值是null,int的默认值是0(这一条说明了为啥要加一句 c!=null)

 

这里提到这个是因为TreeSet<Integer>,泛型只能使用Integer

因为int是基本类型,不包含集合框架中所需要的方法。以这里为例,连hashCode都没有实现,如何计算散列值?所以需要用Integer。泛型里的类型都必须为Object的子类。

 

TreeSet  自平衡二叉搜索树

这是真的java的这些集合封装好了,是真的好用,而C,哎,自己造轮子吧

class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        TreeSet<Integer> set = new TreeSet<>();
        for(int i=0;i<nums.length;i++){

            Integer c = set.ceiling(nums[i]);
            if(c!=null && (long)c-(long)nums[i]<=t) return true;

            Integer f = set.floor(nums[i]);
            if(f!=null && (long)nums[i]-(long)f<=t) return true;

            set.add(nums[i]);
            if(set.size()>k) set.remove(nums[i-k]);
        }
        return false;
    }
}

 

 所以这是方便了个锤子?按理说,现在维持的set是非常好找这个c和f的,比原来再加一个循环看起来是要更便捷的,可能这个函数ceiling和floor背后实现很麻烦??

3.桶(真的是的     第一次见+第一次用     桶排序 )

 非常多的小细节啊

1.泛型必须用Object的子类型,所以只能用Long,不能用long

2.这里w=t+1,这个桶里应该放的数的范围在nums[i]~nums[i]+t,即为t个长度

3.这里还是用了一个滑动窗口,这个窗口还是k大小,但是这里用了桶排序,所以窗口大小就变成了桶的个数

4.特别需要注意的是,每个桶里只放了一个数,这是因为当你发现有第二个数可以放进这个桶时,证明你已经找到了满足k和t的这个数,可以return了,所以一个桶里只会有一个数,所以才可以用get(key)直接取,不然一堆数,还要加个循环(我才开始一直没想明白来着)

5.if(i>=k) map.remove(getId(nums[i-k],w));  这个地方,我才开始也不理解为啥这个条件是i>=k,其实跟着测试例子走一遍就知道了,从一开始你没有k个桶的时候,你不需要remove,但是当i>=k时,这时,你已经有了k个桶,但还没找到满足条件的数,你需要舍弃最开始的那个桶

6. return (num+1)/w-1;  这里getId的负数处理,我才开始也没懂,其实是把负数一起往右移,仿佛是-3,-2,-1--->-2,-1,0

大概是这个感觉,然后就除以w,但是0已经用过了,就又将结果直接往左移

class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        Map<Long,Long> map = new HashMap<>();
        //w为桶的长度,应该为t+1,这个桶里应该放的数的范围nums[i]~nums[i]+t,即为k个
        int w=t+1;
        for(int i=0;i<nums.length;i++){
           //1.首先拿到m
           long n = getId(nums[i],w);
           //2.判断map的对应的编号的桶里有没有这个编号的桶
            if(map.containsKey(n)) return true;
           //3.判断左右近邻的桶中有没有满足要求的数
           if(map.containsKey(n+1)&&Math.abs(map.get(n+1)-nums[i]) <= t) return true;
           if(map.containsKey(n-1)&&Math.abs(nums[i]-map.get(n-1)) <= t) return true;
           //4.如果nums[i]不满足要求,把nums[i]放入n编号的桶中
           map.put(n,(long)nums[i]);
           if(i>=k) map.remove(getId(nums[i-k],w));
        }
        return false;
    }
    private long getId(int num,int w){
        if(num>=0){
            return num/w;
        }else{
            //把所有的负数向右移1,从0的位置开始,但是算出来的数包含0,就整体减1
            return (num+1)/w-1;
        }
    }
}

 

今天这3个题,真是做了很久了,幸亏国庆,比较闲,能静下心来好好做题,哈哈哈哈哈哈哈哈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值