【回溯算法 9】组合总和(medium)(每日一题)

 🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇

                                      ⭐回溯⭐

🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇


前言

回溯算法是⼀种经典的递归算法,通常⽤于解决组合问题、排列问题和搜索问题等。

回溯算法的基本思想:从⼀个初始状态开始,按照⼀定的规则向前搜索,当搜索到某个状态⽆法前进 时,回退到前⼀个状态,再按照其他的规则搜索。

回溯算法在搜索过程中维护⼀个状态树,通过遍历 状态树来实现对所有可能解的搜索。 回溯算法的核⼼思想:“试错”,即在搜索过程中不断地做出选择,如果选择正确,则继续向前搜 索;否则,回退到上⼀个状态,重新做出选择。

回溯算法通常⽤于解决具有多个解,且每个解都需要 搜索才能找到的问题。


 回溯算法的模板

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Backtracking {
    public void backtracking(int[] candidates, int target) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(candidates);
      // 如果需要对candidates进行排序

        backtrack(result, new ArrayList<>(), candidates, target, 0);
    }

    private void backtrack(List<List<Integer>> result, List<Integer> tempList, int[] candidates, int remain, int start) {
        if (remain < 0) { 
       // 如果 remain 小于 0,表示当前的组合不符合要求,直接返回
            return;
        } else if (remain == 0) { 
            // 如果 remain 等于 0,表示当前的组合符合要求,加入到结果中
            result.add(new ArrayList<>(tempList));
        } else {
            for (int i = start; i < candidates.length; i++) {
                if (i > start && candidates[i] == candidates[i - 1]) {
                    continue; 
                  // 避免重复计算,如果当前数字和上一个数字相同,则跳过
                }
                tempList.add(candidates[i]); // 将当前数字加入到临时列表中
                backtrack(result, tempList, candidates, remain - candidates[i], i + 1); 
                // 递归调用,继续向下搜索
                tempList.remove(tempList.size() - 1); 
                // 回溯,将最后加入的数字移除,尝试下一个数字
            }
        }
    }
}

 回溯算法是⼀种⾮常重要的算法,可以解决许多组合问题、排列问题和搜索问题等。回溯算法的核⼼ 思想是搜索状态树,通过遍历状态树来实现对所有可能解的搜索。回溯算法的模板⾮常简单,但是实 现起来需要注意⼀些细节,⽐如如何做出选择、如何撤销选择等。


2. 组合总和(medium)

题目链接:39. 组合总和 - 力扣(LeetCode)

问题描述

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

算法思路

算法原理描述

这个问题的核心是从 1 到 n 中选择 k 个数的所有组合,而不考虑顺序。为了实现这一目标,我们可以采用深度优先搜索(DFS)的方法来生成所有可能的组合。

类定义及变量初始化
  1. 类定义:

    • 定义一个名为 Solution 的类来封装解决方案逻辑。
  2. 成员变量初始化:

    • List<Integer> path: 用于存储当前的组合路径。
    • List<List<Integer>> ret: 用于存储所有有效的组合结果。
    • int max: 表示总的元素数量 n。
    • int num: 表示每个组合需要选择的元素数量 k。
主方法实现
  1. 主方法 combine:
    • 初始化 path 和 ret
    • 设置 max 和 num
    • 从 1 开始调用 dfs 方法开始递归。
    • 最后返回 ret,即所有有效的组合。
递归方法实现
  1. 递归方法 dfs:
    • 参数 cur 表示当前正在考虑放置哪个数字。
    • 递归的基本结束条件是当 path 的大小等于 num 时,此时已经找到了一个有效的组合,将其添加到结果集中 ret 并返回。
    • 对于每一个数字 i (从 cur 开始到 max),执行以下操作:
      • 将 i 添加到当前组合 path 中。
      • 调用 dfs(i + 1) 进行下一层递归。
      • 在递归返回后,从 path 中移除最后一个添加的元素 i,这是回溯的过程,以便尝试下一个可能的组合。

 代码实现:

class Solution {
    List<Integer> path;
    List<List<Integer>> ret;
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        path = new ArrayList<>();
        ret  = new ArrayList<>();
        int sum=0;
        dfs(sum,candidates,target,0);
        return ret;
    }

    public void dfs(int sum,int[] candidates,int target,int pos){
        //如果满足条件就返回
        if(sum == target){
            ret.add(new ArrayList(path));
            return;
        }
        //如果越界或者超过也返回
        if(sum>target||pos == candidates.length){
            return;
        }
        for(int i = pos ;i<candidates.length;i++){
            path.add(candidates[i]);
            dfs(sum+candidates[i],candidates,target,i);
            path.remove(path.size()-1);
        }
    }
}


总结

动动手点个赞会让作者更开心,感谢阅览,加油各位 !

  • 21
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回溯法求解组合总和的主要思路是:对于每个数字,可以选择使用或不使用,如果使用了,则将其加入当前组合中,并继续考虑剩下的数字;如果不使用,则直接考虑剩下的数字。当目标值减为0时,说明已经找到了一个符合要求的组合。 以下是一个求解组合总和JavaScript代码示例: ```javascript function combinationSum(candidates, target) { const res = []; candidates.sort((a, b) => a - b); // 排序 backtrack([], 0, target); return res; function backtrack(path, start, target) { if (target < 0) return; // 如果目标值小于0,说明不符合要求,结束当前回溯 if (target === 0) { // 如果目标值等于0,说明已经找到了一个符合要求的组合 res.push([...path]); return; } for (let i = start; i < candidates.length; i++) { path.push(candidates[i]); // 将当前数字加入组合中 backtrack(path, i, target - candidates[i]); // 继续考虑剩下的数字 path.pop(); // 回溯,将当前数字从组合中移除 } } } ``` 在代码中,backtrack函数用于进行回溯。它接受三个参数:当前组合path、起始数字的下标start和目标值target。在函数中,遍历候选数字数组,对于每个数字,有两种选择:使用或不使用。如果使用,将其加入当前组合path,继续考虑剩下的数字;如果不使用,直接考虑剩下的数字。当目标值减为0时,说明已经找到了一个符合要求的组合,将其加入结果数组res中,并退出当前回溯。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值