1、两数之和
思路
使用map,【键】:元素值 【值】:下标
遍历原值,找对应的值是否存在于map中
若存在,返回两者下标
若不存在,将当前值与下标存入map
代码(Go)
func twoSum(nums []int, target int) []int {
m := make(map[int]int) // 创建一个 map,存储已经遍历过的数值及其索引
for index, val := range nums {
if preindex, ok := m[target-val]; ok { // 查找 map 中键为 target-val 的值是否存在
return []int{index, preindex} // 找到匹配的索引对,返回
} else {
m[val] = index // 如果没有匹配的,存入 map
}
}
return []int{} // 没找到,返回空切片
}
// map中的存储结构为 {key:数据元素,value:数组元素对应的下标}
2、字母异位词分组
(1)计数法
思路
由于字母异位词的字符串包含相同的字母,且每个字母的出现次数相同,可以用一个数组
来记录每个字母的出现次数
。
例如,字符串 “eat” 和 “tea”,字母出现次数是相同的:{e: 1, a: 1, t: 1}。
这样我们可以用一个固定大小的数组(长度为 26,表示字母 ‘a’ 到 ‘z’)作为哈希表的键。
实现
1,遍历每个字符串,创建一个大小为 26 的数组,用来记录每个字母的出现次数。
2,用该数组
作为哈希表的键
,把原字符串添加到对应的键下。
3,最后遍历哈希表,得到所有的字母异位词组。
代码(Go)
// 计数法
func groupAnagrams(strs []string) [][]string {
mp := map[[26]int][]string{} // {}表示初始化一个空的map mp:将字母异位词分组的临时数据结构
for _, str := range strs {
cnt := [26]int{} // 即mp的键
for _, b := range str {
cnt[b-'a']++
}
mp[cnt] = append(mp[cnt], str) // 更新map中cnt键对应的值(字符串切片)
}
ans := make([][]string, 0, len(mp)) // [][]string相当于c的string[][] len(mp) 是总的字母异位词组数
for _, v := range mp { // 返回键、值
ans = append(ans, v)
}
return ans
}
(2)排序法
思路
字母异位词的字符串可以通过排序变成一样的字符串。比如 “eat” 和 “tea” 排序后都是 “aet”。
因此,可以将每个字符串排序后
作为键(key)来存储在哈希表
中。所有排序后相同的字符串,属于同一个字母异位词组。
实现
1,遍历字符串数组,将每个字符串转换成排序后的字符串。
2,使用排序后的字符串
作为哈希表的键
,把原字符串添加到对应的键下。
3,最后遍历哈希表,得到所有的字母异位词组。
代码(Go)
// 排序法
func groupAnagrams(strs []string) [][]string {
mp := make(map[string][]string) // 创建一个哈希表,键是排序后的字符串,值是字母异位词组
for _, str := range strs {
s := []byte(str) // 将字符串转为字节【切片】,是复合类型
sort.Slice(s, func(i, j int) bool { // 对字节切片进行排序
return s[i] < s[j] //这个规定的其实就是,大的在前还是小的在前
})
sortedStr := string(s) // 将排序后的字节切片转换回字符串
mp[sortedStr] = append(mp[sortedStr], str) // 将原字符串加入到对应的字母异位词组
}
ans := make([][]string, 0, len(mp))
for _, v := range mp {
ans = append(ans, v)
}
return ans
}
(3)比较
方法一(排序法):通过排序字符串作为哈希表的键。每个字符串的排序时间复杂度是 O(k log k),因此总时间复杂度是 O(n * k log k)。
方法二(计数法)【性能更好】:通过记录字母出现次数的数组作为哈希表的键。每个字符串的处理时间是 O(k),因此总时间复杂度是 O(n * k)。
3、最长连续序列
思路
题目要求找到数组中的 最长连续子序列
给定数组没有排序,且可能包含重复的元素,需要去重
可以用哈希表来查找数字是否存在
【哈希表自动去重
,因为它的键是唯一
的,不会存储重复的数字】
实现
1,哈希表存储: 将数组中的每个数字存入一个哈希表 numSet,以便能够快速查找每个数字是否存在。
2,遍历数组: 对于每个数字,检查它是否是一个潜在的连续序列的起点
。即它的前一个数字 num-1 不存在于哈希表中。如果是起点,就从该数字开始,继续查找连续的数字。
3,更新最长子序列: 每次找到一个连续子序列时,更新当前找到的最长子序列的长度。
代码(Go)
func longestConsecutive(nums []int) int {
numSet := map[int]bool{} // 创建一个哈希表 numSet,用来存储数组中的所有数字,键是数字,值是 bool 类型,用来标记数字是否存在
for _, num := range nums { // 遍历 nums 数组,将每个数字存入哈希表 numSet
numSet[num] = true // 由于哈希表的键是唯一的,重复的数字会自动去重
}
maxLen := 0
for num := range numSet { // 通过 range 获取哈希表中的每个键(即数字)
if !numSet[num-1] { // 只有 num-1 不存在,才是连续序列的起点
currentNum := num // 从当前 num 开始,向上查找连续的数字
currentMax := 1 // 初始化当前连续序列的长度为 1(包含当前的 num)
for numSet[currentNum+1] { // 相当于while, 为 true 时,说明当前数字的下一个数字存在
currentNum++ // 递增,继续查找下一个数字
currentMax++
}
if currentMax > maxLen { // 如果找到的连续子序列长度大于当前最长的长度,则更新最长长度
maxLen = currentMax
}
}
}
return maxLen
}