代码随想录算法训练营day07| 454.四数相加II 383.赎金信 15.三数之和 18.四数之和

454.四数相加II

哈希

先算前两数之和,再算后两数之和,再转化为两数之和的做法

时间复杂度O(n2)    空间复杂度O(n)

func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
	// 先暴力求出前两数和后两数之和,再哈希查找,时间复杂度O(n2),注意和相同问题
	sumList := make([]int, 0) // 存放前两数的和
	sumMap := make(map[int]int)  // 存放后两数和的哈希表
	result := 0  // 结果
	for _, n1 := range nums1 {
		for _, n2 := range nums2 {
			sumList = append(sumList, n1+n2)
		}	
	}
	for _, n3 := range nums3 {
		for _, n4 := range nums4 {
			sumMap[n3 + n4]++
		}
	}
	for _, n := range sumList{
		result += sumMap[-n]
	}
	return result
}

383.赎金信

数组

使用数组来存放字母出现的频率

时间复杂度O(n)   空间复杂度O(1)

func canConstruct(ransomNote string, magazine string) bool {
	// 法一:数组存储字母出现频率,后者频率大于前者即为true
	charList := [26]int{}  // 26个字母
	for _, char := range magazine{
		charList[char - 'a']++
	}
	for _, char := range ransomNote{
		charList[char - 'a']--
		if charList[char - 'a'] < 0 {
			return false
		}
	}
	return true
}

哈希

将出现的字符的频率用哈希表存起来,解决任意字符的问题

func canConstruct(ransomNote string, magazine string) bool {
	// 法二:将出现的字符频率用哈希表存起来,解决任意字符的问题
	charMap := map[rune]int{}
	for _, r := range magazine {
		charMap[r]++
	}	
	for _, r := range ransomNote {
		charMap[r]--
		if charMap[r] < 0 {
			return false
		}
	}
	return true
}

15.三数之和

遍历+哈希

先遍历数组,将数字出现的频率用map存起来,再遍历两数之和,判断第三个数是否存在(实现方式多了很多重复的判断,故有些慢)

时间复杂度 O(n2)    空间复杂度 O(n)

func threeSum(nums []int) [][]int {
	// 先遍历数组,将元素出现次数存入哈希表中
	countMap := make(map[int]int)      // 记录元素出现次数
	resultMap := make(map[[3]int]bool) // 存放是否出现过
	result := make([][]int, 0)
	for _, num := range nums {
		countMap[num]++
	}
	for i := 0; i < len(nums)-2; i++ {
		for j := i + 1; j < len(nums)-1; j++ {
			// 判断元素
			target := -nums[i] - nums[j]
			tempArr := [3]int{nums[i], nums[j], target}
			for ii := 0; ii < 3; ii++ {
				for kk := 0; kk < 3-ii-1; kk++ {
					if tempArr[kk] > tempArr[kk+1] {
						tempArr[kk], tempArr[kk+1] = tempArr[kk+1], tempArr[kk]
					}
				}
			}
			countMap[nums[i]]--
			countMap[nums[j]]--
			if countMap[target] > 0 && resultMap[tempArr] == false {
				resultMap[tempArr] = true
				result = append(result, []int{tempArr[0], tempArr[1], tempArr[2]})
			}
			countMap[nums[i]]++
			countMap[nums[j]]++
		}
	}
	return result
}

排序+哈希

先进行排序,再处理,可以节省一些遍历。因为排序之后第三个数只能出现在右侧,且代码上容易写判断逻辑

时间复杂度 O(n2)           空间复杂度 O(n) 

func threeSum(nums []int) [][]int {
	// 先排序,减少不必要的遍历
	sort.Slice(nums, func(i, j int) bool {
		return nums[i] < nums[j]  // 从小到大排序
	})
	countMap := make(map[int]int) // 记录该数字是否存在,且索引值在哪
	for index, num := range nums {
		countMap[num] = index
	}
	result := make([][]int, 0)
	isAppear := make(map[[3]int]bool)  // 记录是否已经出现过
	for i := 0; i < len(nums) - 2; i++ {
		for j := i + 1; j < len(nums) - 1; j++ {
			target := -nums[i] - nums[j]
			if countMap[target] > j {
				if _, ok := isAppear[[3]int{nums[i], nums[j], target}]; !ok {
					isAppear[[3]int{nums[i], nums[j], target}] = true
					result = append(result, []int{nums[i], nums[j], target})
				}
			}
		}
	}
	return result
}

18.四数之和

排序+哈希

和上面一题相同的解法,多套了一层for循环

时间复杂度 O(n3)  空间复杂度O(n)

func fourSum(nums []int, target int) [][]int {
	// 同样先排序,再遍历三个数
	sort.Slice(nums, func(i, j int) bool {
		return nums[i] < nums[j]  // 升序
	})
	indexMap := make(map[int]int)  // 存放某个数字最后出现时的索引
	isAppear := make(map[[4]int]bool)
	result := make([][]int, 0)
	for index, val := range nums {
		indexMap[val] = index
	}
	for i := 0; i < len(nums) - 3; i++ {
		for j := i + 1; j < len(nums) - 2; j++ {
			for k := j + 1; k < len(nums) - 1; k++ {
				fourNum := target - nums[i] - nums[j] - nums[k]
				if indexMap[fourNum] > k{
					if _, ok := isAppear[[...]int{nums[i], nums[j], nums[k], fourNum}]; !ok{
						isAppear[[...]int{nums[i], nums[j], nums[k], fourNum}] = true
						result = append(result, []int{nums[i], nums[j], nums[k], fourNum})
					}
				}	
			}
		}
	}
	return result
}

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值