当前位置: 首页 > 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.dtcms.com/a/290648.html

相关文章:

  • 第十八节:第八部分:java高级:动态代理设计模式介绍、准备工作、代码实现
  • 【设计模式C#】简单工厂模式(用于简化获取对象实例化的复杂性)
  • Spring Boot注解详解
  • PDF 表单字段属性详解
  • 泛型:C#中的类型抽象艺术
  • 三款适合户外探险、应急救援的智能三防手机,各有各的优势
  • kafka 日志索引 AbstractIndex
  • Elasticsearch X-Pack安全功能未启用的解决方案
  • 模型系列(篇一)-Bert
  • 暑期算法训练.5
  • 分布在内侧内嗅皮层(MEC)的带状细胞对NLP中的深层语义分析有什么积极的影响和启示
  • [硬件电路-64]:模拟器件 -二极管在稳压电路中的应用
  • Facebook 开源多季节性时间序列数据预测工具:Prophet 乘性季节性 Multiplicative Seasonality
  • JS实现矩阵左右旋转90度
  • uniapp app pdf.js报错:Uncaught SyntaxError:Unexpected token ‘{‘
  • 5道挑战题writup
  • 单体VS微服务:如何选择最适合的架构?
  • 人工智能之数学基础:事件间的关系
  • Leetcode力扣解题记录--第189题(巧思数组翻转)
  • 【MySQL】Linux配置MySQL Windows远程连接
  • 客流分析核心算法 trajectory_event_analyzer数据结构
  • Python-数据库概念-pymysql-元编程-SQLAlchemy-学习笔记
  • QT6 源,七章对话框与多窗体(5) 文件对话框 QFileDialog 篇二:源码带注释
  • 【React】npm install报错npm : 无法加载文件 D:\APP\nodejs\npm.ps1,因为在此系统上禁止运行脚本。
  • 玩转Rocky Linux 9 部署Redis指南
  • WPF实现加载初始页面后跳转到主界面并销毁初始页面资源
  • 在 WPF 启动界面中心加载 GIF 动图
  • 人工智能真的能编程吗?研究勾勒出自主软件工程的障碍
  • Next.js 知识点
  • 【c++】leetcode438 找到字符串中所有字母异位词