算法:
这类题目是二分法的典型题目,核心点就是实现二数之和,三数之和,四数之和,多数之和都属于这类题目的变形题目。本文章统一整理了一个套路,多数之后最终转化为二数之和,通过递归来获取结果。基本步骤如下:
1.先将无序的数组排序。
2.按照典型的二数之和算法求解两数之和。
3.将多数之和,采用递归的方式最终用两数之和计算结果。
题目1: 两数之和
https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/
代码实现:
func twoSum(numbers []int, target int) []int {
l := len(numbers)
if l == 0 {
return nil
}
start, end:= 0, l-1
var tar []int
for start < end {
sum := numbers[start] + numbers[end]
if sum == target {
tar = append(tar,start+1)
tar = append(tar,end+1)
return tar
} else if sum > target {
end --
} else {
start++
}
}
return tar
}
执行结果:
题目2:三数之和
https://leetcode-cn.com/problems/3sum/
代码实现:
func threeSum(nums []int) [][]int {
sort.Ints(nums)
res := [][]int{}
for i:=0;i<len(nums);i++{
arr := nums[i+1:]
r := twoSum(arr,0-nums[i])
if r!=nil {
for _,v:=range r {
tmp := []int{nums[i]}
tmp = append(tmp,v...)
res = append(res,tmp)
}
}
for i+1 < len(nums)-1 && nums[i]==nums[i+1] {
i++
}
}
return res
}
func twoSum(nums []int, sum int) (res [][]int) {
i,j:=0,len(nums)-1
for i<j {
if nums[i]+nums[j]<sum {
i++
} else if nums[i]+nums[j]>sum {
j--
} else {
tmp := []int{nums[i], nums[j]}
res = append(res, tmp)
for i+1<j && nums[i+1] == nums[i] {
i++
}
for j-1>i && nums[j-1] == nums[j] {
j--
}
i++
j--
}
}
return
}
执行结果:
题目3:四数之和
https://leetcode-cn.com/problems/4sum/
代码实现:
func fourSum(nums []int, target int) [][]int {
var res [][]int
if len(nums) < 4 {
return res
}
sort.Ints(nums) // 排序
res = findNSum(nums, target, 4)
return res
}
func findNSum(nums []int, target int, n int) [][]int {
var res [][]int
// 当nums不足2个数时,返回空的res
if len(nums) < 2 || n < 2 {
return res
}
i,j := 0,len(nums)-1
if n == 2 {
for i < j {
sum := nums[i] + nums[j]
if sum < target {
i++
} else if sum > target {
j--
} else {
tmp := []int{nums[i], nums[j]}
res = append(res, tmp)
// 这后面是为了去除重复数据,
// 例如,a,a,a,a,b,后面的a+b其实已经重复了,所以只需要偏移,
// 不需要再次添加到res集合中。
for i + 1 < j && nums[i+1] == nums[i] {
i++
}
for j - 1 > i && nums[j-1] == nums[j] {
j--
}
// 进一步缩小数组的范围,看还存不存在另外一种组合相同
i++
j--
}
}
} else {
// 当n > 2时,遍历数组每一个元素,求基于当前数的 n - 1个数之和的全集
for i := 0; i < len(nums) - 1; i++ {
arr := nums[i+1:]
// 数组为去除当前元素,target为减去当前值,n需要减1
resTmp := findNSum(arr, target-nums[i], n-1)
// 当找到resTmp结果时,加入结果集
if len(resTmp) != 0 {
for _, v := range resTmp {
tmp := []int{nums[i]}
tmp = append(tmp, v...) // 合并当前数和除去该数之后的其他数集合
res = append(res, tmp) // 存入单次计算结果
}
}
// 去除重复数据,相同数字只算一次,例如 [a,a,a,a,b]跳过重复的a到b
for i + 1 < len(nums) - 1 && nums[i+1] == nums[i] {
i++
}
}
}
return res
}
执行结果: