day07 四数相加II、 赎金信、三数之和、四数之和

题目链接: leetcode454-四数相加IIleetcode383-赎金信leetcode15-三数之和leetcode18-四数之和

四数相加II

Go

时间复杂度: O(n^2)
空间复杂度: O(n^2), 最坏的情况,nums1[i]+nums2[j]都不相同

func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
	m := make(map[int]int)
	res := 0

	// 存储map[nums1[i]+nums2[j]]
	for _, v1 := range nums1 {
		for _, v2 := range nums2 {
			m[v1+v2]++
		}
	}

	// 判断nums3[i]+nums4[j]的相反数是否在map中存在
	for _, v1 := range nums3 {
		for _, v2 := range nums4 {
			res += m[-v1-v2]
		}
	}

	return res
}

赎金信

leetcode-242有效的字母异位词相似

Go

时间复杂度: O(m+n), m和n分别代表两个字符串的长度
空间复杂度: O(S), S为字符集大小,这里为26

func canConstruct(ransomNote string, magazine string) bool {
	m := [26]int{}

	// 存储magazine中的字符
	for _, ch := range magazine {
		m[ch-'a']++
	}

	for _, ch := range ransomNote {
		if m[ch-'a'] == 0 {
			return false
		}
		m[ch-'a']--
	}

	return true
}

三数之和

Go

时间复杂度: O(n^2)
空间复杂度: O(n)

func threeSum(nums []int) [][]int {
	numsLen := len(nums)
	res := [][]int{}
	if numsLen < 3 {
		return res
	}

	// 对数组进行排序
	sort.Ints(nums)

	// 为什么是numsLen-2:因为所求的是三数之和,所以i
	for i := 0; i < numsLen-2; i++ {
		// nums[i]大于0,说明i之后的都大于0
		if nums[i] > 0 {
			break
		}

		// 	去重
		if i > 0 && nums[i] == nums[i-1] {
			continue
		}

		left := i + 1
		right := numsLen - 1

		for left < right {
			leftV, rightV := nums[left], nums[right]
			sum := nums[i] + leftV + rightV

			if sum < 0 {
				left++
			} else if sum > 0 {
				right--
			} else {
				res = append(res, []int{nums[i], leftV, rightV})

				// left, right去重复
				for left < right && nums[right] == rightV {
					right--
				}

				for left < right && nums[left] == leftV {
					left++
				}
			}

		}
	}

	return res
}

四数之和

Go

时间复杂度: O(n^3)
空间复杂度: O(n)

func fourSum(nums []int, target int) [][]int {
	numsLen := len(nums)
	res := [][]int{}
	if numsLen < 4 {
		return res
	}

	// 排序
	sort.Ints(nums)

	// 寻找符合要求的组合
	// nums[i]为第一个数字,nums[j]为第二个数字, nums[left]为第三个数字,nums[right]为第四个数字
	// 因为是四数之和,所有第一个数字至多也就只会在nums[len(nums)-3-1]的位置
	for i := 0; i < numsLen-3; i++ {

		// 当前数字已经大于了target,后面的数值肯定大于target
		if target > 0 && nums[i] > target {
			break
		}

		// 去重
		if i > 0 && nums[i] == nums[i-1] {
			continue
		}

		for j := i + 1; j < numsLen-2; j++ {
			// 剪枝
			// 注意不能直接return, 因为i与j之间的数值可能还存在满足要求的组合
			if target > 0 && nums[j] > target {
				break
			}

			// 去重
			if j > i+1 && nums[j] == nums[j-1] {
				continue
			}

			left := j + 1
			right := numsLen - 1

			for left < right {
				leftV, rightV := nums[left], nums[right]
				sum := nums[i] + nums[j] + leftV + rightV
				if sum > target {
					right--
				} else if sum < target {
					left++
				} else {
					res = append(res, []int{nums[i], nums[j], leftV, rightV})

					// left, right 去重复
					for left < right && nums[left] == leftV {
						left++
					}

					for left < right && nums[right] == rightV {
						right--
					}
				}
			}
		}

	}

	return res
}
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值