梦开始的地方
解法:哈希表!!!其他自行领悟
之前第一眼看到题目,想到的做法是dfs + KMP。其中,dfs用来遍历所有可能的单词组合,而KMP用来字符串匹配,但是最终超时了!!!
解法一:朴素哈希表
- 首先定义一个哈希表统计给定
words
中单词出现的频次- 其次从
0
开始枚举给定字符串s
,从中取得words.size() * words[0].size()
长度的子串- 再次定义一个哈希表统计子串中单词出现的频次
- 最后比较两个哈希表
解法二:哈希表 + 滑动窗口
我们发现,枚举起点的过程可以优化!优化方法就是滑动窗口。
- 滑动窗口起点的划分方法有
words[0].size()
种,即 0 , 1 , ⋯ , w o r d s [ 0 ] . s i z e ( ) − 1 0,1,\cdots,words[0].size() - 1 0,1,⋯,words[0].size()−1。这是因为窗口在不断滑动,以 0 0 0
为起点的滑动窗口会包含以 w o r d s [ 0 ] . s i z e ( ) words[0].size() words[0].size()为起点的滑动窗口。- 和之前一样,我们定义一个哈希表统计给定
words
中单词出现的频次- 针对于不同的滑动窗口起点,我们同样定义一个哈希表统计滑动窗口中单词的频次。当窗口滑动的时候,删除滑出窗口单词的频数,增加滑入窗口单词的频数,最后比较两个哈希表是否相同。
- 滑动窗口的一个注意事项是:只有当滑动窗口中的字符数满足
words.size() * words[0].size()
时,才可以删除滑出窗口单词频数。
用哈希表解这道题目是有点慢,用数组解决更合适一些。关于思路,题目给得很清楚,题解说得也很清楚
之前的思考思路
- 利用哈希表
unordered_map<char,int>
记录每一个单词中字母出现的次数,- 利用
set<unordered_map<char,int>>
来判断是否是其他单词的字母异位词- 但是我没有解决该单词是哪一组单词的字母异位词。
- 之后又想的是利用
unordered_map<char,int>
作为unordered_map
的键值,即unordered_map<unordered_map<char,int>,vector<string>>
,但是标准库中并未提供相应的哈希函数,而我自己懒得定义,因此作罢。
看了y总的代码后
他的思路是对利用字母的ASALL码值对每一个单词进行排序,这样字母异位词的排序结果都是相同的。比如"abc
"和“bac
”,排序后的结果是"abc"
和"abc"
,这样我们可以利用排序后的字符串作为键值,vector<string>
作为实值,进而定义了一个哈希表unordered_map<string,vector<string>>
。
数据结构:哈希表 在C ++ STL中,有四种哈希表形式,这里我们使用的是
unordered_set
具体步骤如下:
- 遍历数组,将所有元素加入哈希表中
- 枚举哈希表中的元素。假设当前元素
x
是最长连续序列的起点,在哈希表中查找是否存在 x + 1 , x + 2 , ⋯ , x + n x+1,x+2,\cdots,x+n x+1,x+2,⋯,x+n- 由于枚举的点实际上并不是最长连续序列的起点,所以上述过程会出现重复枚举的情况。因此我们需要判断枚举的点 x x x是否是最长连续序列的起点,即判断 x − 1 x- 1 x−1是否出现在哈希表中。如果是,则跳过本轮循环,否则在哈希表中查找是否存在 x + 1 , x + 2 , ⋯ , x + n x+1,x+2,\cdots,x+n x+1,x+2,⋯,x+n,并记录最长连续序列的长度。
思路和算法:
- 哈希表
- 排序
方法一:
哈希表。用哈希表
unordered_map
记录数组中出现的元素及其最大索引。在数组元素加入哈希表之前,先判断哈希表中是否出现过该元素?如果哈希表中有该元素,那么索引差值是否符合要求?方法二:
滑动窗口 + 哈希表。哈希表中存储滑动窗口内的元素,对于数组中的每一个元素,先在哈希表中查找该元素。若有元素移出滑动窗口,及时在哈希表中删除它。
小tips:滑动窗口是一种特殊的双指针算法,由于滑动窗口长度固定,因此可以只用一根指针实现滑动窗口。
- 排序。
- 异或。先预处理出[0,n]这个区间内所有数字的异或,然后再与给定数组的各个元素相异或,最后的异或结果即是确实的数字。
- 原地哈希。和LeetCode第41题的做法相同。
思路和算法:双哈希表映射。
这道题目的本质就是建立小写字母和字符串的双向映射关系。此外,还需要对这样的情况进行判断:若
pattern
未遍历完,但字符串s
已遍历完,那么返回false
。
这是一道典型的哈希表应用题。
思路和算法如下:
- 遍历字符串
secret
,用哈希表记录相应的字母及其出现的次数- 遍历字符串
secret
和guess
,统计bull
的个数,并把哈希表中相应字母出现的次数减1
,如果减到0
,则从哈希表中删除它。- 遍历字符串
secret
和guess
,统计cow
的个数,统计方法是判断哈希表中是否存在guess[i]
,并把哈希表中guess[i]
出现的次数减1
,如果减到0
,则从哈希表中删除它。
设题目中提供的点的个数是 n n n,点 i i i和点 j j j是任意两个不相同的点。
根据题意,为了解决问题,需要获得两个信息:
- 点
i
i
i与点
j
j
j的欧式距离
distance
( 1 ≤ i ≤ n , 1 ≤ j ≤ n , i ≠ j 1 \le i \le n, 1 \le j \le n,i \neq j 1≤i≤n,1≤j≤n,i=j) - 对于点
i
i
i,与其相距
distance
的点的个数。
设与点
i
i
i相距distance
的点的个数是m
,对于点i
及与其相距distance
的所有点中,能组成
m
×
(
m
−
1
)
m \times (m - 1)
m×(m−1)个回旋镖。
遍历每个点及每个点所有的欧式距离,根据上述公式计算回旋镖的数量并累加,最后所得结果即是答案。
451. 根据字符出现频率排序
看到字符频率,应当有一种联想到哈希表的直觉。
这道题目的思路如下:用哈希表统计字符出现的频率,然后把【频率,字符】键值对加入到优先队列当中,最后从优先队列当中弹出元素,构造答案。
或者也可以这样来做;
- 用哈希表统计字符出现的频率
- 遍历哈希表,找到出现频次最高的元素,
- 构造答案,并从哈希表中删掉当前频次最高的元素
- 重复上述步骤$2-4 $,直到哈希表为空
原以为是双重循环 + 双指针,没想到这道题目使用哈希表解决。不过想想也对,因为题目只要求索引唯一,不要求相加的四个数字唯一,哈希表确实是最简单的方法。
思路很简单,其基本思想是用哈希表存储下前两个数组的和及出现次数,再遍历后两个数组,以后两个数组中任意两个元素的和的负值为键值查找哈希表中是否存在该元素,如果存在,把该键值出现的次数加到答案中。
原地哈希
41.缺失的第一个正整数
方法:
- 哈希表,不过空间复杂度不是常数级别
- 原地哈希,这里有具体解释
442.数组中重复的数据
方法:原地哈希。
应用:数据长度是 n n n,且数组中元素的数据范围位于 [ 1 , n ] [1,n] [1,n] 或其他可以双射到 [ 1 , n ] [1,n] [1,n]上的数据集,要求时间复杂度是 O ( n ) O(n) O(n)以及使用额外常数空间。
若数据范围位于
[
1
,
n
]
[1,n]
[1,n],原地哈希的基本思想是尝试把把数据i
放在nums[i - 1]
的位置(举个例子,把1
放在nums[0]
处,把5
放在nums[4]
处)。
在本题中,因为数据重复出现,所以当nums[i] != i + 1 && nums[nums[i] - 1] == nums[i]
,说明nums[i]
一定是重复出现的数字。