解题思路
使用双指针加固定循环的方法。
- 首先对数组进行排序,这样可以方便后续的双指针操作。
在处理排序后的数组时,可能会存在重复的元素,如果不进行特殊处理,会导致在结果中出现重复的四元组。因此,我们需要在固定两个数时对重复的元素进行skip,确保最终结果中的四元组不会重复。,当当前的i大于0(即i已经不是数组的第一个元素),并且当前的nums[i]等于前一个元素nums[i-1]时,我们就可以认定当前的nums[i]和前一个元素重复了,此时我们应该跳过当前元素,以避免在后续的计算中出现重复的情况。j的循环也一样的判断。
- 接下来使用两层循环固定两个数,然后在剩余的部分中使用双指针找到另外两个数。
- 对于left和right的初始化,则直接从j的后一个位置开始和数组末尾开始。
- 在固定两个数的循环内,使用双指针分别指向已固定数的右边第一个元素和数组最后一个元素。
- 计算四个数的和,并比较与目标值的大小关系:
如果和等于目标值,则将四个数加入结果列表中,并且移动左右指针,寻找下一个可能的解。 如果和小于目标值,将左指针右移一位。
如果和大于目标值,将右指针左移一位。
- 在处理完当前固定的两个数后,需要进行去重操作,避免出现重复解。
- 在整个循环过程中,注意跳过重复的元素,以及边界条件的判断,确保得到正确的结果。
两层循环固定两个元素,然后再使用双指针寻找另外两个元素。在这种情况下,我们需要合理确定循环的边界,以避免重复计算和不必要的遍历。
考虑到四个数的组合,
我们需要保证i、j、left、right分别表示四个不同的元素位置,因此需要限定循环的范围,以避免重复选择相同位置的元素。
对于i的循环条件,我们需要确保i所指向的位置后面至少还有3个元素,以保证在循环中可以找到i后面的三个元素。
对于j的循环条件,同样需要确保它所指向的位置后面至少还有2个元素。
// fourSum1 函数寻找一个整数数组中所有和为 target 的四元组。
//
// 参数:
// nums: 一个整数数组。
// target: 目标和。
//
// 返回值:
// 返回一个二维整数数组,每个子数组都是一个和为 target 的四元组。
// 如果没有找到满足条件的四元组,则返回空数组。
func fourSum1(nums []int, target int) [][]int {
// 当数组长度小于4时,直接返回nil,因为无法形成四元组
if len(nums) < 4 {
return nil
}
var res [][]int
// 对数组进行排序,以便后续使用双指针法
sort.Ints(nums)
// 遍历数组,作为四元组的第一个数字
for i := 0; i < len(nums)-3; i++ {
n1 := nums[i]
// 跳过重复的数字,以避免产生重复的四元组
if i > 0 && nums[i] == nums[i-1] {
continue
}
// 在当前第一个数字之后的范围内,遍历作为四元组的第二个数字
for j := i + 1; j < len(nums)-2; j++ {
n2 := nums[j]
// 跳过重复的数字,以避免产生重复的四元组
if j > i+1 && nums[j] == nums[j-1] {
continue
}
// 使用双指针法查找剩余两个数字
left, right := j+1, len(nums)-1
for left < right {
n3 := nums[left]
n4 := nums[right]
sum := n1 + n2 + n3 + n4
// 如果找到匹配的四元组,将其添加到结果中,并跳过相同数字
if sum == target {
res = append(res, []int{n1, n2, n3, n4})
for left < right && n3 == nums[left+1] {
left++
}
for left < right && n4 == nums[right-1] {
right--
}
left++
right--
} else if sum < target {
// 如果和小于目标值,将左指针向右移动
left++
} else {
// 如果和大于目标值,将右指针向左移动
right--
}
}
}
}
return res
}