代码随想录day22 || 77 组合,216 组合总和,17 电话号码字母组合

回溯问题

  • 回溯通常用来解决这些问题
    组合问题:N个数里面按一定规则找出k个数的集合
    切割问题:一个字符串按一定规则有几种切割方式
    子集问题:一个N个数的集合里有多少符合条件的子集
    排列问题:N个数按一定规则全排列,有几种排列方式
    棋盘问题:N皇后,解数独等等

image

  • 回溯的通用模板
      func backtracking(参数) {
      	if (终止条件) {
      		存放结果;
      		return;
      	}
    
      	for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
      		处理节点;
      		backtracking(路径,选择列表); // 递归
      		回溯,撤销处理结果
      	}
      	return
      }
    
      // for 循环用来遍历树的同一层级,递归用来遍历树的纵向深度
    

77组合

func combine(n int, k int) [][]int {
	// 回溯加剪枝
	var path = []int{}
	var res = [][]int{}
	backtracking(n, k, 1, &path, &res)
	return res
}

func backtracking(n, k, startidx int, path *[]int, res *[][]int) {
	if len(*path) == k {
		newpath := make([]int, len(*path))  // !!!易错点,此处必须要将path重新赋值给新的变量,不然直接*res = append(*res, *path) 这样传递的是path的引用,导致最终所有结果都一样
		copy(newpath, *path)
		*res = append(*res, newpath)
		return
	}

	// 剪枝
	if n-startidx+1 < k - len(*path) {  // 易错点2,剪枝操作,如果剩余元素小于目标长度减去路径列表已有长度才剪枝,而不是直接判断index 与 k的关系
		return
	}
	for i:=startidx; i<=n; i++ {
		*path = append(*path, i) // 添加元素
		backtracking(n, k, i+1, path, res)
		*path = (*path)[:len(*path) - 1]  // 回溯删除上面添加的元素
	}

	return
}

216 排列之和

//leetcode submit region begin(Prohibit modification and deletion)
func combinationSum3(k int, n int) [][]int {
	// 思路组合问题另一种变体,返回值res用来存放和满足条件的结果即可
	var path = []int{}
	var res = [][]int{}
	backtracking(k, n, 1, &path, &res)
	return res
}

func backtracking(k, n, startidx int, path *[]int, res *[][]int) {
	length := len(*path)
	if sum(*path) == n && length == k{
		var copypath = make([]int, length)
		copy(copypath, *path)
		*res = append(*res, copypath)
		return
	}

	// 剪枝操作,如果当前剩余数组长度小于目标长度减去已有长度,剪枝
	if 9 - startidx + 1 < k - length {
		return
	}
	// 剪枝2,最小和、大于目标和
	if minsum(k) > n {
		return
	}

	// 回溯递归
	for i:=startidx; i<=9; i++{
		*path = append(*path, i)
		backtracking(k, n, i+1, path, res)
		*path = (*path)[0 : len(*path) - 1]
	}
	return
}

func sum(li []int) int {
	var sum int
	for _, i := range li {
		sum += i
	}
	return sum
}

func minsum (k int) int {
	// 返回1-9 k个数最小和
	var sum int
	for i:=1; i<=k; i++{
		sum += i
	}
	return sum
}

17 电话号码对应字母组合

func letterCombinations(digits string) []string {
	if len(digits) == 0 {
		return nil
	}
	var path = []string{}
	var res = []string{}
	backtracking(0, digits, &path, &res)
	return res
}


func backtracking(stridx int, k string, path *[]string, res *[]string){
	if len(*path) == len(k) {
		str := strings.Join(*path, "")
		*res = append(*res, str)
		return
	}

	// 剪枝情况, 结果集要的是全部情况,应该不能剪枝

	key, _ := strconv.Atoi(string(k[stridx]))
	for _, v := range digmap[key] {  // var v rune == var v []int32
		*path = append(*path, string(v))
		backtracking(stridx+1, k, path, res)
		*path = (*path)[0 : len(*path) - 1]
	}
	return
}


posted @ 2024-08-07 13:51  周公瑾55  阅读(20)  评论(0)    收藏  举报