[英雄星球六月集训LeetCode解题日报] 第七日 哈希表
一、 442. 数组中重复的数据
链接: 442. 数组中重复的数据
1. 题目描述
给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次 。请你找出所有出现 两次 的整数,并以数组形式返回。
你必须设计并实现一个时间复杂度为 O(n) 且仅使用常量额外空间的算法解决此问题。
2. 思路分析
其实哈希计数很简单,但是题目要求空间复杂度O(1)。
因此可以原地哈希,把每个数放到对应的位置:
每次操作把本位置的数换出去,如果换进来的数不对,继续换出去。
这样每次都能至少让一个数在正确位置。
3. 代码实现
class Solution:
def findDuplicates(self, nums: List[int]) -> List[int]:
n = len(nums)
for i in range(n):
while nums[i] != nums[nums[i] - 1] :
nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
return [nums[i] for i in range(n) if nums[i]-1 != i]
二、 2068. 检查两个字符串是否几乎相等
1. 题目描述
如果两个字符串 word1 和 word2 中从 ‘a’ 到 ‘z’ 每一个字母出现频率之差都 不超过 3 ,那么我们称这两个字符串 word1 和 word2 几乎相等 。
给你两个长度都为 n 的字符串 word1 和 word2 ,如果 word1 和 word2 几乎相等 ,请你返回 true ,否则返回 false 。
一个字母 x 的出现 频率 指的是它在字符串中出现的次数。
2. 思路分析
计数比较就行。
3. 代码实现
class Solution:
def checkAlmostEquivalent(self, word1: str, word2: str) -> bool:
c1,c2 = Counter(word1),Counter(word2)
for c,v in c1.items():
if abs(v-c2.get(c,0)) >3:
return False
for c,v in c2.items():
if abs(v-c1.get(c,0)) >3:
return False
return True
三、 2283. 判断一个数的数字计数是否等于数位的值
1. 题目描述
给你一个下标从 0 开始长度为 n 的字符串 num ,它只包含数字。
如果对于 每个 0 <= i < n 的下标 i ,都满足数位 i 在 num 中出现了 num[i]次,那么请你返回 true ,否则返回 false 。
2. 思路分析
这题主要是类型转换要注意。
3. 代码实现
class Solution:
def digitCount(self, num: str) -> bool:
cnt = Counter(num)
# 注意类型转换
return all(int(num[i]) == cnt.get(str(i), 0) for i in range(len(num)))
四、884. 两句话中的不常见单词
链接: 884. 两句话中的不常见单词
1. 题目描述
句子 是一串由空格分隔的单词。每个 单词 仅由小写字母组成。
如果某个单词在其中一个句子中恰好出现一次,在另一个句子中却 没有出现 ,那么这个单词就是 不常见的 。
给你两个 句子 s1 和 s2 ,返回所有 不常用单词 的列表。返回列表中单词可以按 任意顺序 组织。
2. 思路分析
直接在两个一起计数,找频次1的。
3. 代码实现
class Solution:
def uncommonFromSentences(self, s1: str, s2: str) -> List[str]:
return [x for x,v in Counter(s1.split(' ') + s2.split(' ')).items() if v == 1]
五、附每日一题 875. 爱吃香蕉的珂珂
链接: 875. 爱吃香蕉的珂珂
1. 题目描述
珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。
珂珂可以决定她吃香蕉的速度 k (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。
珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。
返回她可以在 h 小时内吃掉所有香蕉的最小速度 k(k 为整数)。
2. 思路分析
速度快了就会时间短,速度慢了就时间长,要求时间不能超过h。因此可以二分。
二分上下界:[1,max(piles)]。
python的bisect参数要好好理解。
只能升序搜,key参数是指原数组每个数经过key计算后,第一个不大于 指定数据(-h)的数。
这里因为k和计算式的结果大小是相反的,所以加负号。
返回值是下标,因此range从0开始,这样可以让下标=值,但搜索下限指定为1。
3. 代码实现
# class Solution:
# def minEatingSpeed(self, piles: List[int], h: int) -> int:
# a = range(1,+1)
# ans = max(piles)+1
# l,r = 1, ans
# m = (l+r) // 2
# while l<r:
# m = (l+r) // 2
# s = sum([ceil(x/m) for x in piles])
# # print(l,r,m,s,h)
# # if s == h:
# # return m
# if s > h:
# l = m+1
# elif s <= h:
# ans = min(ans,m)
# r = m
# return ans
class Solution:
def minEatingSpeed(self, piles: List[int], h: int) -> int:
return bisect_left(range(0,max(piles)+1), -h, lo=1, key=lambda k: -sum([ceil(x/k) for x in piles]))