算法练习-第六天【哈希表】

哈希表(二)

454.四数相加 II

参考:代码随想录454.四数相加

思路

题目中给出了四个长度相同数组,并且要求求出组成结果为0的四元组。答案可以包含重复的四元组。

  1. 先使用哈希表 key存储数组1和数组2的2个数之和,value存储数组1和数组2的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.赎金信

参考:代码随想录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.三数之和

参考:代码随想录15.三数之和

看完题目的第一想法

使用双层for循环来解答,并且使用map来存放-(a+b)的值。
因为要对三元组去重,使用map来去重有些复杂,没有AC。暂时使用双指针解法来解开

进阶

首先对数组进行升序排序,使用双指针的方式来处理

  1. 可以将i理解成最左侧的指针,当nums[i]的值大于0时,不可能出现比0小的组合了
  2. 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.四数之和

参考:代码随想录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替代;同理在第二层循环中也可以进行剪枝操作。

posted @   neil_liu  阅读(118)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示