题目链接: leetcode454-四数相加II,leetcode383-赎金信,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
}
赎金信
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
}