【回溯】LeetCode经典题目总结:组合、排列、子集、分割、N皇后、单词搜索

news2025/1/5 7:12:36

回溯

    • 组合问题
    • 组合总和
    • 全排列
    • 子集
    • 分割回文串
    • N皇后
    • 电话号码的字母组合
    • 单词搜索
    • 括号生成

组合问题

给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。
示例: 输入: n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]

树形结构
在这里插入图片描述
代码
使用startIndex控制遍历,每一次递归相当于树形图中的下一层,startIndex相当于递归的深度

class Solution {
    private List<Integer> path =  new ArrayList<>();
    private List<List<Integer>> res = new ArrayList<>();

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

    public void backTracing(int n, int k, int start) {
        if (path.size() == k) {
            res.add(new ArrayList<>(path));
            return;
        }
        // 剪枝,循环的遍历:至多从 n - (k - path.size) + 1 的位置开始搜索
        for (int i=start; i <= n - (k - path.size()) + 1; i++) {
            path.add(i);
            backTracing(n, k, i + 1);  //  i + 1 是因为组合中不能有重复
            path.removeLast();
        }
    }
}

组合总和

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入:candidates = [2,3,6,7], target = 7,
所求解集为: [ [7], [2,2,3] ]

树形结构
在这里插入图片描述
代码
因为该题目中,同一个数字可以无限制重复被选取,所以在递归函数调用时与上一题不同,i不需要+1

class Solution {
    private List<Integer> path = new ArrayList<>();
    private List<List<Integer>> res = new ArrayList<>();

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        backtracing(candidates, target, 0, 0);
        return res;
    }

    public void backtracing(int[] candidates, int target, int sum, int start) {
        if (sum > target) return;
        if (sum == target) {
            res.add(new ArrayList<>(path));
            return;
        }
        for (int i = start; i < candidates.length; i++) {
            path.add(candidates[i]);
            backtracing(candidates, target, sum + candidates[i], i);
            path.removeLast();  // 回溯,移除路径 path 最后一个元素
        }
    }
}

全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]

树形结构
在这里插入图片描述
代码
排列问题,for循环i从0开始;组合问题是从startIndex开始;使用used数组标注该元素是否使用过

class Solution {
    private List<Integer> path = new ArrayList<>();
    private List<List<Integer>> res = new ArrayList<>();
    private boolean[] used;
    public List<List<Integer>> permute(int[] nums) {
        used = new boolean[nums.length];
        backTracing(nums);
        return res;
    }

    public void backTracing(int[] nums) {
        if (path.size() == nums.length) {
            res.add(new ArrayList<>(path));
            return;
        }
        // 排列问题,for循环i从0开始;组合问题是从startIndex开始
        for(int i = 0; i < nums.length; i++) {
            // 如果取过了就跳过
            if (used[i]) {
                continue;
            }
            path.add(nums[i]);
            used[i] = true;
            backTracing(nums);
            used[i] = false;
            path.removeLast();
        }
    }
}

子集

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例: 输入: nums = [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]

树形结构
在这里插入图片描述
代码
因为是子集,只要递归到就可以直接加入结果。之前都是叶节点加入结果集,这一题在递归函数一开始就可以加入结果集。

class Solution {

    private List<Integer> path = new ArrayList<>();
    private List<List<Integer>> res = new ArrayList<>();

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

    public void backTracing(int[] nums, int startIndex) {
        res.add(new ArrayList<>(path));

        if (path.size() == nums.length) {
            return;
        }

        for (int i = startIndex; i < nums.length; i++) {
            path.add(nums[i]);
            backTracing(nums, i + 1);
            path.removeLast(); 
        }
    }
}

分割回文串

给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例: 输入: “aab” 输出: [ [“aa”,“b”], [“a”,“a”,“b”] ]

树形结构
在这里插入图片描述
代码
使用startIndex控制分割位置,[startIndex, i] 就是要截取的子串。
判断这个子串是不是回文,如果是回文,就加入在path中,path用来记录切割过的回文子串。

class Solution {

    List<List<String>> res = new ArrayList<>();
    List<String> path = new ArrayList<>();

    public List<List<String>> partition(String s) {
        backTracing(s, 0);
        return res;
    }

    public void backTracing(String s, int startIndex) {
        if (startIndex == s.length()) {
            res.add(new ArrayList<>(path));
            return;
        }
        StringBuilder sb = new StringBuilder();
        for (int i = startIndex; i < s.length(); i++) {
            sb.append(s.charAt(i));
            if (check(sb)) {
                path.add(sb.toString());
                backTracing(s, i + 1);
                path.removeLast();
            }
        }
    }

    public boolean check(StringBuilder sb) {
        for (int i = 0; i < sb.length() / 2; i++) {
            if (sb.charAt(i) != sb.charAt(sb.length() - 1 - i)) {
                return false;
            }
        }
        return true;
    }
}

N皇后

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
在这里插入图片描述
树形结构
在这里插入图片描述
代码

class Solution {

    List<List<String>> res = new ArrayList<>();

    public List<List<String>> solveNQueens(int n) {
        char[][] board = new char[n][n];
        for (char[] c : board) {
            Arrays.fill(c, '.');
        }
        backtracing(n, 0, board);
        return res;
    }

    public void backtracing(int n, int row, char[][] board) {
        if (row == n) {  // 终止条件
            res.add(array2List(board));
            return;
        }
        for (int col = 0; col < n; col++) {
            if (isValid(row, col, n, board)) {
                board[row][col] = 'Q';
                backtracing(n, row + 1, board);
                board[row][col] = '.';
            }
        }
    }

    public boolean isValid(int row, int col, int n, char[][] board) {
        // 判断列
        for (int i = 0; i < row; i++) {
            if (board[i][col] == 'Q') {
                return false;
            }
        }

        // 判断45° 斜线
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (board[i][j] == 'Q') {
                return false;
            }
        }

        // 判断 135 ° 斜线, 注意 j <= n - 1
        for (int i = row - 1, j = col + 1; i >= 0 && j <= n - 1; i--, j++) {
            if (board[i][j] == 'Q') {
                return false;
            }
        }
        return true;
    }

    public List<String> array2List(char[][] board) {
        List<String> list = new ArrayList<>();
        for (char[] c : board) {
            list.add(String.copyValueOf(c));
        }
        return list;
    }
}

电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
在这里插入图片描述
示例 1:
输入:digits = “23”
输出:[“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]

树形结构
例如:输入:“23”,抽象为树形结构,如图所示:
在这里插入图片描述
代码

class Solution {

    private List<String> res = new ArrayList<>();
    private String[] numString = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    private StringBuilder temp = new StringBuilder();  // 相当于path

    public List<String> letterCombinations(String digits) {
        if (digits == null || digits.length() == 0) {
            return res;
        }
        backtracing(digits, 0);
        return res;
    }

    public void backtracing(String digits, int index) {
        if (index == digits.length()) {  // 叶节点的位置终止
            res.add(temp.toString());  // StringBuilder 转成String类型
            return;
        }
        String str = numString[digits.charAt(index) - '0'];
        for(int i=0; i < str.length(); i++) {  
            temp.append(str.charAt(i));
            backtracing(digits, index + 1);
            temp.deleteCharAt(temp.length() - 1);
        }
    }
}

单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

代码

class Solution {

    private int[][] directs = new int[][]{{-1,0}, {1,0}, {0,1}, {0,-1}};  // 定义四个方向
    private int m;  // board 的行数
    private int n;  // borad 的列数
    private char[] ws;  // word的字符数组
    private boolean[][] used; // board中的某元素是否使用过
    private char[][] boad;  
 
    public boolean exist(char[][] board, String word) {
        this.m = board.length;
        this.n = board[0].length;
        this.ws = word.toCharArray();
        this.used = new boolean[m][n];
        this.boad = board;
        for(boolean[] u : used) {
            Arrays.fill(u, false);
        }
        for (int i=0; i<m; i++) {
            for (int j=0; j < n; j++) {
                if (boad[i][j] == ws[0]) {
                    used[i][j] = true;
                    if (backtracing(i, j, 1)) {
                        return true;
                    } else {
                        used[i][j] = false;
                    }
                }
            }
        }
        return false;
    }

    public boolean backtracing(int i, int j, int index) {
        if (index == ws.length) {
            return true;
        }
        for (int[] direct : directs) {
            int newX = i + direct[0];
            int newY = j + direct[1];

            // 超出边界
            if (!isInArea(newX, newY)) {
                continue;
            }
            // 被使用过
            if (used[newX][newY]) {
                continue;
            }
            // 不是要找的值
            if (boad[newX][newY] != ws[index]) {
                continue;
            }
            // 开始递归
            used[newX][newY] = true;
            if (backtracing(newX, newY, index + 1)) { // 下一层递归成功
                return true;
            } else {
                used[newX][newY] = false;
            }
        }
        return false;
    }

    public boolean isInArea(int i, int j) {
        if (i >= 0 && i < m && j >= 0 && j < n) {
            return true;
        }
        return false;
    }
}

括号生成

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且有效的括号组合。
示例 1:
输入:n = 3
输出:[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”]
示例 2:
输入:n = 1
输出:[“()”]

代码
这题不采用和之前一样的代码结构,采用选与不选的方法

class Solution {

    private int n;
    private char[] path ;
    private List<String> ans = new ArrayList<>();

    public List<String> generateParenthesis(int n) {
        this.n = n;
        path = new char[n * 2];
        dfs(0, 0);
        return ans;    
    }

    // 用选与不选的思路进行递归
    // i 是第 i 个位置, open是左括号的数量
    private void dfs(int i, int open) {
        if (i == 2 * n) {
            ans.add(new String(path));
            return;
        }
        // 左括号的数量<n ,说明还能继续添加左括号
        if (open < n) {
            path[i] = '(';
            dfs(i + 1, open + 1);  // 下次递归
        }
        // 位置 i 时,右括号的位置 < 左括号的位置,说明还能继续添加右括号(如果右括号>左括号就不合法了)
        if (i - open < open) {
            path[i] = ')';
            dfs(i + 1, open);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2267943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux-frp_0.61.1内网穿透的配置和使用

下载frp frp官网 https://gofrp.org/zh-cn/docs/setup/ frp安装包下载地址 https://github.com/fatedier/frp/releases?page1 下载之后在服务器上 解压 tar -zxvf frp_0.61.1_linux_amd64.tar.gztar&#xff1a;一个用于压缩和解压缩的工具。-z&#xff1a;表示使用 gzi…

WEB攻防-通用漏洞-文件上传-js验证-MIME验证-user.ini-语言特征

目录 定义 1.前端验证 2.MIME验证 3.htaccess文件和.user. ini 4.对内容进行了过滤&#xff0c;做了内容检测 5.[ ]符号过滤 6.内容检测php [] {} ; 7.()也被过滤了 8.反引号也被过滤 9.文件头检测 定义 文件上传漏洞是指攻击者上传了一个可执行文件&#xff08;如木马…

Excel基础知识

一&#xff1a;数组 一行或者一列数据称为一维数组&#xff0c;多行多列称为二维数组&#xff0c;数组支持算术运算&#xff08;如加减乘除等&#xff09;。 行&#xff1a;{1,2,3,4} 数组中的每个值用逗号分隔列&#xff1a;{1;2;3;4} 数组中的每个值用分号分隔行列&#xf…

快速下载pytorch_geometric

注意&#xff1a;千万不要一上去就使用pip去安装&#xff01;&#xff01;&#xff01; 1.找到GitHub手动下载所需依赖: https://github.com/pyg-team/pytorch_geometric 进入网址后点击此处&#xff1a; 2.点击here进去后寻找自己的torch版本&#xff08;我的是torch2.1.2的…

数学建模 绘图 图表 可视化(2)

文章目录 前言柱形图条形图克利夫兰点图系列坡度图南丁格尔玫瑰图径向柱图极坐标图词云图总结参考资料 前言 承接上期 数学建模 绘图 图表 可视化&#xff08;1&#xff09;的总体描述&#xff0c;这期我们继续跟随《Python 数据可视化之美 专业图表绘制指南》步伐来学习其中l…

建造者模式 Builder Pattern

在创建一个对象的时候&#xff0c;构造器参数有点多&#xff0c;而且有些参数还是可选的&#xff0c;再者还有不少同类型的&#xff0c;那就更应该使用 builder 模式了。 使用 Builder 模式的初衷是 把易变性&#xff08;mutability&#xff09;移动到Builder类&#xff0c;而…

【Java】IO流练习

IO流练习 题干&#xff1a; 根据指定要求&#xff0c;完成电话记录、 注册、登录 注册 题干&#xff1a; 完成【注册】功能&#xff1a; 要求&#xff1a; 用户输入用户名、密码存入users.txt文件中 若users.txt文件不存在&#xff0c;创建该文件若users.txt文件存在 输入…

计算机网络:应用层 —— 网络应用模式

文章目录 客户—服务器方式和对等方式客户/服务器方式 (C/S方式)工作流程特点 对等方式 (P2P方式)工作流程P2P 应用特点 客户—服务器方式和对等方式 网络应用程序运行在处于网络边缘的不同的端系统上&#xff0c;通过彼此间的通信来共同完成某项任务。 开发一种新的网络应用…

118.【C语言】数据结构之排序(堆排序和冒泡排序)

目录 1.堆排序 2.冒泡排序 单趟排序的两种情况 情况1.和arr[i]的前一个元素交换,第一次循环结束时i的值为n-1,第二次循环结束时i的值为n-2 情况2.和arr[i]的后一个元素交换,第一次循环结束时i的值为n-2,第二次第一次循环结束时i的值为n-3,... 将单趟排序代码嵌入外循环中…

【图像处理lec9】小波与多分辨率分析

目录 一、背景 1、引出小波变换 2、图像金字塔 &#xff08;1&#xff09;图像金字塔的基本概念 &#xff08;2&#xff09;高斯金字塔 &#xff08;3&#xff09;拉普拉斯金字塔 &#xff08;4&#xff09;金字塔的结构与生成框图 3、子带编码 &#xff08;1&#xf…

ubuntu2204 gpu 没接显示器,如何连接vnc

之前一直用ssh ,一直没接显示器&#xff0c;后来实在不方便&#xff0c;要安个vnc看一下&#xff0c;结果装上就黑了 硬件上&#xff1a;买一个HDMI显卡欺骗器插在设备上。 软件上&#xff1a;装一个虚拟显示器欺骗一下 sudo apt install xserver-xorg-coresudo apt install…

黑神话悟空游戏鼠标光标使用教程与下载

效果图&#xff1a; 鼠标光标特点 这套鼠标光标的设计灵感来源于《黑神话&#xff1a;悟空》游戏中的角色和元素&#xff0c;具有以下特点&#xff1a; • 主题鲜明&#xff1a;光标设计紧扣游戏主题&#xff0c;采用了游戏中的元素&#xff0c;让玩家在使用电脑时也能感受到…

32132132123

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

简述css中z-index的作用?如何用定位使用?

z-index是一个css属性&#xff0c;用于控制元素的堆叠顺序&#xff0c; 如何使用定位用index 1、position&#xff1a;relative&#xff1b; z-index&#xff1b; 相对于自己来定位的&#xff0c;可以根据top&#xff0c;bottom&#xff0c;right&#xff0c;left&#xff…

简单贪吃蛇小游戏的设计与实现

文章目录 1、知识预备1.1 WIN32 API1.1.1 什么是WIN32 API1.1.2 了解部分WIN32 API1.1.2.1 控制台坐标1.1.2.2 控制台光标1.1.2.3 获取键盘按键情况 2.1 宽字符2.1.1 C语言的国际化2.1.2 宽字符的打印 2、 贪吃蛇游戏设计2.1 游戏开始2.2 游戏运行2.2.1 更新分数2.2.2 按键检测…

mac中idea菜单工具栏没有git图标了

1.右击菜单工具栏 2.选中VCS&#xff0c;点击添加 3.搜索你要的工具&#xff0c;选中点击确定就添加了 4.回到上面一个界面&#xff0c;选中你要放到工具栏的工具&#xff0c;点击应用就好了 5.修改图标&#xff0c;快捷键或者右击选中编辑图标 6.选择你要的图标就好了

ElementPlus 自定义封装 el-date-picker 的快捷功能

文章目录 需求分析 需求 分析 我们看到官网上给出的案例如下&#xff0c;但是不太满足我们用户想要的快捷功能&#xff0c;因为不太多&#xff0c;因此需要我们自己封装一些&#xff0c;方法如下 外部自定义该组件的快捷内容 export const getPickerOptions () > {cons…

电子病历五级的Python编程基础实战

一、电子病历五级之路&#xff1a;机遇与挑战并存 在当今数字化医疗的浪潮下&#xff0c;电子病历五级成为医院迈向高质量发展的关键里程碑。它不仅象征着医院信息化建设的深度与广度&#xff0c;更是保障医疗服务质量、提升患者安全的核心要素。随着电子病历五级标准的深入推行…

VDA 学习手册

VDA&#xff08;Verband der Automobilindustrie&#xff0c;德国汽车工业联合会&#xff09;报文标准是专为汽车行业制定的电子数据交换&#xff08;EDI&#xff09;标准&#xff0c;用于支持供应链管理中的数据传输。它是由德国汽车工业联合会开发和维护的&#xff0c;广泛应…

cesium入门学习四

怎么加载地图效果文件&#xff0c;地图效果的显示。 学习总结&#xff1a; 1.cesium入门学习一-CSDN博客 2.cesium入门学习二-CSDN博客 3.cesium入门学习三-CSDN博客 1.怎么加载geojson文件&#xff0c;并在html中显示 1.1 geojson文件来源&#xff1a; DataV.GeoAtlas地理小…