【Leetcode】220. Contains Duplicate III 存在重复元素 III

1

解法

本题的关键其实是滑动窗口,需要判断nums[i]前长度为k的窗口里有没有[nums[i]-1,nums[i]+t]范围内的数
要注意k和t都有可能是负数……神坑

解法一:离散化+BIT

我自己用的比较naive的BIT来做的,非常不美= =

class Solution(object):
    def containsNearbyAlmostDuplicate(self, nums, k, t):
        """
        :type nums: List[int]
        :type k: int
        :type t: int
        :rtype: bool
        """
        n = len(nums)
        if n==0 or k<0 or t<0:
            return False
        from bisect import bisect_right,bisect_left
        unique = sorted(set(nums))
        idx = {}
        for i,v in enumerate(unique):
            idx[v] = (i+2,bisect_left(unique,v-t,hi=i)+1,bisect_right(unique,v+t,lo=i)+1)
        l = len(unique)+1
        c = [0]*l
        def lowbit(k):
            return k&-k
        def add(k,val):
            while k<=l:
                c[k-1] += val
                k += lowbit(k)
        def csum(k):
            res = 0
            while k>=1:
                res += c[k-1]
                k -= lowbit(k)
            return res
        for i,a in enumerate(nums):
            if i>k:
                add(idx[nums[i-k-1]][0],-1)
            if csum(idx[a][2])-csum(idx[a][1]):
                return True
            add(idx[a][0],1)
        return False

解法二:滑动窗口+treemap

主要利用treemap的排序性质,然而,python没有treemap= =

解法三:滑动窗口+桶排序

这个思路太巧了
首先划分桶,我们想想与一个数差距不超过t,那么也就是说差距可以是0,1,...,t,我们将nums[i]//(t+1)相同的数都放到一个桶里,这个桶里的数字之间差距一定不超过t,此外,相邻的桶里也有可能有差距不超过t的数字,所以我们还要check一下桶nums[i]//(t+1)-1和桶nums[i]//(t+1)-1
注意:
实际编程时每个桶用int存而不需要用list存,这是因为每个时刻每个桶里最多只可能有一个数,有两个数的时候已经直接返回True了。

class Solution(object):
    def containsNearbyAlmostDuplicate(self, nums, k, t):
        """
        :type nums: List[int]
        :type k: int
        :type t: int
        :rtype: bool
        """
        if len(nums)==0 or t<0 or k<0:
            return False
        from collections import defaultdict
        t += 1
        record = {}
        for i,c in enumerate(nums):
            if i>k and nums[i-k-1]//t in record:
                # 新的窗口内一定没有桶nums[i-k-1]//t里的数
                # 否则在遍历到nums[i-k-1]就会返回真
                record.pop(nums[i-k-1]//t)
            if c//t in record or (c//t-1 in record and c-record[c//t-1]<t) or (c//t+1 in record and record[c//t+1]-c<t):
                return True
            # 此处record里一定没有c//t
            # 否则前面会返回真
            record[c//t]=c
        return False
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值