当前位置: 首页 > 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 快照日志
  • 金融监管总局修订发布《行政处罚办法》,7月1日起施行
  • 看见“看得见的手”,看见住房与土地——读《央地之间》
  • 78家公募年度业绩比拼:23家营收净利双升,十强座次微调
  • 解放日报:持续拿出排头兵姿态先行者担当
  • 铁路五一假期运输今日启动,预计发送旅客1.44亿人次
  • 央行召开落实金融“五篇大文章”总体统计制度动员部署会议