[Leetcode]220. Contains Duplicate III

这是Leetcode第220题,给定一个整数数组,问是否存在两个数差距最多为\(t\),两数的间隔最大为\(k\)
很明显,这里需要用到一个大小为\(K\)的窗口,每次判断窗口内是否存在每个数差值满足\(<=t\)的条件。每一次都进行朴素的判断,需要用\(O(K)\)的时间复杂度,主体循环一次就是\(O(NK)\)。则,我们优化的目标是,怎么在\(O(1)\)时间判断窗口内是否存在满足条件的数。
这里使用了hash Map的思路,更准确地讲,是桶排序的思想。将每个数\(n\)映射到\(n//t\)的key上,如果\(t\)等于零,则是\(n\)本身,每次判断\(key-1\)\(key+1\)上面的数即可。具体代码如下:

class Solution:
    def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
        n=len(nums)
        if t==0 and n==len(set(nums)):
            return False
        dic = {}
        for i, v in enumerate(nums):
            # t == 0 is a special case where we only have to check the bucket
            # that v is in.
            key, offset = (v // t, 1) if t else (v, 0)
            for idx in range(key - offset, key + offset + 1):
                if idx in dic and abs(dic[idx] - nums[i]) <= t:
                    return True

            dic[key] = v
            if i >= k:
                # Remove the bucket which is too far away. Beware of zero t.
                del dic[nums[i - k] // t if t else nums[i - k]]

        return False

使用空间来降低时间复杂度是一个很常见的套路了。但更多时候,我们需要思考如下使用空间记录更多的信息,来帮助我们排除干扰,降低时间复杂度。

扩展

[Leetcode]164. Maximum Gap 最大间距

求一个无序数组排序后相邻数的差距的最小值,如果使用基于比较的排序绝对是\(O(nlogn)\) 的。使用桶在这道题是有天然优势的,最大gap肯定是出现在后一个有效桶的min与前一个有效桶的max之间,不用去比较桶内元素的大小。
具体代码如下:

class Solution:
    def maximumGap(self, nums: List[int]) -> int:
        if len(nums) <= 1 :
            return 0

        minValue = 2**31-1
        maxValue = -2**31
        for num in nums:
            minValue = min(minValue, num)
            maxValue = max(maxValue, num)

        bucket_range = (maxValue - minValue) // len(nums) + 1
        bucket_num = ((maxValue - minValue) // bucket_range) + 1

        hashmapMax = {}
        hashmapMin = {}
        for i in range(len(nums)):
            bucket_id = (nums[i]-minValue) // bucket_range
            if not bucket_id in hashmapMax:
                hashmapMax[bucket_id] = nums[i]
                hashmapMin[bucket_id] = nums[i]
            else:

                hashmapMax[bucket_id] = max(hashmapMax[bucket_id],nums[i])
                hashmapMin[bucket_id] = min(hashmapMin[bucket_id],nums[i])

        prev = 0
        res = 0

        for i in range(1,bucket_num):
            if not i in hashmapMax:
                continue
            if not prev in hashmapMax:
                continue
            res = max(res, hashmapMin[i] - hashmapMax[prev])
            prev = i
        return res

[Leetcode]128. Longest Consecutive Sequence 最长连续序列

给定一个未排序的整数数组,找出最长连续序列的长度。要求算法的时间复杂度为 \(O(n)\)。利用Map存储元素nums[i]的值以及其所在连续序列的长度,此时基本只有两种情况:

  • 数组中出现过元素nums[i]-1或nums[i]+1,意味着当前元素可以归入左或右序列,那么此时假如左右序列的长度分别为left、right,那么显然加入nums[i]后,这整段序列的长度为 1+left+right,而由于这一整段序列中,只可能在左右两端扩展,所以只需要更新左右两端的value值即可。
  • 数组中未出现过元素nums[i]-1或nums[i]+1,意味着当前元素所在的连续序列就是自身(只有自己一个元素)。
    另外,注意去重即可
class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        nums_set = set(nums)
        dic = {}
        res = 0
        for num in nums_set:
            left = dic.get(num-1,0)
            right = dic.get(num+1,0)
            cur = left+right+1

            dic[num-left] = cur
            dic[num+right] = cur
            res = max(res,cur)
        return res
posted @ 2019-10-02 14:50  Jamest  阅读(141)  评论(0编辑  收藏  举报