1. 程式人生 > 其它 >四數之和

四數之和

給定一個包含 n 個整數的陣列 nums 和一個目標值 target,判斷 nums 中是否存在四個元素 a,b,c 和 d ,使得 a + b + c + d 的值與 target 相等?找出所有滿足條件且不重複的四元組。

注意:答案中不可以包含重複的四元組。

示例 1:

輸入:nums = [1,0,-1,0,-2,2], target = 0
輸出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2:

輸入:nums = [], target = 0
輸出:[]

提示:

0 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/4sum

解題思路

做過之前的三數之和,感覺這一道題就是在三數之和上面新增一層迴圈就可以了----先排序,最後兩層雙指標。但是提交的時候遇到一些問題了。

錯誤程式碼一

func fourSum(nums []int, target int) [][]int {

	if len(nums) < 4 {
		return nil
	}
	sort.Ints(nums)
	result := make([][]int,0)
	for i:=0;i<len(nums);i++{
        // 第一層迴圈
		tmp := threeSum(nums[i],nums[i+1:],target-nums[i])
		result = append(result,tmp...)
	}
	return result
}


func threeSum(val int,nums []int,target int) [][]int {

	result := make([][]int,0)
	for i:=0;i<len(nums);i++{
		x,y := i+1,len(nums)-1
		tmp := target - nums[i]
		for x < y {
			// 這裡直接是為了去重
			for x <= len(nums)-2 && nums[x] == nums[x+1]{
				x++
				continue
			}
			for y > x && nums[y] == nums[y-1] {
				y--
				continue
			}
			if nums[x] + nums[y] == tmp {
				arr := []int{val,nums[i],nums[x],nums[y]}
				result = append(result,arr)
				x++
				y--
			}else if nums[x] + nums[y] > tmp {
				y--
			}else if nums[x] + nums[y] < tmp {
				x++
			}
		}
	}
	return result
}

用例:nums := []int{2,2,2,2,2},target=8的時候出現錯誤,結果為:[[2 2 2 2] [2 2 2 2] [2 2 2 2]]。因為在第一層迴圈沒有去重的情況下,即使後面上層去重了,也會導致出現重複的情況。於是想著給第一層添加當i>0的時候,如果此時的數等於上一個數則直接跳出本次迴圈。

錯誤程式碼二

func fourSum(nums []int, target int) [][]int {

	if len(nums) < 4 {
		return nil
	}
	sort.Ints(nums)
	result := make([][]int,0)
	for i:=0;i<len(nums);i++{
		if i>0 && nums[i] == nums[i-1] {
			continue
		}
		tmp := threeSum(nums[i],nums[i+1:],target-nums[i])
		result = append(result,tmp...)
	}
	return result
}


func threeSum(val int,nums []int,target int) [][]int {

	result := make([][]int,0)
	for i:=0;i<len(nums);i++{
		x,y := i+1,len(nums)-1
		tmp := target - nums[i]
		for x < y {
			// 這裡直接是為了去重
			for x <= len(nums)-2 && nums[x] == nums[x+1]{
				x++
				continue
			}
			for y > x && nums[y] == nums[y-1] {
				y--
				continue
			}
			if nums[x] + nums[y] == tmp {
				arr := []int{val,nums[i],nums[x],nums[y]}
				result = append(result,arr)
				x++
				y--
			}else if nums[x] + nums[y] > tmp {
				y--
			}else if nums[x] + nums[y] < tmp {
				x++
			}
		}
	}
	return result
}

給第一層去重了之後,提交執行,還是同一個例子出現錯誤,結果為:[[2 2 2 2] [2 2 2 2]]。因為第一層已經去重了,出現問題只能是之後了。經過除錯發現,在第二層這裡,沒有對本次遍歷的值是否與上一次的相等進行判斷。給第二層添加當i>0的時候,如果此時的數等於上一個數則直接跳出本次迴圈。,

錯誤程式碼三

func fourSum(nums []int, target int) [][]int {

	if len(nums) < 4 {
		return nil
	}
	sort.Ints(nums)
	result := make([][]int,0)
	for i:=0;i<len(nums);i++{
		if i>0 && nums[i] == nums[i-1] {
			continue
		}
		tmp := threeSum(nums[i],nums[i+1:],target-nums[i])
		result = append(result,tmp...)
	}
	return result
}


func threeSum(val int,nums []int,target int) [][]int {

	result := make([][]int,0)
	for i:=0;i<len(nums);i++{
		if i>0 && nums[i] == nums[i-1] {
			continue
		}
		x,y := i+1,len(nums)-1
		tmp := target - nums[i]
		for x < y {
			// 這裡直接是為了去重
			for x <= len(nums)-2 && nums[x] == nums[x+1]{
				x++
				continue
			}
			for y > x && nums[y] == nums[y-1] {
				y--
				continue
			}
			if nums[x] + nums[y] == tmp {
				arr := []int{val,nums[i],nums[x],nums[y]}
				result = append(result,arr)
				x++
				y--
			}else if nums[x] + nums[y] > tmp {
				y--
			}else if nums[x] + nums[y] < tmp {
				x++
			}
		}
	}
	return result
}

這次上面的例子通過,但是當nums=[]int{-2,-1,-1,1,1,2,2},target=0的時候,結果只為:[[-2 -1 1 2]]。與正確結果不符合,還有一個[-1,-1,1,1]。經過除錯發現是因為第三層的判斷出現了錯誤,因為y > x && nums[y] == nums[y-1],會導致x=y的情況而導致在判斷-1,-1,1,1這個結果的時候直接跳出迴圈。因為是y-1會導致判斷向前看,但是我們每一次的判斷是向後看的,也就是我們需要看nums[y]不與nums[y+1]相等。

正確程式碼

上面的修改完之後,就正確咯

func fourSum(nums []int, target int) [][]int {

	if len(nums) < 4 {
		return nil
	}
	sort.Ints(nums)
	log.Println(nums)
	result := make([][]int,0)
	for i:=0;i<len(nums);i++{
		if i>0 && nums[i] == nums[i-1] {
			continue
		}
		tmp := threeSum(nums[i],nums[i+1:],target-nums[i])
		result = append(result,tmp...)
	}
	return result
}


func threeSum(val int,nums []int,target int) [][]int {

	result := make([][]int,0)
	for i:=0;i<len(nums);i++{
		if i>0 && nums[i] == nums[i-1] {
			continue
		}
		x,y := i+1,len(nums)-1
		tmp := target - nums[i]
		for x < y {
			// 這裡的迴圈,都是為了讓下一次的迴圈值等於上次的迴圈值
			if x>i+1 && nums[x] == nums[x-1] {
				x++
				continue
			}
			if y>=0 && y<len(nums)-1 && nums[y] == nums[y+1] {
				y--
				continue
			}

			if nums[x] + nums[y] == tmp {
				arr := []int{val,nums[i],nums[x],nums[y]}
				result = append(result,arr)
				x++
				y--
			}else if nums[x] + nums[y] > tmp {
				y--
			}else if nums[x] + nums[y] < tmp {
				x++
			}
		}
	}
	return result
}