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

力扣:回溯算法

组合I 

class Solution {
    
    List<List<Integer>> result = new ArrayList(); // 所有结果集
    List<Integer> list = new ArrayList(); // 当前结果集

    public List<List<Integer>> combine(int n, int k) {
        dfs(n, k, 1);
        return result;
    }

    public void dfs(int n, int k, int index) {
        if (list.size() == k) { // 当前结果集等于要收集的数量即可存入最终结果集
            List<Integer> tem = new ArrayList(list);
            result.add(tem);
            return;
        }
        for (int i = index; i <= n; i++) {
            list.add(i); // 元素加入当前结果集
            dfs(n, k, i + 1); // 递归
            list.remove(list.size() - 1); // 该元素组合完成可以移除(回溯)
        }
    }
}

组合II 

class Solution {

    List<List<Integer>> result = new ArrayList(); // 所有结果集
    Set<List<Integer>> set = new HashSet(); // 结果集去重
    List<Integer> list = new ArrayList(); // 当前结果集

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        backTring(candidates, 0, target, 0);
        return result;
    }

    public void backTring(int[] candidates, int sum, int target, int index) {
        if (candidates == null || candidates.length < 0) return; 
        if (sum == target) { // 总和等于目标值是返回当前结果集
            List<Integer> tem = new ArrayList(list);
            Collections.sort(tem); // 去重(如:1 1 2 和 2 1 1 是一组结果集)
            if (!set.contains(tem)) { 
                result.add(new ArrayList(list));
                set.add(tem);
            }
            return;
        }
        if (sum > target) { // 当前结果集大于目标值说明当前结果集不对
            return;
        }
        for (int i = index; i < candidates.length; i++) {
            sum += candidates[i]; // 当前总和
            list.add(candidates[i]); // 当前结果集
            backTring(candidates, sum, target, i + 1);
            sum -= candidates[i]; // 回溯总和
            list.remove(list.size() - 1); // 回溯结果集
        }
    }
}

 组合III

class Solution {

    List<List<Integer>> result = new ArrayList(); // 最终结果集
    List<Integer> list = new ArrayList(); // 当前结果集

    public List<List<Integer>> combinationSum3(int k, int n) {
        backCheck(k, n, 1, 0, 0);
        return result;
    }

    public void backCheck(int k, int n, int num, int count, int sum) {
        if (count == k && n == sum) { // 元素数量等于k 且 sum等于 n 时为符合的结果集
            result.add(new ArrayList(list));
            return;
        }
        if (count > k || n < sum) { // 要求的数量或者总和不对则返回
            return;
        }
        
        for (int i = num; i <= 9; i++) {
            list.add(i);
            sum += i;
            count++;
            backCheck(k, n, i + 1, count, sum);
            list.remove(list.size() - 1);
            sum -= i;
            count--;
        }
    }
}

 分割回文串

class Solution {

    List<List<String>> result = new ArrayList(); // 最终结果集
    List<String> list = new ArrayList(); // 当前结果集

    public String[][] partition(String s) {
        int n = s.length();
        dfs(0, n, s);
        return listToArrays(result); // 集合转换为数组
    }

    public void dfs(int index, int n, String s) {
        if (index == n) { // 指针指向n时说明遍历到字符串末尾,可以返回结果集
            result.add(new ArrayList(list));
            return;
        }
        for (int i = index; i < n; i++) {
            if (isPalindrome(s.substring(index, i + 1))) {  // 如果是回文串则加入当前结果集         
                list.add(s.substring(index, i + 1)); // 加入结果集
                dfs(i + 1, n, s);
                list.remove(list.size() - 1); // 回溯
            }
        }
    }

    public boolean isPalindrome(String str) { // 判断是否为回文串
        int l = 0;
        int r = str.length() - 1;
        while (l < r) {
            if (str.charAt(l) != str.charAt(r)) {
                return false;
            }
            l++;
            r--;
        }
        return true;
    }

    public String[][] listToArrays (List<List<String>> list) { // 集合转换为数组
        int n = list.size();
        String[][] arrs = new String[n][];
        for (int i = 0; i < n; i++) {
            List<String> tem = list.get(i);
            String[] arr = tem.toArray(new String[tem.size()]);
            arrs[i] = arr;
        }
        return arrs;
    }
}

复原 IP 地址

class Solution {

    List<String> res = new ArrayList(); // 所有结果集
    List<String> tem = new ArrayList(); // 当前结果集

    public List<String> restoreIpAddresses(String s) {
        int n = s.length(); // 字符串长度
        if (n < 0 || n > 12) return res; // 剪枝
        dfs(s, 0, n);
        return res;
    }

    public void dfs(String s, int index, int n) {
        if (tem.size() == 4) { // ip地址为四个数字组成,当前结果集等于4即可返回
            if (index == n) { // 当前指针指向末尾即可加入最终结果集
                StringBuilder sb = new StringBuilder(); // 拼凑成需要的字符串
                for (int i = 0; i < 4; i++) {
                    sb.append(tem.get(i));
                    if (i != 3) {
                        sb.append(".");
                    }
                }
                res.add(sb.toString()); // 加入到最终结果集
            }
            return;
        }
        for (int i = index; i < n && i < index + 3; i++) { // 当前指针
            if (isNum(s.substring(index, i + 1))) { //
                tem.add(s.substring(index, i + 1));
                dfs(s, i + 1, n);
                tem.remove(tem.size() - 1);
            }
        }
    }

    public boolean isNum(String s) { // 判断是否为合法数字
        if (s.length() >= 2 && s.charAt(0) == '0') 
            return false;
        Integer num = Integer.valueOf(s);
        if (num > 255) 
            return false;
        return true;
    }
}

子集I

class Solution {

    List<List<Integer>> res = new ArrayList();
    List<Integer> tem = new ArrayList();

    public List<List<Integer>> subsets(int[] nums) {
        dfs(nums, 0, nums.length);
        return res;
    }

    public void dfs(int[] nums, int index, int n) {
        res.add(new ArrayList(tem)); // 每次递归都是一个新子集
        for (int i = index; i < n; i++) {
            tem.add(nums[i]);
            dfs(nums, i + 1, n);
            tem.remove(tem.size() - 1);
        }
    }
}

 子集II

class Solution {

    List<List<Integer>> res = new ArrayList(); // 所有结果集
    List<Integer> list = new ArrayList(); // 当前子集
    Set<List<Integer>> set = new HashSet();  // 子集去重

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums); // 排序
        dfs(nums, 0, nums.length);
        return res;
    }

    public void dfs(int[] nums, int index, int n) {

        res.add(new ArrayList(list)); // 每次递归都是新子集
        
        for (int i = index; i < n; i++) {
            if (i != index && nums[i] == nums[i - 1]) continue; // 数组已经排序,如果当前元素等于上一个元素进行递归会有重复子集(如:数组 {1 1} 的子集为 {1} {1 1},如果索引到第二个元素再进行递归则会有重复子集{1}
            list.add(nums[i]); 
            dfs(nums, i + 1, n);
            list.remove(list.size() - 1);
        }
    }
}

 最长递增子序列

 

class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] dp = new int[nums.length]; // 动态规划+暴力枚举
        Arrays.fill(dp, 1); // 每个子序列起始都是1
        int max = dp[0];
        for (int i = 1; i < nums.length; i++) {
            for (int j = 0; j < i; j++) { // 判断当前位置最长子序列是多少
                if (nums[j] < nums[i]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            max = max > dp[i] ? max : dp[i];
        }
        return max;
    }
}

全排列I

class Solution {

    List<List<Integer>> res = new ArrayList(); // 所有结果集
    List<Integer> list = new ArrayList(); // 当前结果集

    public List<List<Integer>> permute(int[] nums) {
        boolean[] used = new boolean[nums.length]; // 判断当前元素是否加入结果集
        dfs(nums, used);
        return res;
    }

    public void dfs(int[] nums, boolean[] used) {
        if (list.size() == nums.length) { // 当前结果集长度等于数组长度即可加入所有结果集
            res.add(new ArrayList(list));
        }
        for (int i = 0; i < nums.length; i++) {
            if (used[i] == false) { // 判断元素是否加入当前结果集
                list.add(nums[i]); // 元素入集合
                used[i] = true; // 设置元素状态为被使用
                dfs(nums, used);
                used[i] = false; // 回溯
                list.remove(list.size() - 1);
            }
        }
    }
}

 全排列II

class Solution {

    List<List<Integer>> res = new ArrayList(); // 所有结果集合
    List<Integer> list = new ArrayList(); // 当前结果集合
    Set<List<Integer>> set = new HashSet(); // 结果集去重

    public List<List<Integer>> permuteUnique(int[] nums) {
        boolean[] flag = new boolean[nums.length]; // 判断元素是否加入当前结果集
        dfs(nums, flag);
        return res;
    }

    public void dfs(int[] nums, boolean[] flag) {
        if (list.size() == nums.length) { // 当前结果集合等于数组长度即可加入最终结果集
            List<Integer> tem = new ArrayList(list);
            if (!set.contains(tem)) { // 判断该结果集是否在最终结果集中存在
                set.add(tem); // 该结果集的顺序存入去重集合中,避免重复加入最终结果集
                res.add(tem);
            }
        }
        for (int i = 0; i < nums.length; i++) {
            if (flag[i] == false) {
                list.add(nums[i]);
                flag[i] = true;
                dfs(nums, flag);
                flag[i] = false;
                list.remove(list.size() - 1);
            }
        }
    }
}

 N皇后

class Solution {

    List<List<String>> res = new ArrayList(); // 最终结果集合
    List<String> list = new ArrayList(); // 

    public List<List<String>> solveNQueens(int n) {
        char[][] board = new char[n][n]; // 创建棋盘并初始化
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                board[i][j] = '.';
            }
        }
        dfs(board, n, 0);
        return res;
    }

    public void dfs(char[][] board, int n, int row) {
        if (row == n) { // 当第row行也可以放棋子说明该方法合法
            res.add(printResult(board, n));
            return;
        }
        for (int col = 0; col < n; col++) {
            // 判断该位置是否可以填棋
            if (isFlag(board, row, col)) {
                board[row][col] = 'Q';
                dfs(board, n, row + 1);
                board[row][col] = '.';
            }
        }
    }

    // 核心方法判断棋子放置位置是否合法
    public boolean isFlag(char[][] board, int row, int col) { // 判断该位置放棋子是否合法
        int n = board.length;
        for (int i = 0; i < n; i++) { // 同一列不能有皇后
            if (board[i][col] == 'Q') return false;
        }
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { // 右斜线不能有皇后
            if (board[i][j] == 'Q') return false;
        }
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { // 左斜线不能有皇后
            if (board[i][j] == 'Q') return false;
        }
        return true; // 合法
    }

    public List<String> printResult(char[][] board, int n) { // 按照题目要求打印结果集
        List<String> list = new ArrayList();
        for (int i = 0; i < n; i++) {
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < n; j++) {
                sb.append(board[i][j]);
            }
            list.add(sb.toString());
        }
        return list;
    }
}

 解数独

class Solution {
    public void solveSudoku(char[][] board) {
        dfs(board);
    }

    public boolean dfs(char[][] board) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] == '.') {
                    // 填充数字
                    for (char c = '1'; c <= '9'; c++) {
                        if (isFlag(board, i, j, c)) {
                            board[i][j] = c; // 暂时填充该数字
                            if (dfs(board)) return true;
                            board[i][j] = '.'; // 递归到后面不合法,回溯
                        }
                    }
                    return false;
                }
            }
        }
        return true;
    }

    // 核心方法,判断该位置的数字是否合法
    public boolean isFlag(char[][] board, int row, int col, char c) { // 判断该数字是否重复
        for (int i = 0; i < 9; i++) {
            // 同行出现过
            if (board[i][col] == c) return false; 
            // 同列出现过
            if (board[row][i] == c) return false; 
            // 九宫格出现过
            if (board[(row / 3) * 3 + i / 3][(col / 3) * 3 + i % 3] == c) return false;
        }
        return true;
    }
}

相关文章:

  • 获客、留客、复购...如何利用易境通集运系统越过“三座大山”?
  • 【AI工具开发】Notepad++插件开发实践:从基础交互到ScintillaCall集成
  • AI正在接管你的生活:2025年互联网生存指南
  • 全国职业技能大赛_网络安全_中职A模块解析
  • Leetcode-100 回溯法-电话号码的字母组合
  • 初识Qt(一)
  • 经销商订货管理系统小程序PHP+uniapp
  • beamforming
  • 免费使用!OpenAI 全量开放 GPT-4o 图像生成能力!
  • java基础知识和语法
  • S32K144外设实验(六):FTM输出单路PWM
  • JVM 如何打破双亲委派模型?
  • Arduino硬件控制开发基础资料
  • 消息队列Message Queue
  • Baklib内容中台的核心定位是什么?
  • 创新驱动 智领未来丨中威电子全景展示高速公路数字化创新成果
  • rent8_wechat-新增提醒收租功能
  • 青少年编程与数学 02-013 初中数学知识点 03课题、数与代数
  • 【LVS】负载均衡群集部署(DR模式)
  • VLAN 高级特性
  • 工商银行杭州金融研修院原院长蒋伟被“双开”
  • 现场丨在胡适施蛰存等手札与文献间,再看百年光华
  • 著名词作家陈哲逝世,代表作《让世界充满爱》《同一首歌》等
  • 夜读丨读《汉书》一得
  • 通化市委书记孙简升任吉林省副省长
  • 哲学新书联合书单|远离苏格拉底