当前位置: 首页 > news >正文

代码训练day25回溯p4

1.递增子序列

(1)不能排序 (2)回溯搜索不能重复,用hashset去重(3)注意搜索条件,递增,不重复

class Solution {
    // 不能排序
    List<List<Integer>> res = new ArrayList<>();
    Deque<Integer> path = new ArrayDeque<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backtrack(nums, 0);
        return res;        
    }
    private void backtrack(int[] nums, int startIndex){
        if (path.size() > 1) {// 终止条件,递增子序列大小至少为2
            res.add(new ArrayList<>(path));
        }
        // 单层搜索逻辑
        HashSet<Integer> uset = new HashSet<>();
        for (int i = startIndex; i < nums.length; i++) {
            if (!path.isEmpty() && path.getLast() > nums[i] || uset.contains(nums[i]))
                continue;// 判断 path 不为空且队列递减   或   有重复跳过
            uset.add(nums[i]);// 用于去重
            path.add(nums[i]);
            backtrack(nums, i + 1);
            path.removeLast();// 回溯
        }
    }
}

2.全排列

元素不重复

深入理解回溯:

回溯的本质:通过状态恢复,遍历所有可能的决策分支。

回溯的撤销是对当前路径上元素标记状态的撤销,以免影响其他路径。

每一次for循环都代表不同的路径分支,所以for循环的末尾是对状态的回溯。

class Solution {
    // 全排列是有序的,元素顺序不同排列也不同,不用startindex,用used标记已选择
    List<List<Integer>> res = new ArrayList<>();
    Deque<Integer> path = new ArrayDeque<>();
    boolean[] used;
    public List<List<Integer>> permute(int[] nums) {
        if (nums.length == 0) return res;
        used = new boolean[nums.length];
        backtrack(nums);
        return res;
    }
    private void backtrack(int[] nums) {
        if (path.size() == nums.length) {// 终止条件 path 元素等于数组长度
            res.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (used[i]) continue; // 重复跳过
            used[i] = true;
            path.add(nums[i]);
            backtrack(nums);
            path.removeLast();// 回溯
            used[i] = false;
        }
    }
}

3.全排列II

数组元素可重复

class Solution {
    // 全排列去重,元素顺序不同排列不同
    // 去重的关键在于排序   
    List<List<Integer>> res = new ArrayList<>();
    Deque<Integer> path = new ArrayDeque<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        if (nums.length == 0) return res;
        boolean[] used = new boolean[nums.length];
        Arrays.fill(used, false);
        Arrays.sort(nums);
        backtrack(nums, used);
        return res;
    }
    private void backtrack(int[] nums, boolean[] used) {
        if (path.size() == nums.length) {
            res.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            // used[i - 1] == true,说明同⼀树⽀nums[i - 1]使⽤过
            // used[i - 1] == false,说明同⼀树层nums[i - 1]使⽤过
            // 如果同⼀树层nums[i - 1]使⽤过则直接跳过
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) continue;
             //如果同⼀树⽀nums[i]没使⽤过开始处理
            if (used[i] == false) {
                used[i] = true; // 标记同一树枝nums[i]使用过,防止同路径重复使用
                path.add(nums[i]);
                backtrack(nums, used);
                path.removeLast();
                used[i] = false;
            }
        }
    }
}

相关文章:

  • 嵌入式程序设计英语
  • java: 需要‘)‘ java: 未结束的字符串文字,java: 不是语句,怎么解决
  • C++ (初始C++,命名空间,引用,函数增强)
  • Java-分布式锁tryLock(0, TimeUnit.SECONDS)中0的含义
  • 大模型中提到的分词器是什么
  • C++算法优化实战:破解性能瓶颈,提升程序效率
  • 【AI】使用 Hugging Face Transformers 进行文本摘要实现
  • (2)VTK C++开发示例 --- 绘制多面锥体
  • 预防WIFI攻击,保证网络安全
  • 《植物大战僵尸融合版v2.4.1》,塔防与创新融合的完美碰撞
  • RHCE第五章:NFS服务器
  • 前端操作document的小方法,主要功能-获取当前页面全部的a标签页,并根据链接中必要的字段进行判断,然后把这些链接放入iframe去打开
  • 【Windows】系统安全移除移动存储设备指南:告别「设备被占用」弹窗
  • UE5蓝图实现打开和关闭界面、退出
  • 使用人工智能大模型腾讯元宝,如何快速些成果申报书?
  • C/C++基础
  • 基于 DB、EAST、SAST 的文本检测算法详解及应用综述
  • VSCode写java时常用的快捷键
  • 【KWDB 创作者计划】_产品技术解读_2
  • 如何分析 JVM OOM 内存溢出 Dump 快照日志
  • 解放日报:订单不撤,中国工程师有能力
  • 央媒关注微短剧如何探索精品化之路:从“悬浮”落回“现实”
  • 2025扬州“烟花三月”国际经贸旅游节开幕,37个重大项目现场签约
  • 42岁北京大学科学技术与医学史系副教授陈昊逝世
  • 美肯塔基州长警告:关税或致美家庭年增数千美元支出
  • 广西吃了自然保护地划得过多的亏?自治区党委书记要求廓清模糊认识