[Leetcode]220. Contains Duplicate III
这是Leetcode第220题,给定一个整数数组,问是否存在两个数差距最多为,两数的间隔最大为。
很明显,这里需要用到一个大小为的窗口,每次判断窗口内是否存在每个数差值满足的条件。每一次都进行朴素的判断,需要用的时间复杂度,主体循环一次就是。则,我们优化的目标是,怎么在时间判断窗口内是否存在满足条件的数。
这里使用了hash Map的思路,更准确地讲,是桶排序的思想。将每个数映射到的key上,如果等于零,则是本身,每次判断和上面的数即可。具体代码如下:
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 最大间距
求一个无序数组排序后相邻数的差距的最小值,如果使用基于比较的排序绝对是 的。使用桶在这道题是有天然优势的,最大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 最长连续序列
给定一个未排序的整数数组,找出最长连续序列的长度。要求算法的时间复杂度为 。利用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
标签:
OJ
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)