算法题(回溯)

一、题目

1、全排列(LC 46)

2、子集(LC 78)

二、题解

1、全排列(LC 46)

(1)分析

使用回溯的方式解决。按排列的位置依次填充元素,并通过标记数组避免元素重复使用。定义用于存储单个排列结果的固定长度列表 path,存储所有排列结果的二维集合 ans,以及标记数组元素是否被使用的 onPath 数组。递归时考虑边界条件,当 i 等于数组长度时,说明已完成一个完整排列的构造,将当前排列存入结果集并终止当前递归。

在递归过程中,通过循环遍历所有数组元素,若元素未被标记使用,则将其放入当前排列的对应位置,标记为已使用后递归处理下一个位置;递归返回后,将元素的使用标记重置为未使用状态,完成回溯恢复现场,保证后续可以正常使用该元素,最终生成所有不重复的全排列。

时间复杂度:O(n * n!),其中 n 为 nums 的长度。

空间复杂度:O(n)。返回值的空间不计入。

(2)解答
java 复制代码
class Solution {
    public List<List<Integer>> permute(int[] nums) {
        //初始化
        int n = nums.length;
        List<Integer> path = Arrays.asList(new Integer[n]); //存放每个排列的列表
        List<List<Integer>> ans = new ArrayList<>();        //存放所有排列
        boolean[] onPath = new boolean[n];                  //标记数组中的元素是否可选
        dfs(0, nums, ans, onPath, path);          
        return ans;
    }

    public void dfs(int i, int[] nums, List<List<Integer>> ans, boolean[] onPath ,List<Integer> path){
        if( i == nums.length){                       //边界条件,i超过了数组的最大下标
            ans.add(new ArrayList<>(path));          //把这次所得的排列保存在结果中
            return;
        }

        for(int j = 0; j < nums.length; j++){
            if(!onPath[j]){
                path.set(i,nums[j]);         //当前元素可以选择时,放在列表中
                onPath[j] = true;            //标记这个元素已经被选择了
                dfs(i + 1, nums, ans, onPath ,path); //考虑下一个元素
                onPath[j] = false;                   //恢复现场,否则只能生成一个排列
            }
        }
    }
}

2、子集(LC 78)

(1)分析

基于回溯算法的"选或不选"思想解决。对于数组中的每一个元素,都存在加入当前子集和不加入当前子集两种选择,长度为n的数组最终会生成2ⁿ个子集。

递归函数以 i 作为当前处理的数组元素下标,当 i 等于数组长度时,代表所有元素的选择决策已完成,将当前子集复制后存入结果集。递归过程分为两个分支:不选择当前元素时,直接递归处理下一个元素;选择当前元素时,将元素添加到子集后递归处理下一个元素,递归返回后移除最后添加的元素,完成回溯恢复现场,确保两个选择分支互不干扰,最终生成数组的全部子集。

时间复杂度:O(n * )

空间复杂度:空间复杂度:O(n)。返回值的空间不计入。

(2)解答
java 复制代码
class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        //初始化
        List<List<Integer>> ans = new ArrayList<>();  //存放所有子集
        List<Integer> path = new ArrayList<>();       //存放一个子集
        dfs(0, nums, path, ans);
        return ans;
        
    }
    public void dfs(int i, int[] nums, List<Integer> path, List<List<Integer>> ans){
        if( i == nums.length){
            ans.add(new ArrayList<>(path));      //边界条件,i超出数字下标
            return;
        }

        //不选
        dfs(i+1, nums, path, ans);           //不选择当前元素,不加入子集中

        //选
        path.add(nums[i]);                  //选择当前元素,加入子集中
        dfs(i+1, nums, path, ans);

        path.removeLast();               //恢复现场
    }
}
相关推荐
weixin_307779132 小时前
C++代码实现MATLAB中的dlarray函数功能
开发语言·c++·算法·matlab
hetao17338377 小时前
2026-10-03~04 hetao1733837 的刷题记录
c++·算法
Zootopia6268 小时前
飞行力学知识梳理1|飞行性能与稳定性
人工智能·python·算法·机器学习·无人机·学习方法·信息与通信
longlongzihan8 小时前
从LeetCode 70. 爬楼梯看动态规划:如何精准推导状态转移方程?
c++·算法·leetcode·动态规划
2601_960356389 小时前
2027校招采购岗解析:数学基础如何迁移到需求预测、成本与供应商分析
人工智能·算法
h_a_o777oah10 小时前
【树论】树链剖分:将树形结构转化为线性结构以处理树上路径问题(洛谷 P3384 附C++代码模板)
数据结构·算法·线段树·acm·树链剖分·树论·重链剖分
HEJOO910 小时前
指针的算术运算详解
java·数据结构·算法
Coder-magician10 小时前
《代码随想录》刷题打卡day47:并查集-part01
数据结构·算法·图论
垆边人似月.10 小时前
VLAN 资源池(100~200 分档)
数据结构·算法
潼心1412o11 小时前
C++初阶(长期更新)第6讲:类和对象(下)
开发语言·c++·算法