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

代码随想录算法训练营二十二天|回溯part04

LeetCode 491 非递减子序列

题目链接:491. 非递减子序列 - 力扣(LeetCode)

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

示例 1:

输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]
示例 2:

输入:nums = [4,4,3,2,1]
输出:[[4,4]]

 这个递增子序列涉及到子集和去重,我们会想到90.子集II,但是在90.子集II中是通过排序,再加一个标记数组来达到去重的目的,但是本题,我们是不能对原数组进行排序的,所以不能使用90题的去重逻辑。

那怎么去重呢,可以定义一个集合set,只需要判断当前值在不在这个集合中就可以。如果在的话跳过;如果不在,继续往下进行。

其他没什么,直接套回溯模板就行,代码如下:

class Solution {List<List<Integer>> res = new ArrayList<List<Integer>>();List<Integer> list = new ArrayList<>();public List<List<Integer>> findSubsequences(int[] nums) {backtracking(nums, 0);return res;}public void backtracking(int[] arr, int startIndex) {if (list.size() >= 2) {res.add(new ArrayList<>(list));}Set<Integer> set=new HashSet<>();//当前层去重for (int i = startIndex; i < arr.length; i++) {if(set.contains(arr[i]))continue;if (list.isEmpty()||arr[i]>=list.get(list.size()-1)) {set.add(arr[i]);list.add(arr[i]);backtracking(arr, i + 1);list.remove(list.size() - 1);}}}
}

LeetCode 46 全排列

题目链接:46. 全排列 - 力扣(LeetCode)

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:

输入:nums = [1]
输出:[[1]]

 以[1,2,3]为例,抽象成树型结构如下:

引入一个used数组,标记已经选择的元素。

排列问题和之前的问题不同,它不需要引入startIndex参数,因为每层都是从0开始,这点需要注意。

代码如下:

class Solution {List<List<Integer>> res=new ArrayList<List<Integer>>();List<Integer> list=new ArrayList<>();public List<List<Integer>> permute(int[] nums) {boolean[] used=new boolean[nums.length];backtracking(nums,used);return res;}public void backtracking(int[] arr,boolean[] used){if(list.size()==arr.length){res.add(new ArrayList<>(list));}for(int i=0;i<arr.length;i++){if(used[i]==true)continue;list.add(arr[i]);used[i]=true;backtracking(arr,used);used[i]=false;list.remove(list.size()-1);}}
}

LeetCode 47 全排列II

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]
示例 2:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

 和全排列不同的是,需要去重,去重的逻辑和非递减子序列一样,引入一个集合set,直接看当前元素是否在set中即可。

其余和全排列一样,代码如下:

class Solution {List<List<Integer>> res=new ArrayList<List<Integer>>();List<Integer> list=new ArrayList<>();public List<List<Integer>> permuteUnique(int[] nums) {boolean[] used=new boolean[nums.length];backtracking(nums,used);return res;}public void backtracking(int[] arr,boolean[] used){if(list.size()==arr.length){res.add(new ArrayList<>(list));return;}Set<Integer> set=new HashSet<>();for(int i=0;i<arr.length;i++){if(set.contains(arr[i]))continue;if(used[i]==true)continue;set.add(arr[i]);list.add(arr[i]);used[i]=true;backtracking(arr,used);used[i]=false;list.remove(list.size()-1);}}
}

LeetCode 51 N皇后

题目链接:51. N 皇后 - 力扣(LeetCode)

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

示例 1:


输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:

输入:n = 1
输出:[["Q"]]

 递归函数参数:参数n:棋盘大小;参数row:当前遍历到棋盘的第几层;二维数组ch;

递归终止条件:row等于n时,棋盘递归到最底层,终止;

单层搜索的逻辑:

递归深度就是row控制的棋盘的行,每一层里的for循环的col控制棋盘的列,一行一列,确定放置皇后的位置。每次都要从新的一行的起始位置开始搜,所以都是从0开始。

for(int col=0;col<n;col++){if(isValid(row,col,n,ch)){ch[row][col]='Q';backtracking(n,row+1,ch);ch[row][col]='.';}}

isValid函数用来验证棋盘是否合法,按照如下标准:

  1. 不能同行
  2. 不能同列
  3. 不能同斜线 (45度和135度角)

代码如下:

public boolean isValid(int row,int col,int n,char[][] ch){for(int i=0;i<n;i++){//处在同一列if(ch[i][col]=='Q')return false;}for(int j=0;j<n;j++){//同一行if(ch[row][j]=='Q')return false;}for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){if(ch[i][j]=='Q')return false;}for(int i=row-1,j=col+1;i>=0&&j<=n-1;i--,j++){if(ch[i][j]=='Q')return false;}return true;}

其实同行的检查可以去掉,因为在单层的搜索过程中,每一层递归,只会选for循环里的一个元素,也就是同一行的一个元素,所以不需要去重。

注意最后函数返回的是list,所以还需要把二维数组转化为list:

 public List<String> ArrayToList(char[][] ch){List<String> list=new ArrayList<>();for(char[] c:ch){list.add(String.valueOf(c));}return list;}

 整体代码如下:

class Solution {List<List<String>> res=new ArrayList<List<String>>();public List<List<String>> solveNQueens(int n) {char[][] ch=new char[n][n];for(int i=0;i<n;i++){for(int j=0;j<n;j++){ch[i][j]='.';}}backtracking(n,0,ch);return res;}public void backtracking(int n,int row,char[][] ch){if(row==n){res.add(ArrayToList(ch));return;}for(int col=0;col<n;col++){if(isValid(row,col,n,ch)){ch[row][col]='Q';backtracking(n,row+1,ch);ch[row][col]='.';}}}public List<String> ArrayToList(char[][] ch){List<String> list=new ArrayList<>();for(char[] c:ch){list.add(String.valueOf(c));}return list;}public boolean isValid(int row,int col,int n,char[][] ch){for(int i=0;i<n;i++){//处在同一列if(ch[i][col]=='Q')return false;}for(int j=0;j<n;j++){//同一行if(ch[row][j]=='Q')return false;}for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){if(ch[i][j]=='Q')return false;}for(int i=row-1,j=col+1;i>=0&&j<=n-1;i--,j++){if(ch[i][j]=='Q')return false;}return true;}
}

LeetCode 37 解数独

题目链接:37. 解数独 - 力扣(LeetCode)

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则:

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.' 表示。

示例 1:


输入:board = [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]]
输出:[["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8"],["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"],["4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"],["9","6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"],["3","4","5","2","8","6","1","7","9"]]
解释:输入的数独如上图所示,唯一有效的解决方案如下所示:

递归函数的参数:二维数组ch。

返回值:类型是boolean,这是因为解数独找到一个符合的条件立刻就返回,所以需要使用boolean返回值。

递归函数的终止条件:不需要,因为当数组填满的时候就终止了。

单层搜索的逻辑:

 一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,递归遍历这个位置放9个数字的可能。

public boolean backtracking(char[][] ch){for(int i=0;i<ch.length;i++){for(int j=0;j<ch[0].length;j++){if(ch[i][j]!='.')continue;for(char k='1';k<='9';k++){if(isValid(i,j,k,ch)){ch[i][j]=k;if(backtracking(ch))return true;ch[i][j]='.';}}return false;//9个数都试完了,都不行}}return true;}

判断棋盘是否合法: 

  • 同行是否重复
  • 同列是否重复
  • 9宫格里是否重复
public boolean isValid(int row,int col,char k,char[][] ch){for(int i=0;i<9;i++){if(ch[i][col]==k)return false;}for(int j=0;j<9;j++){if(ch[row][j]==k)return false;}int startRow=(row/3)*3;int startCol=(col/3)*3;for(int i=startRow;i<startRow+3;i++){for(int j=startCol;j<startCol+3;j++){if(ch[i][j]==k)return false;}}return true;}

整体代码如下: 

class Solution {public void solveSudoku(char[][] board) {backtracking(board);}public boolean backtracking(char[][] ch){for(int i=0;i<ch.length;i++){for(int j=0;j<ch[0].length;j++){if(ch[i][j]!='.')continue;for(char k='1';k<='9';k++){if(isValid(i,j,k,ch)){ch[i][j]=k;if(backtracking(ch))return true;ch[i][j]='.';}}return false;//9个数都试完了,都不行}}return true;}public boolean isValid(int row,int col,char k,char[][] ch){for(int i=0;i<9;i++){if(ch[i][col]==k)return false;}for(int j=0;j<9;j++){if(ch[row][j]==k)return false;}int startRow=(row/3)*3;int startCol=(col/3)*3;for(int i=startRow;i<startRow+3;i++){for(int j=startCol;j<startCol+3;j++){if(ch[i][j]==k)return false;}}return true;}
}
http://www.lryc.cn/news/595450.html

相关文章:

  • 关于线程的例子
  • 【力扣】第42题:接雨水
  • 复制docker根目录遇到的权限问题
  • 模拟高负载测试脚本
  • 闲庭信步使用图像验证平台加速FPGA的开发:第二十八课——图像膨胀的FPGA实现
  • 关于Ajax的学习笔记
  • Linux的相关指令
  • 「日拱一码」034 机器学习——插值处理
  • Unity 脚本生命周期详解与实战分析
  • (十九)深入了解 AVFoundation-编辑:使用 AVMutableVideoComposition 实现视频加水印与图层合成(上)——理论篇
  • iOS 加固工具有哪些?快速发布团队的实战方案
  • RIQ模型时间管理方法详解
  • 工业自动化中的协议转换:RS485转PROFIBUS网关在涡街流量计与S7-300 PLC通信中的应用
  • Swap Face 使用遇到的问题
  • Match宣布2025曼谷发布会,发布“保本”资管新范式,旨在重塑Web3投资规则
  • 20250720问答课题-基于BERT与混合检索问答系统代码解读
  • 企业开发转型 | 前端AI化数字化自动化现状
  • 自动化商品监控:利用淘宝API开发实时价格库存采集接口
  • 【unitrix】 6.11 二进制数字标准化模块(normalize.rs)
  • G7打卡——Semi-Supervised GAN
  • Acrobat JavaScript 中的 `app.response()` 方法
  • 【学习路线】C#企业级开发之路:从基础语法到云原生应用
  • 基于MySQL实现分布式调度系统的选举算法
  • 一文速通《矩阵的特征值和特征向量》
  • Tomcat的部署、单体架构、session会话、spring
  • PostgreSQL高可用架构Repmgr部署流程
  • 计算机网络中:传输层和网络层之间是如何配合的
  • socket编程(UDP)
  • vue2使用v-viewer图片预览:打开页面自动预览,禁止关闭预览,解决在微信浏览器的页面点击事件老是触发预览初始化的问题
  • Linux 721 创建实现镜像的逻辑卷