【回溯算法 7】组合(medium)(每日一题)

 

                                      ⭐回溯⭐


前言

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

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

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

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


 回溯算法的模板

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

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

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

    private void backtrack(List> result, List 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)

题目链接:77. 组合 - 力扣(LeetCode)

问题描述

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。

算法思路

算法原理描述

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

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

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

    • List path: 用于存储当前的组合路径。
    • List> 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 path;
    List> ret;
    int max,num;
    public List> combine(int n, int k) {
         path = new ArrayList<>();
         ret = new ArrayList<>();
         max = n;
         num = k;
         dfs(1);
         return ret;
    }
    //这里cur指的是当前要放置的数字
    public void dfs(int cur){
        //出口
        if(path.size()==num){
            ret.add(new ArrayList<>(path));
            return;
        }
        for(int i = cur;i<=max;i++){
           path.add(i);
           dfs(i+1);
           //回溯
           path.remove(path.size()-1);
        }
    }
}


总结

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

你可能感兴趣的:(回溯算法,linux,windows,运维,算法,leetcode,java,蓝桥杯)