回溯算法排列组合leetcode39:

先画图,写出递归树:

有点乱不好意思

 

通过图可以观察到for循环从底从左往右遍历,然后递归深度。

backtracking的设计应该是

  1、设计递归出口,并处理逻辑

  递归出口刚开是想到的是startIndex=len(s),但是发现不太合理,如果是这个递归出口的话那么会一直循环一直递归,会导致栈溢出,后来仔细想了一下应该是target==0的时候刚好得到一组数据。所以应该是target==0

if target == 0 {

        temp := make([]int, len(paths)) // 创建一个临时切片存储当前路径

        copy(temp, paths)               // 拷贝当前路径到临时切片

        *res = append(*res, temp)       // 将临时切片加入结果数组中

        return

    }

 

原来我直接将path append到res中了,但是在第二个测试用例中出现了异常结果:[2,2,3,2],仔细查找了一下原因是因为切片是引用类型,在回溯过程中,paths 会不断地被修改和回溯,如果直接将 paths 添加到结果数组中,后续对 path 的修改也会影响到已经添加到结果数组中的路径。为了避免这个问题,我们需要创建一个临时切片 temp,将当前的路径 path 拷贝到 temp 中,然后将 temp 添加到结果数组中。这样可以确保每个路径在添加到结果数组之前都是独立的,互不影响。

#    2、处理横向遍历for循环逻辑

在横向处理for中逻辑的时候就比较常规了对横向的字符串数字遍历就好,图中可以观察到只要当前节点的值不大于target就可加入路径,但是值得注意的是本题中数字是可以一直使用的。所以在if语句块内回溯的时候就不能对index+1回溯了,需要对当前的i回溯,因为可以无限使用。

func backtracking(candidates []int, index int, target int, paths []int, res *[][]int) {

    if target == 0 {

        temp := make([]int, len(paths)) // 创建一个临时切片存储当前路径

        copy(temp, paths)               // 拷贝当前路径到临时切片

        *res = append(*res, temp)       // 将临时切片加入结果数组中

        return

    }

    for i := index; i < len(candidates); i++ {

        if candidates[i] <= target {

            paths = append(paths, candidates[i])

            backtracking(candidates, i, target-candidates[i], paths, res)

            paths = paths[:len(paths)-1]

        }


    }

}

 

# 3、设计主函数:

开始的时候我是用的全局变量 res,并尝试通过返回值的方式来返回结果,这样会导致出现不可预料的结果。后来我将 res 作为参数传递给 backtracking 函数,并且将它修改为指针类型。然后,在 combinationSum 函数中,直接声明一个局部的结果数组并将其作为参数传递给 backtracking 函数。这样就避免问题了。

贴上全部代码:

package main

import "fmt"

func combinationSum(candidates []int, target int) [][]int {
	res := [][]int{}
	startIndex := 0
	backtracking(candidates, startIndex, target, []int{}, &res)
	return res
}

func backtracking(candidates []int, index int, target int, paths []int, res *[][]int) {
	if target == 0 {
		temp := make([]int, len(paths)) // 创建一个临时切片存储当前路径
		copy(temp, paths)               // 拷贝当前路径到临时切片
		*res = append(*res, temp)       // 将临时切片加入结果数组中
		return
	}
	for i := index; i < len(candidates); i++ {
		if candidates[i] <= target {
			paths = append(paths, candidates[i])
			backtracking(candidates, i, target-candidates[i], paths, res)
			paths = paths[:len(paths)-1]
		}

	}
}
func main() {
	candidates := []int{2, 3, 5}
	target := 8
	result := combinationSum(candidates, target)
	fmt.Println(result)
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值