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

回溯

    • 组合问题
    • 组合总和
    • 全排列
    • 子集
    • 分割回文串
    • 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 - 1for (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();  // 相当于pathpublic 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.mzph.cn/diannao/65482.shtml

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

相关文章

HEIC 是什么图片格式?如何把 iPhone 中的 HEIC 转为 JPG?

在 iPhone 拍摄照片时&#xff0c;默认的图片格式为 HEIC。虽然 HEIC 格式具有高压缩比、高画质等优点&#xff0c;但在某些设备或软件上可能存在兼容性问题。因此&#xff0c;将 HEIC 格式转换为更为通用的 JPG 格式就显得很有必要。本教程将介绍如何使用简鹿格式工厂&#xf…

【实战示例】面向对象的需求建模

前言 博主准备写一个以面向对象为核心思想的软件需求建模、领域建模的系列&#xff0c;总结一整套可落地的DDD的打法&#xff0c;前面几篇文章论述了如何进行面向对象的需求建模&#xff0c;本文将以一个简单的购物商城的需求来演示如何进行面向对象的需求建模。 面向对象的需…

04-微服务02

我们将黑马商城拆分为5个微服务&#xff1a; 用户服务 商品服务 购物车服务 交易服务 支付服务 由于每个微服务都有不同的地址或端口&#xff0c;相信大家在与前端联调的时候发现了一些问题&#xff1a; 请求不同数据时要访问不同的入口&#xff0c;需要维护多个入口地址…

Node.js 工具:在 Windows 11 中配置 Node.js 的详细步骤

一、概述 记录时间 [2024-12-25] 本文讲述如何在 Windows 11 中进行 Node.js 工具的安装和配置。 以下是详细的步骤和说明。 二、安装 Node.js 1. 官网下载 通过官网&#xff0c;下载 Node.js&#xff0c;上面有好几种下载方式&#xff0c;文中下载的是 zip 压缩包。 如图&…

Element-plus自动导入

安装 npm i element-plus 自动引入 1. 安装两个插件 npm install -D unplugin-vue-components unplugin-auto-import2. 配置插件 vue3项目修改vite.config.js&#xff0c;把两个插件添加入即可&#xff0c;注意:不是覆盖原有配置 Vite // vite.config.js import { define…

基于FISCO BCOS的电子签章系统

概述 本项目致力于构建一个安全、高效且功能完备的电子印章系统&#xff0c;通过整合区块链技术与传统数据库管理&#xff0c;为用户提供了可靠的电子签章解决方案&#xff0c;有效应对传统电子签章系统的数据安全隐患&#xff0c;满足企业和个人在数字化办公环境下对电子文档…

【2025最新计算机毕业设计】基于SpringBoot+Vue在线考试系统(源码包运行)【提供源码+答辩PPT+文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

如何设置Edge浏览器访问软件

使用Edge浏览器访问分销ERP A\V系列软件时会出现各种报错&#xff0c;如何设置Edge浏览器使其正常访问&#xff0c;请看下面的具体操作。 一、打开Edge浏览器&#xff0c;点击右上角的 设置及其他&#xff0c;如图&#xff1a; 二、在弹出界面中&#xff0c;点击 扩展&#xff…

[创业之路-222]:波士顿矩阵与GE矩阵在业务组合选中作用、优缺点比较

目录 一、波士顿矩阵 1、基本原理 2、各象限产品的定义及战略对策 3、应用 4、优点与局限性 二、技术成熟度模型与产品生命周期模型的配对 1、技术成熟度模型 2、产品生命周期模型 3、技术成熟度模型与产品生命周期模型的配对 三、产品生命周期与产品类型的对应关系 …

计算机图形学知识点汇总

一、计算机图形学定义与内容 1.图形 图形分为“图”和“形”两部分。 其中&#xff0c;“形”指形体或形状&#xff0c;存在于客观世界和虚拟世界&#xff0c;它的本质是“表示”&#xff1b;而图则是包含几何信息与属性信息的点、线等基本图元构成的画面&#xff0c;用于表达…

Tomcat介绍、下载安装、使用(部署项目)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

2024.12.29(进程线程实现并发服务器)

作业 多进程多线程并发服务器实现一遍提交。 服务器 #include <myhead.h> #define PORT 12345 #define IP "192.168.124.123"void *fun(void *fd) {int newfd *(int *)fd;char buff[1024];while(1){int res recv(newfd,buff,sizeof(buff),0);if(res 0){p…

初学STM32 ---高级定时器互补输出带死区控制

互补输出&#xff0c;还带死区控制&#xff0c;什么意思&#xff1f; 带死区控制的互补输出应用之H桥 捕获/比较通道的输出部分&#xff08;通道1至3&#xff09; 死区时间计算 举个栗子&#xff08;F1为例&#xff09;&#xff1a;DTG[7:0]250&#xff0c;250即二进制&#x…

brupsuite的基础用法常用模块(1)

proxy模块&#xff1a; Options: 设置代理端口&#xff0c;默认为8080端口&#xff0c;若8080端口被占用可在该界面更改代理端口. HTTP history: 拦截的历史请求&#xff0c;右键可做更多操作&#xff0c;很多操作与其他模块有关。&#xff08;清除历史的话右键选择clear p…

Linux 笔记 SELinux 常见操作与介绍

SELinux&#xff08;Security-Enhanced Linux&#xff09;是 Linux 操作系统中的一种安全模块&#xff0c;旨在提供更细粒度的访问控制。它最初由美国国家安全局&#xff08;NSA&#xff09;开发&#xff0c;目的是增强 Linux 系统的安全性。SELinux 通过强制访问控制&#xff…

Postman接口测试03|执行接口测试、全局变量和环境变量、接口关联、动态参数、断言

目录 七、Postman 1、安装 2、postman的界面介绍 八、Postman执行接口测试 1、请求页签 3、响应页签 九、Postman的环境变量和全局变量 1、创建环境变量和全局变量可以解决的问题 2、postman中的操作-全局变量 1️⃣手动设置 2️⃣代码设置 3️⃣界面获取 4️⃣代…

旅游管理系统|Java|SSM|VUE| 前后端分离

【技术栈】 1⃣️&#xff1a;架构: B/S、MVC 2⃣️&#xff1a;系统环境&#xff1a;Windowsh/Mac 3⃣️&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4⃣️&#xff1a;技术栈&#xff1a;Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库…

vulhub-wordpress靶场

一.主题上传漏洞 来到靶场点击主题选择add new 这里有一个上传主题的地方 我们可以去网上找到wordpress主题下载一个 wordpress模板 网页设计模板 免费 免费下载 - 爱给网 下载完成后对我们有用的东西只有这一个目录&#xff0c;把它拖出来 点开moban目录后&#xff0c;创建…

【人工智能视角下的计算机系统:硬件、操作系统与进程管理基础】

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 电脑硬件的基本常识电脑操作系统&#xff08;软件&#xff09;的基本常识进程进程操作PCB的属性PCB…

Flink源码解析之:如何根据算法生成StreamGraph过程

Flink源码解析之&#xff1a;如何根据算法生成StreamGraph过程 在我们日常编写Flink应用的时候&#xff0c;会首先创建一个StreamExecutionEnvironment.getExecutionEnvironment()对象&#xff0c;在添加一些自定义处理算子后&#xff0c;会调用env.execute来执行定义好的Flin…