算法练习-第六天【哈希表】
哈希表(二)
454.四数相加 II
思路
题目中给出了四个长度相同数组,并且要求求出组成结果为0的四元组。答案可以包含重复的四元组。
- 先使用哈希表 key存储数组1和数组2的2个数之和,value存储数组1和数组2的2个数之和出现的次数
- 遍历数组3和数组4在哈希表中找到key为
-(num3+num4)
,如果可以在哈希表中找到,那么就在返回结果上加上value次。
func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
m := map[int]int{}
for _, num1 := range nums1 {
for _, num2 := range nums2 {
m[num1+num2]++
}
}
rlt := 0
for _, num3 := range nums3 {
for _, num4 := range nums4 {
rlt += m[-num3-num4]
}
}
return rlt
}
本题总结
很容易的一道题,使用哈希表可以显著的降低时间复杂度。
383.赎金信
看完题目的第一想法
题目判断第一个字符串ransomNote
能否由magazine
构成。而且组成的字符只能使用一次。
func canConstruct(ransomNote string, magazine string) bool {
m := make(map[rune]int)
for _, ch := range magazine {
m[ch]++
}
for _, ch := range ransomNote {
m[ch]--
if v, ok := m[ch]; ok && v < 0 {
return false
}
}
return true
}
优化
func canConstruct(ransomNote string, magazine string) bool {
record := [26]int{}
for _, ch := range magazine {
record[ch-'a']++
}
for _, ch := range ransomNote {
record[ch-'a']--
if record[ch-'a'] < 0 {
return false
}
}
return true
}
本题总结
与242.有效的字母异位词类似的一道题,做起来没有什么难度。可以使用数组代替哈希表。
15.三数之和
看完题目的第一想法
使用双层for循环来解答,并且使用map来存放-(a+b)
的值。
因为要对三元组去重,使用map来去重有些复杂,没有AC。暂时使用双指针解法来解开
进阶
首先对数组进行升序排序,使用双指针的方式来处理
- 可以将
i
理解成最左侧的指针,当nums[i]
的值大于0时,不可能出现比0小的组合了 - 当
nums[i]==nums[i-1]
时,说明此时的i
在前一位处理过;之所以不判断nums[i]==nums[i+1]
因为left指针指向i+1
的位置也是一个合法的三元组,比如(-1,-1,2)。
func threeSum(nums []int) [][]int {
sort.Ints(nums)
rlt := [][]int{}
for i := range nums {
if nums[i] > 0 {
break
}
if i > 0 && nums[i] == nums[i-1] {
continue
}
left, right := i+1, len(nums)-1
for left < right {
sum := nums[i] + nums[left] + nums[right]
if sum < 0 {
left++
} else if sum > 0 {
right--
} else {
rlt = append(rlt, []int{nums[i], nums[left], nums[right]})
for left < right && nums[left] == nums[left+1] {
left++
}
for left < right && nums[right] == nums[right-1] {
right--
}
left++
right--
}
}
}
return rlt
}
今日总结
最先使用的哈希表的方式来解答, 一直没有AC,最后使用了双指针的方式。
18.四数之和
看完题目的第一想法
有了三数之和的经验,直接双指针开搞;
func fourSum(nums []int, target int) [][]int {
rlt := [][]int{}
sort.Ints(nums)
n := len(nums)
for i := 0; i < n; i++ {
if i > 0 && nums[i] == nums[i-1] {
continue
}
for j := i + 1; j < n; j++ {
if j > i+1 && nums[j] == nums[j-1] {
continue
}
left, right := j+1, n-1
for left < right {
sum := nums[i] + nums[j] + nums[left] + nums[right]
if sum < target {
left++
} else if sum > target {
right--
} else {
rlt = append(rlt, []int{nums[i], nums[j], nums[left], nums[right]})
for left < right && nums[left] == nums[left+1] {
left++
}
for left < right && nums[right] == nums[right-1] {
right--
}
left++
right--
}
}
}
}
return rlt
}
进阶
在for循环中进行剪枝操作
func fourSum(nums []int, target int) [][]int {
rlt := [][]int{}
sort.Ints(nums)
n := len(nums)
for i := 0; i < n; i++ {
// 剪枝
if nums[i] >= 0 && nums[i] > target {
break
}
if i > 0 && nums[i] == nums[i-1] {
continue
}
for j := i + 1; j < n; j++ {
// 剪枝
if nums[i]+nums[j] >= 0 && nums[i]+nums[j] > target {
break
}
if j > i+1 && nums[j] == nums[j-1] {
continue
}
left, right := j+1, n-1
for left < right {
sum := nums[i] + nums[j] + nums[left] + nums[right]
if sum < target {
left++
} else if sum > target {
right--
} else {
rlt = append(rlt, []int{nums[i], nums[j], nums[left], nums[right]})
for left < right && nums[left] == nums[left+1] {
left++
}
for left < right && nums[right] == nums[right-1] {
right--
}
left++
right--
}
}
}
}
return rlt
}
今日总结
四数之和与三数之和唯一的区别就是给定了target,因此if nums[i] > 0{ break }
的剪枝操作需要更改,使用if nums[i]>=0 && nums[i] >target
替代;同理在第二层循环中也可以进行剪枝操作。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构