哈希表
1. 两数之和
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
输入: nums = [2,7,11,15], target = 9
输出:[0,1]
解释: 因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
解题思路:
使用 hash 表来存放 key-元素值,value-元素下标
遍历数组,如果当前元素与 hash 表中的值恰好之和为 target,那么就成功了,否则将当前元素加入到 hash 表中。
func twoSum(nums []int, target int) []int {
m := make(map[int]int)
for i, num := range nums {
if idx, exists := m[target-num]; exists {
return []int{i, idx}
} else {
m[num] = i
}
}
return []int{}
}
15. 三数之和
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请
你返回所有和为 0
且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
输入: nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
解题思路:
排序,将数组排序成有序的
固定一个数,然后使用双指针遍历另外两个元素。
去重可以使用 hashmap,也可以使用比较当前元素与前一个元素值的方式。
注意点:
三数之和不要使用 hash 表的方法!!!hash 表的方法会很繁琐,记住就行,三数之和要使用 排序+双指针 的方法!!
得到一个结果之后两个指针需要分别向左,向右移动。这样可以防止出现死循环。
得到的数组最后必须要进行去重,为了防止出现重复的数组。
func threeSum(nums []int) [][]int {
res := make([][]int, 0)
history := make(map[string]struct{}) // 去重的 hashmap
// 排序
sort.Slice(nums, func(i, j int) bool {
return nums[i] < nums[j]
})
for i := 0; i <= len(nums)-3; i++ {
left := i + 1
right := len(nums) - 1
for left < right {
if nums[i]+nums[left]+nums[right] < 0 {
left++
} else if nums[i]+nums[left]+nums[right] > 0 {
right--
} else {
subNum := []int{nums[i], nums[left], nums[right]}
/** --------- bug 记录 ----------
没有去重,导致出现重复的三元组. 现在这里使用 hashmap 来进行去重
*/
s := encode(subNum)
if _, exists := history[s]; !exists {
history[s] = struct{}{}
res = append(res, subNum)
}
/** --------- bug 记录 -------------
刚开始 left++,right-- 没写,导致程序在这里死循环!
*/
left++
right--
}
}
}
return res
}
func encode(nums []int) string {
return fmt.Sprintf("%v", nums)
}
以下是去重版本2,没有使用 hashmap 进行去重,而是通过判断上一个元素是否与这一个元素相等来进行的去重。
在写这道题的过程中,出现了三处 bug:
-
没有去重代码
-
使用去重方法2的时候,应该开始新循环的地方没有写 continue,导致代码继续执行
-
得到结果的时候,left -- 和 right ++ 没有写,导致程序在这处死循环。
// 去重版本2
func threeSum_(nums []int) [][]int {
res := make([][]int, 0)
// 排序
sort.Slice(nums, func(i, j int) bool {
return nums[i] < nums[j]
})
for i := 0; i <= len(nums)-3; i++ {
// 第一个元素也需要被去重
if i > 0 && nums[i] == nums[i-1] {
continue
}
left := i + 1
right := len(nums) - 1
for left < right {
/** --------- bug 记录 ----------
没有去重,导致出现重复的三元组. 因为重复的原因在于遍历数组的时候,相邻元素可能相等,那么去重就可以跳过相邻的元素。
*/
// 左面, 右面相邻元素重复,需要跳过以达到去重的目的, 比如left > i + 1的目的是让left不是第一个元素,必须从第二个开始去重,rigth < len(nums)-1 同理
if left > i+1 && nums[left] == nums[left-1] {
left++
continue
/** ---- bug 记录 -----
刚开始没有写 continue,导致去重之后继续执行后序代码,与预期不相符合,所以说想要开始新循环的时候一定要写 continue,要养成习惯!!
*/
}
if right < len(nums)-1 && nums[right] == nums[right+1] {
right--
continue
}
if nums[i]+nums[left]+nums[right] < 0 {
left++
continue
} else if nums[i]+nums[left]+nums[right] > 0 {
right--
continue
} else {
subNum := []int{nums[i], nums[left], nums[right]}
res = append(res, subNum)
/** --------- bug 记录 -------------
刚开始 left++,right-- 没写,导致程序在这里死循环!
*/
left++
right--
}
}
}
return res
}
454. 四数相加 II
给你四个整数数组 nums1
、nums2
、nums3
和 nums4
,数组长度都是 n
,请你计算有多少个元组 (i, j, k, l)
能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
输入: nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出: 2
解释:
两个元组如下:
- (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
- (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
解题思路:
本题乍一看好像与三数之和相同,只不过由三个数变成了四个数,仔细一看发现不一样,三数之和是在一个数组中,所以使用固定一个数,移动另外两个数的方式。而这道题是在四个数组中,所以使用 hashmap 的方法,先计算两项和出现的次数,然后将两项和合并,计算总共出现的次数。
func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
// 先计算两项和, 再计算另外两项和, 然后再计算它俩的和
m1 := make(map[int]int) //两项和出现的次数
for i := 0; i < len(nums1); i++ {
for j := 0; j < len(nums2); j++ {
m1[nums1[i]+nums2[j]]++
}
}
m2 := make(map[int]int)
for i := 0; i < len(nums3); i++ {
for j := 0; j < len(nums4); j++ {
m2[nums3[i]+nums4[j]]++
}
}
count := 0
for sum1, count1 := range m1 {
for sum2, count2 := range m2 {
if sum2+sum1 == 0 {
count += count2 * count1
}
}
}
return count
}
标签:right,数组,nums,int,++,哈希,left
From: https://www.cnblogs.com/geraldkohn/p/17001731.html