代码随想录算法训练营day25 | 491.递增子序列 、46.全排列 、47.全排列 II、51.N皇后、37.解数独

碎碎念:加油加油,继续坚持
参考:代码随想录

491.递增子序列

题目链接

491.递增子序列

思想

注意结果中不能有重复的子集。
不能排序后处理,因为进行排序以后改变元素顺序,求的递增子序列会改变。

树形图:
在这里插入图片描述
结果分布在节点上,只是对节点里面的数字有些要求。

定义一个一维数组path,一个二维数组result。
一进来递归的时候就收集结果:如果path.size>1,就把当前path放到result中。
定义一个set,用来判断当前取到的数之前是否取过。【之前的90.子集II 用的是used数组,因为之前的题目我们可以用排序使得相同的数字相邻,这里不能用排序了,因为排序会改变递增子序列】
回溯三部曲:

  1. 参数和返回值:参数有nums,startIndex
  2. 终止条件:如果startIndex>=nums.size
  3. 单层搜索逻辑:for循环,i从startIndex开始,如果当前取的数小于子集里最右面的元素(对path为空做一个判断)或者uset里存在了当前取的数,continue。
    用uset记录一下当前取的数,把要取的数放入path,递归(i+1),把之前加入的数取出来。【为什么没有回溯uset的值呢,因为本层定义的uset只记录本层的情况,进入下一层会重新定义一个uset】

题解

// cpp 
class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& nums, int startIndex) {if (path.size() > 1){result.push_back(path);}unordered_set<int> uset;for (int i = startIndex; i < nums.size(); i++) {if (!path.empty() && nums[i] < path.back() || uset.find(nums[i])!= uset.end()) continue;uset.insert(nums[i]);path.push_back(nums[i]);backtracking(nums, i+1);path.pop_back();}}
public:vector<vector<int>> findSubsequences(vector<int>& nums) {backtracking(nums, 0);return result;}
};
# python 用数组模拟set
class Solution:def __init__(self):self.path = []self.result = []def backtracking(self, nums, startIndex):if len(self.path) > 1:self.result.append(self.path[:])used = [0] * 201for i in range(startIndex, len(nums)):if (self.path and nums[i] < self.path[-1] or used[nums[i] + 100] == 1):continueused[nums[i] + 100] = 1self.path.append(nums[i])self.backtracking(nums, i+1)# used[nums[i] + 100] = 0 不用写了 因为每一层都会定义一个新uesdself.path.pop()def findSubsequences(self, nums: List[int]) -> List[List[int]]:self.backtracking(nums, 0)return self.result

反思

注意思考为什么不用排序+used数组,注意思考为什么单层搜索逻辑不用回溯uset。
这种用set去重的方法在之前提到的题目如90.子集II 也可以使用。
本题的set也可以用数组模拟。

46.全排列

题目链接

46.全排列

思想

本题没有重复的元素,那么就不用考虑去重。
排列和组合的区别:[2,1]和[1,2]是同一个组合,但是是不同的排列。排列是强调元素顺序的。
这里用used数组来标记哪个元素使用过了。【组合类问题用startIndex来防止重复取】

树形图:
在这里插入图片描述

定义一个一维数组path,一个二维数组result。
回溯三部曲:

  1. 参数和返回值:参数是nums和uesd数组
  2. 终止条件:如果path的长度和nums的长度相等的时候,收获结果,return
  3. 单层搜索逻辑:for循环,i从0开始 ,如果used[i]==true,coutinue。修改used数组,把取的数字加入path,进入下一层递归,把数字取出,修改used。

题解

// cpp
class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& nums, vector<bool>& used) {if (path.size() == nums.size()) {result.push_back(path);return;}for (int i = 0 ; i < nums.size(); i++) {if (used[i] == true) continue;used[i] = true;path.push_back(nums[i]);backtracking(nums, used);path.pop_back();used[i] = false;}}
public:vector<vector<int>> permute(vector<int>& nums) {vector<bool> used(nums.size(), false);backtracking(nums, used);return result;}
};
# python
class Solution:def backtracking(self, nums, used, path, result):if len(path) == len(nums):result.append(path[:])returnfor i in range(0, len(nums)):if used[i] == True:continueused[i] = Truepath.append(nums[i])self.backtracking(nums, used, path, result)path.pop()used[i] = Falsedef permute(self, nums: List[int]) -> List[List[int]]:path = []result = []used = [False] * len(nums)self.backtracking(nums, used, path, result)return result

反思

注意和组合最大的区别在于for循环从0开始,而不是从startIndex开始。

47.全排列 II

题目链接

47.全排列 II

思想

本题和上一题的区别:本题给的集合有重复元素,而题目有要求给出的排列不重复,所以关键点在于去重。

树形图:
在这里插入图片描述

在主函数里要做一下排序,方便去重。
used数组用来标记排列里用了哪些元素。
定义一个一维数组path,一个二维数组result。
回溯三部曲:

  1. 参数和返回值:参数是nums和uesd数组
  2. 终止条件:如果path的长度和nums的长度相等的时候,收获结果,return
  3. 单层搜索逻辑:for循环,i从0开始,如果i>0且当前数字和前一个数字相等且used[i-1]为false(说明在树层上),continue。【去重】 如果used[i]==true,coutinue【防止元素重复使用】。修改used数组,把取的数字加入path,进入下一层递归,把数字取出,修改used【回溯】。

题解

// cpp
class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& nums, vector<bool>& used) {if (path.size() == nums.size()) {result.push_back(path);return;}for (int i = 0; i < nums.size(); i++) {if (i > 0 && nums[i] == nums[i - 1] && used[i-1] == false) continue;if (used[i] == true) continue;used[i] = true;path.push_back(nums[i]);backtracking(nums, used);path.pop_back();used[i] = false;}}
public:vector<vector<int>> permuteUnique(vector<int>& nums) {sort(nums.begin(), nums.end());vector<bool> used(nums.size(), false);backtracking(nums, used);return result;}
};
# python
class Solution:def backtracking(self, nums, uesd, path, result):if len(nums) == len(path):result.append(path[:])returnfor i in range(0, len(nums)):if i > 0 and nums[i] == nums[i - 1] and uesd[i-1] == False:continueif uesd[i] == True:continueuesd[i] = Truepath.append(nums[i])self.backtracking(nums, uesd, path, result)path.pop()uesd[i] = Falsedef permuteUnique(self, nums: List[int]) -> List[List[int]]:path = []result = []uesd = [False] * len(nums)self.backtracking(nums, uesd, path, result)return result

反思

树层去重效率更高,剪枝能剪掉更多。

51.N皇后

题目链接

51.N皇后

思想

树形图:
在这里插入图片描述
定义一个三维数组result。
回溯三部曲:

  1. 参数和返回值:传入棋盘,棋盘大小,row(行数)
  2. 终止条件:如果row==n,收获结果到结果集,return
  3. 单层搜索逻辑:for循环,i从0开始,判断棋盘是否合法(用一个isValid函数判断),如果合法,在row,i位置上放皇后,进入下一层递归(row+1),把row,i位置上的皇后拿走(回溯)。

isValid函数:返回值是bool类型,参数有row,i,棋盘,棋盘大小。
验证标准:不能同行,不能同列,不能同斜线(45度和135度)。

题解

// cpp
class Solution {
private:vector<vector<string>> result;void backtracking(int n, int row, vector<string>& chessboard) {if (row == n) {result.push_back(chessboard);return;}for (int col = 0; col < n; col++) {if (isValid(row, col, chessboard, n)){chessboard[row][col] = 'Q';backtracking(n, row + 1, chessboard);chessboard[row][col] = '.';}}}bool isValid(int row, int col, vector<string>& chessboard, int n) {for (int i = 0; i < n; i++) {if (chessboard[i][col] == 'Q') return false;}for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {if (chessboard[i][j] == 'Q') return false;}for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {if (chessboard[i][j] == 'Q') return false;}return true;}
public:vector<vector<string>> solveNQueens(int n) {std::vector<std::string> chessboard(n, std::string(n, '.'));backtracking(n, 0, chessboard);return result;}
};
# python
class Solution:def isValid(self, row, col, chessboard, n):for i in range(row):if chessboard[i][col] == 'Q':return Falsei, j = row - 1, col - 1while i >= 0 and j >= 0:if chessboard[i][j] == 'Q':return Falsej -= 1i -= 1i, j = row - 1, col + 1while i >= 0 and j < n:if chessboard[i][j] == 'Q':return Falsei -= 1j += 1return Truedef backtracking(self, n, row, chessboard, result):if row == n:result.append(chessboard[:])returnfor col in range(n):if self.isValid(row, col, chessboard, n):chessboard[row] = chessboard[row][:col] + 'Q' + chessboard[row][col+1:]self.backtracking(n, row + 1, chessboard, result)chessboard[row] = chessboard[row][:col] + '.' + chessboard[row][col+1:]def solveNQueens(self, n: int) -> List[List[str]]:result = []chessboard = ['.' * n for _ in range(n)]self.backtracking(n, 0, chessboard, result)return result

反思

在给出的代码中没有对同行进行检查,因为在单层的搜索过程中,每一层递归只会选择同一行里的一个元素,不用进行去重。

37.解数独

题目链接

37.解数独

思想

本题需要两个for循环+递归,一个for循环遍历行,一个for循环遍历列,递归来枚举9个数字。
在这里插入图片描述
图解来自 代码随想录

回溯三部曲:

  1. 参数和返回值:返回值是bool类型的(找到一个结果就立刻返回),参数是棋盘
    两层for循环,遍历棋盘中的每一个位置。
  2. 终止条件:不用特意写了。
  3. 单层搜索逻辑:遇到“.”开始处理,遍历1~9(字符类型的),判断在该位置放入数字后是否合法【用isValid判断】,如果合法,把数字放入数独。进入下一层递归,注意用result接一下返回值,如果result为true,返回true【找到结果了立刻return】。把数独改回去【回溯】。如果1-9都不合法,return false。直到把棋盘填满,return true。

isValid的实现:
判断是否合法的三个维度:同行是否重复;同列是否重复;九宫格内是否重复。

题解

// cpp
class Solution {
private:bool isValid(int row, int col, char val, vector<vector<char>>& board) {for (int j = 0; j < 9; j++) {if (board[row][j] == val) return false;}for (int i = 0; i < 9; i++) {if (board[i][col] == val) 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 (board[i][j] == val) return false;}}return true;}bool backtracking(vector<vector<char>>& board) {for (int i = 0; i < board.size(); i++) {for (int j = 0; j < board[0].size(); j++) {if (board[i][j] == '.') {for (char k = '1'; k <= '9'; k++) {if (isValid(i, j, k, board)) {board[i][j] = k;if (backtracking(board)) return true;board[i][j] = '.';}}return false;}}}return true;}
public:void solveSudoku(vector<vector<char>>& board) {backtracking(board);}
};
# python
class Solution:def backtracking(self, board):for i in range(len(board)):for j in range(len(board[0])):if board[i][j] == '.':for k in range(1, 10):if self.isValid(i, j, k, board):board[i][j] = str(k)if self.backtracking(board):return Trueboard[i][j] = '.'return Falsereturn Truedef isValid(self, row, col, val, board):for j in range(9):if board[row][j] == str(val):return Falsefor i in range(9):if board[i][col] == str(val):return FalsestartRow = int(row / 3) * 3startCol = int(col / 3) * 3for i in range(startRow, startRow + 3):for j in range(startCol, startCol + 3):if board[i][j] == str(val):return Falsereturn Truedef solveSudoku(self, board: List[List[str]]) -> None:"""Do not return anything, modify board in-place instead."""self.backtracking(board)

反思

注意本题的递归函数的返回值是bool,之前我们遇到的回溯问题大多是void,因为之前需要搜索所有的节点,拿到所有的结果,而本题我们找到一个符合要求的结果就可以返回了,返回的bool类型数据可以作为找到结果的标记。
本题在N皇后的区别在于,和N皇后差了一个维度。
注意backtracking在哪里return,return什么很重要,容易弄错。
注意如何计算九宫格的起始行和起始列。

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

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

相关文章

大模型金九银十秋招:AI时代的就业新趋势,收藏我这篇就够了非常详细

随着人工智能技术的飞速发展&#xff0c;大模型&#xff08;Large Models&#xff09;在各个领域的应用日益广泛&#xff0c;从自然语言处理到图像识别&#xff0c;从自动驾驶到智能推荐系统&#xff0c;大模型正逐渐成为AI领域的新宠。在这个背景下&#xff0c;大模型的秋招&a…

sizeof和strlen区别

如图&#xff0c;sizeof来计算的时候&#xff0c;得出的是计算机用多少个字节来表示一个地址 而strlen来计算的时候&#xff0c;只是计算出他的有效字符长度 打印出的不同地址就是其不同的区别

Visual Studio 智能代码插件:Fitten Code

Fitten Code 是由非十大模型驱动的AI编程助手&#xff0c;它可以自动生成代码&#xff0c;提升开发效率&#xff0c;协助调试 Bug&#xff0c;节省时间。还可以对话聊天&#xff0c;解决编程碰到的问题。 Fitten Code 免费且多种编程语言&#xff0c;包括 Python、C、Javascri…

Python 爬虫入门(一):从零开始学爬虫 「详细介绍」

Python 爬虫入门&#xff08;一&#xff09;&#xff1a;从零开始学爬虫 「详细介绍」 前言1.爬虫概念1.1 什么是爬虫&#xff1f;1.2 爬虫的工作原理 2. HTTP 简述2.1 什么是 HTTP&#xff1f;2.2 HTTP 请求2.3 HTTP 响应2.4 常见的 HTTP 方法 3. 网页的组成3.1 HTML3.2 CSS3.…

数据分析:微生物数据的荟萃分析框架

介绍 Meta-analysis of fecal metagenomes reveals global microbial signatures that are specific for colorectal cancer提供了一种荟萃分析的框架&#xff0c;它主要基于常用的Wilcoxon rank-sum test和Blocked Wilcoxon rank-sum test 方法计算显著性&#xff0c;再使用分…

SpringBoot启动命令过长

Error running DromaraApplication: Command line is too long. Shorten command line for DromaraApplication or also for Spring Boot default configuration?

线上环境服务器CPU飙升排查

前因 收到线上服务器CPU使用率100%的告警信息。 环境 jdk1.8CentOS Linux &#xff1b;CentOS Linux 排查 查看服务器CPU使用率 果然cpu已经达到了100%了 命令 top 使用arthas工具 使用方式 arthas 执行命令java -jar arthas-boot.jar 然后执行命令 thread 看到有两个…

【linux】Shell脚本三剑客之awk命令的详细用法攻略

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

【基础教程】Tutorial on Pytorch 结合官方基础文档和个人经验

参考与前言 此教程首次书写于2021年12月份 至 2022年4月份间不断补充&#xff1b;阅读本文时可以对着代码运行查看 官方网址&#xff1a;https://pytorch.org/tutorials/ 【基本从这里翻译而来 更简洁版碎碎念】https://pytorch.org/tutorials/beginner/blitz/cifar10_tutori…

vue3+element-plus 实现动态菜单和动态路由的渲染

在 Vue.js 中&#xff0c;使用 Vue Router 管理路由数据&#xff0c;并将其用于渲染 el-menu&#xff08;Element UI 的菜单组件&#xff09;通常涉及以下几个步骤&#xff1a; 定义路由元数据&#xff1a; 在你的路由配置中&#xff0c;为每个路由项添加 meta 字段&#xff0c…

无人机10公里WiFi图传摄像模组,飞睿智能超清远距离无线监控,智能安防新潮流

在这个科技日新月异的时代&#xff0c;我们对影像的捕捉和传播有了更高的要求。从传统的有线传输到无线WiFi图传&#xff0c;每一次技术的飞跃都为我们带来了全新的视觉体验。今天&#xff0c;我们要探讨的&#xff0c;正是一款具有划时代意义的科技产品——飞睿智能10公里WiFi…

自学网络安全,从小白到大神的破茧之路!

在当今数字化高速发展的时代&#xff0c;网络安全已经成为了至关重要的领域。无论是个人的隐私保护&#xff0c;还是企业、国家的关键信息资产维护&#xff0c;都离不开网络安全的有力保障。出于对这一领域的浓厚兴趣以及对未来职业发展的清晰规划&#xff0c;我毅然决然地踏上…

0722_驱动1 字符设备驱动框架

一、字符设备驱动框架 字符设备驱动按照字节流进行访问&#xff0c;并且只能顺序访问 设备号一共有32位&#xff0c;主设备号&#xff08;高12位&#xff09;次设备号&#xff08;低20位&#xff09; 二、注册/注销字符设备驱动API接口 2.1、注册字符设备驱动(入口) #include &…

树莓派智能家居中枢

一个先进的枢纽&#xff0c;使智能家居系统更智能、更可定制、更易于控制 Homey Pro由树莓派 Compute Module 4 供电,Homey Pro 为用户提供了一个单一界面,用于控制和监控来自不同品牌的所有智能家居设备。它完全在本地网络上运行,而不是依赖云端,从而实现了最低的延迟、最高的…

docker发布镜像到自己远程私有仓库

1、登录docker hub创建自己的仓库地址&#xff1a;https://hub.docker.com/repository/create 输入仓库名称 2.构建镜像 略过。。。。请自己查找别的资料&#xff0c;此篇文章只讲述镜像推送到远程 3.推送 假设你已经构建了一个镜像 web/online-editor:latest&#xff0c;现…

推荐系统三十六式学习笔记:工程篇.常见架构25|Netflix个性化推荐架构

目录 架构的重要性经典架构1.数据流2.在线层3.离线层4.近线层 简化架构总结 你是否曾经觉得算法就是推荐系统的全部&#xff0c;即便不是全部&#xff0c;至少也是嫡长子&#xff0c;然而实际上&#xff0c;工程实现才是推荐系统的骨架。如果没有好的软件实现&#xff0c;算法不…

树 ----- 基础学习

树 树&#xff1a;n&#xff08;n>0&#xff09;个结点的有限集合。n 0 ,空树。 在任意一个非空树中&#xff0c; 1&#xff0c;有且仅有一个特定的根结点 2&#xff0c;当n>1 时&#xff0c;其余结点可分为m个互不相交的有限集合T1,T2,T3.。。。。Tm&#xff0c;其中每…

如何利用业余时间做副业,在家里赚钱,来增加收入

人一生每个阶段都会有压力和烦恼&#xff0c;中年人更是如此。 上有老下有小&#xff0c;生活的重担都在一个人身上&#xff0c;压得人喘不过气&#xff0c;这些都需要钱&#xff0c;仅靠工资已经很难维持一家人的开支了。 所以很多人打算利用业余时间做副业&#xff0c;来增加…

Pycharm软件Win 64位安装包+详细安装步骤 百度云

如大家所掌握的&#xff0c;Pycharm是一款集成开发环境&#xff08;IDE&#xff09;&#xff0c;专门用于python语言开发的工具。作为一款功能强大的IDE&#xff0c;Pycharm提供了丰富的功能和工具&#xff0c;使得python开发变得更加高效和便捷。 Pycharm常用场景如下&#x…

Delphi5实现鱼C屏幕保护程序

效果图 鱼C屏幕保护程序 添加背景图片 在additional添加image组件&#xff0c;修改picture属性上传图片。 这个图片可以截屏桌面&#xff0c;方便后面满屏不留白操作。实现无边框 即上面的“- □ ”不显示 将Form1的borderstyle属性改为bsnone实现最大化&#xff0c;满屏 将…