代码随想录算法训练营第二十九天| 491.递增子序列 46.全排列 47.全排列 II
1.代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素。2.代码随想录算法训练营第二天|977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II3.代码随想录算法训练营第三天| 203.移除链表元素,707.设计链表 ,206.反转链表4.代码随想录算法训练营第四天| 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 142.环形链表II5.代码随想录算法训练营第六天| 哈希表理论基础 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和6.代码随想录算法训练营第七天| 454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和7.代码随想录算法训练营第八天| 344.反转字符串 541. 反转字符串II 卡码网:54.替换数字 151.翻转字符串里的单词 卡码网:55.右旋转字符串8.代码随想录算法训练营第九天| 28. 实现 strStr() 459.重复的子字符串 字符串总结 双指针回顾9.代码随想录算法训练营第十天| 堆栈理论基础 232.用栈实现队列 225. 用队列实现栈10.代码随想录算法训练营第十一天| 20. 有效的括号 1047. 删除字符串中的所有相邻重复项 150. 逆波兰表达式求值11.代码随想录算法训练营第十三天|239. 滑动窗口最大值 347.前 K 个高频元素 总结12.代码随想录算法训练营第十四天| 理论基础 递归遍历 迭代遍历 统一迭代13.代码随想录算法训练营第十五天| 层序遍历 10 226.翻转二叉树 101.对称二叉树 214.代码随想录算法训练营第十六天| 104.二叉树的最大深度 559.n叉树的最大深度 111.二叉树的最小深度 222.完全二叉树的节点个数15.代码随想录算法训练营第十七天| 110.平衡二叉树 257. 二叉树的所有路径 404.左叶子之和16.代码随想录算法训练营第十八天|● 513.找树左下角的值 ● 112. 路径总和 113.路径总和ii ● 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树17.代码随想录算法训练营第十九天|654.最大二叉树 ● 617.合并二叉树 ● 700.二叉搜索树中的搜索 ● 98.验证二叉搜索树18.代码随想录算法训练营第二十天|530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● 236. 二叉树的最近公共祖先19.代码随想录算法训练营第二十二天|235. 二叉搜索树的最近公共祖先 ● 701.二叉搜索树中的插入操作 ● 450.删除二叉搜索树中的节点20.代码随想录算法训练营第二十三天|669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树 ● 总结篇21.代码随想录算法训练营第二十四天|● 理论基础 ● 77. 组合22.代码随想录算法训练营第二十五天| 216.组合总和III 17.电话号码的字母组合23.代码随想录算法训练营第二十六天| 39. 组合总和 40.组合总和II 131.分割回文串24.代码随想录算法训练营第二十七天| 93.复原IP地址 78.子集 90.子集II
25.代码随想录算法训练营第二十九天| 491.递增子序列 46.全排列 47.全排列 II
26.代码随想录算法训练营第三十天|回溯法总结27.代码随想录算法训练营第三十一天| 理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和28.代码随想录算法训练营第三十二天| ● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II29.代码随想录算法训练营第三十三天| ● 1005.K次取反后最大化的数组和 ● 134. 加油站 ● 135. 分发糖果30.代码随想录算法训练营第三十四天| ● 860.柠檬水找零 ● 406.根据身高重建队列 ● 452. 用最少数量的箭引爆气球31.代码随想录算法训练营第三十六天| ● 435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间32.代码随想录算法训练营第三十七天| ● 738.单调递增的数字 ● 968.监控二叉树 ● 总结33.代码随想录算法训练营第三十八天| ● 理论基础 ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯34.代码随想录算法训练营第三十九天|● 62.不同路径 ● 63. 不同路径 II35.代码随想录算法训练营第四十天|● 343. 整数拆分 ● 96.不同的二叉搜索树36.代码随想录算法训练营第四十一天|01背包问题, 01背包问题—— 滚动数组,分割等和子集37.代码随想录算法训练营第四十三天|● 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零38.代码随想录算法训练营第四十四天|完全背包 ● 518. 零钱兑换 II ● 377. 组合总和 Ⅳ39.代码随想录算法训练营第四十五天| ● 70. 爬楼梯 (进阶) ● 322. 零钱兑换 ● 279.完全平方数40.代码随想录算法训练营第四十六天| 139.单词拆分 多重背包 背包问题总结篇!41.代码随想录算法训练营第四十七天| ● 198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III42.代码随想录算法训练营第四十八天| ● 121. 买卖股票的最佳时机 ● 122.买卖股票的最佳时机II43.代码随想录算法训练营第五十天| ● 123.买卖股票的最佳时机III ● 188.买卖股票的最佳时机IV44.代码随想录算法训练营第五十一天| ● 309.最佳买卖股票时机含冷冻期 ● 714.买卖股票的最佳时机含手续费 ●总结45.代码随想录算法训练营第五十二天| ● 300.最长递增子序列 ● 674. 最长连续递增序列 ● 718. 最长重复子数组46.代码随想录算法训练营第五十三天| ● 1143.最长公共子序列 ● 1035.不相交的线 ● 53. 最大子序和 动态规划47.代码随想录算法训练营第五十四天| ● 392.判断子序列 ● 115.不同的子序列48.代码随想录算法训练营第五十五天| ● 583. 两个字符串的删除操作 ● 72. 编辑距离 ● 编辑距离总结篇49.代码随想录算法训练营第五十七天| 九章 动态规划part17 ● 647. 回文子串 ● 516.最长回文子序列 ● 动态规划总结篇50.代码随想录算法训练营第五十八天|● 739. 每日温度 ● 496.下一个更大元素 I51.代码随想录算法训练营第五十九天|● 503.下一个更大元素II ● 42. 接雨水52.代码随想录算法训练营第六十天|● 84.柱状图中最大的矩形53.每日一题: 2192. 有向无环图中一个节点的所有祖先54.每日一题:1026. 节点与其祖先之间的最大差值55.每日一题:1483. 树节点的第 K 个祖先491.递增子序列
题目链接:491. 非递减子序列 - 力扣(LeetCode)
思路:一开始一直报访问异常的错误,最后只好参考官网答案,结果竟然是因为我递归参数写错了导致程序一直出问题???(⊙︿⊙)
这里去重用的是标记数组,可以用集合unordered_set,但由于本题数据范围比较小,所以我们可以用数组更加高效的解决。
class Solution {
public:
vector<vector<int>>result;
vector<int>path;
void backtracking(vector<int> nums,int start){
if(path.size()>1){
result.push_back(path);
}
int use[201]={0};
for(int i=start;i<nums.size();i++){
if((!path.empty()&&path.back()>nums[i])
||use[nums[i]+100]==1){
continue;
}
use[nums[i]+100]=1;
path.push_back(nums[i]);
backtracking(nums,i+1);
path.pop_back();
}
}
vector<vector<int>> findSubsequences(vector<int>& nums) {
backtracking(nums,0);
return result;
}
};
46.全排列
思路:利用了上一题中学到的标记数组法,用长度为6的数组记录该元素是否被使用过。注意不要在result保存结果后将数组清零,证明对回溯法理解不到位。
class Solution {
public:
vector<vector<int>>result;
vector<int>path;
int count[6]={0};
void backtracking(vector<int> nums){
if(path.size()==nums.size()){
result.push_back(path);
// memset(count,0,sizeof(count));
return;
}
for(int i=0;i<nums.size();i++){
if(count[i]){
continue;
}
path.push_back(nums[i]);
count[i]=1;
backtracking(nums);
count[i]=0;
path.pop_back();
}
}
vector<vector<int>> permute(vector<int>& nums) {
backtracking(nums);
return result;
}
};
观察题解区发现还有一种不用标记数组而是利用交换的方法。
举个简单的例子,假设我们有 [2,5,8,9,10][2, 5, 8, 9, 10][2,5,8,9,10] 这 555 个数要填入,已经填到第 333 个位置,已经填了 [8,9][8, 9][8,9] 两个数,那么这个数组目前为 [8,9 ∣ 2,5,10][8, 9~|~2, 5, 10][8,9 ∣ 2,5,10] 这样的状态,分隔符区分了左右两个部分。假设这个位置我们要填 101010 这个数,为了维护数组,我们将 222 和 101010 交换,即能使得数组继续保持分隔符左边的数已经填过,右边的待填 [8,9,10 ∣ 2,5][8, 9, 10~|~2, 5][8,9,10 ∣ 2,5] 。
当然善于思考的读者肯定已经发现这样生成的全排列并不是按字典序存储在答案数组中的,如果题目要求按字典序输出,那么请还是用标记数组或者其他方法。
class Solution {
public:
void backtrack(vector<vector<int>>& res, vector<int>& output, int first, int len){
// 所有数都填完了
if (first == len) {
res.emplace_back(output);
return;
}
for (int i = first; i < len; ++i) {
// 动态维护数组
swap(output[i], output[first]);
// 继续递归填下一个数
backtrack(res, output, first + 1, len);
// 撤销操作
swap(output[i], output[first]);
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int> > res;
backtrack(res, nums, 0, (int)nums.size());
return res;
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/permutations/solutions/218275/quan-pai-lie-by-leetcode-solution-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
47.全排列 II
题目链接:47. 全排列 II - 力扣(LeetCode)
思路:注意本题的去重方式,count[i-1]==0
,该句的运作原理可以参照下图。其他与上一题一致。
class Solution {
public:
vector<vector<int>>result;
vector<int>path;
int count[8]={0};
void backtracking(vector<int> nums,int count[]){
if(path.size()==nums.size()){
result.push_back(path);
return;
}
for(int i=0;i<nums.size();i++){
if(i&&nums[i]==nums[i-1]&&count[i-1]==0){
continue;
}
if(count[i]==0){
count[i]=1;
path.push_back(nums[i]);
backtracking(nums,count);
path.pop_back();
count[i]=0;
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums){
sort(nums.begin(),nums.end());
backtracking(nums,count);
return result;
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端