代码随想录算法训练营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…

linux syscall和int 80的区别

前言 syscall和int 80是中断指令&#xff0c;Linux通过对这两个指令的封装为开发者们提供的一种用户态切换至内核态的方法&#xff0c;因为在处理器中用户态是没有权限向更高的权限空间切换的&#xff0c;以x86为例&#xff0c;它只允许高权限向低权限切换或同等权限切换&…

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.…

《梦醒蝶飞:释放Excel函数与公式的力量》23.2 项目评估与反馈

第23章&#xff1a;学生项目展示 23.2 项目评估与反馈 在学生项目展示中&#xff0c;项目评估与反馈是至关重要的一环。通过评估和反馈&#xff0c;可以识别项目中的优点和不足&#xff0c;帮助学生不断改进和提升。以下是项目评估与反馈的详细步骤和示例。 项目评估的关键要…

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

介绍 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;再使用分…

Kafka核心知识点整理,值得收藏!

消息队列应用场景 提高系统性能&#xff1a;通过异步处理减少响应时间。削峰/限流&#xff1a;应对高并发场景。降低系统耦合性&#xff1a;解耦生产者和消费者。 消息队列对比 Kafka&#xff1a;高吞吐量&#xff0c;适合日志收集和传输&#xff0c;适合大型公司。RocketMQ…

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 为用户提供了一个单一界面,用于控制和监控来自不同品牌的所有智能家居设备。它完全在本地网络上运行,而不是依赖云端,从而实现了最低的延迟、最高的…

深入理解CSS中的变量(应用篇)

在现代Web开发中,换肤功能已经成为提升用户体验的重要手段之一。通过使用CSS变量和JavaScript,我们可以轻松实现动态换肤功能。本文将介绍如何动态生成和应用CSS变量来实现换肤效果。 1. 定义基础CSS变量 首先,我们在CSS中定义一些基础的CSS变量。这些变量将用于存储不同主…

测试面试宝典(三十三)—— 接口测试有没有测试出什么问题?

在之前的接口测试工作中&#xff0c;确实发现了一些问题。比如&#xff0c;在对某关键业务接口进行测试时&#xff0c;发现当输入的参数值超出正常范围时&#xff0c;接口没有按照预期返回错误提示&#xff0c;而是出现了系统崩溃的情况。 还有一次&#xff0c;在测试一个数据…

关于任务栏设置闪退的一种解决方法

昨天我用了下360安全卫士&#xff0c;就发现我的任务栏变成了小任务栏模式。我想把它关掉&#xff0c;于是想要打开任务栏设置&#xff0c;然后就发现任务栏设置闪退。 我去晚上找了许多方法&#xff0c;像是卸载360&#xff0c;用指令修补破损文件&#xff0c;重启电脑等等&am…