【LeetCode回溯算法#08】递增子序列,巩固回溯算法中的去重问题
递增子序列
给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。
示例 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]]
说明:
- 给定数组的长度不会超过15。
- 数组中的整数范围是 [-100,100]。
- 给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况
思路
题目要找出数组的所有递增子序列,所以需要将整个树结构遍历一遍。
根据说明中的第三点,本题也需要去重。
根据示例2可以看出,我们要找的是数组中当前顺序下的递增序列,因此不能对给定数组进行排序
那就恶心了,要知道我们之前在此类问题中去重考的就是 排序后的相邻重复值 + used标记数组
不管没关系,不能排序也行,那就在单层处理时做手脚
这里还是需要使用used数组来记录单层中使用过的元素
在记录遍历值前,需要做以下判断:
- 使用当前遍历值与之前保存在结果数组path中的值进行大小比较(判定是否有递增趋势)
- 判断当前遍历值是否被记录在used数组中(即之前被使用过)
为了实现上述思路,在回溯时不能删除之前used数组记录的值,且used数组改为在单层递归循环前定义,这样每到一层新的递归层时,used数组都会被清空
代码分析
1、确定回溯函数的参数和返回值
参数时题目给的数组nums、beingIndex,这里used数组在回溯函数里面定义
无返回值
class Solution {
private:
//定义结果数组
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数和返回值
void backtracking(vector<int>& nums, int beginIndex){
}
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
}
};
2、确定终止条件
参考 子集问题 ,如需要收集树结构的所有节点,实际上是不需要返回值的(依靠for循环结束即可)
但是,本题有一个要求是:递增子序列大小至少为2
所以在这里需要单独处理一下这个逻辑(严格来说也不是终止条件)
class Solution {
private:
//定义结果数组
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数和返回值
void backtracking(vector<int>& nums, int beginIndex){
//(确定终止条件)
//确保递增子序列大小至少为2
if(path.size() > 2){//2个以上才保存到结果数组
res.push_back(path);
}
}
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
}
};
3、确定单层处理逻辑
在单层处理时,还是去循环遍历当前层的元素
不过需要初始化used数组,并且加入当前遍历值与path数组中元素比较大小以及判断当前元素是否被used记录的逻辑
class Solution {
private:
//定义结果数组
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数和返回值
void backtracking(vector<int>& nums, int beginIndex){
//(确定终止条件)
//确保递增子序列大小至少为2
if(path.size() > 1){//2个以上才保存到结果数组
res.push_back(path);
}
//确定单层处理逻辑
//初始化used数组,每次进入递归都会被刷新
int used[201] = {0};//题目中说了,数值范围[-100,100],因此直接用数组就行
for(int i = beginIndex; i < nums.size(); ++i){
//判断逻辑
//path是否为空;当前值是否小于path中最新加入的值;或者当前值是否被记录于used
if(!path.empty() && nums[i] < path.back() || used[100 + nums[i]] == 1){
continue;//满足上述条件就跳过
}
used[100 + nums[i]] = 1;//在nums[i]位置记录出现过当前遍历值
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
}
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
}
};
注意点
1、vector::back()
用于取数组最新加入的一个值,这里用来取上次添加的值并与当前遍历值进行比较
2、使用数组来记录数的话,需要创建能够容纳所有元素个数的大小。然后只需在该元素大小位置处标记元素是否出现过即可
例如:如果遍历值是2,那么应该在used数组的100 + 2,也就是下标为102处记录1,表示2出现过1次
加100是因为题目所给范围是[-100,100],前100是负数值
完整代码
class Solution {
private:
//定义结果数组
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数和返回值
void backtracking(vector<int>& nums, int beginIndex){
//(确定终止条件)
//确保递增子序列大小至少为2
if(path.size() > 1){//2个以上才保存到结果数组
res.push_back(path);
}
//确定单层处理逻辑
//初始化used数组,每次进入递归都会被刷新
int used[201] = {0};//题目中说了,数值范围[-100,100],因此直接用数组就行
for(int i = beginIndex; i < nums.size(); ++i){
//判断逻辑
//path是否为空;当前值是否小于path中最新加入的值;或者当前值是否被记录于used
if(!path.empty() && nums[i] < path.back() || used[100 + nums[i]] == 1){
continue;//满足上述条件就跳过
}
used[100 + nums[i]] = 1;//在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 res;
}
};
【LeetCode回溯算法#08】递增子序列,巩固回溯算法中的去重问题的更多相关文章
- Leetcode之深度优先搜索&回溯专题-491. 递增子序列(Increasing Subsequences)
Leetcode之深度优先搜索&回溯专题-491. 递增子序列(Increasing Subsequences) 深度优先搜索的解题详细介绍,点击 给定一个整型数组, 你的任务是找到所有该数组 ...
- (转载)最长递增子序列 O(NlogN)算法
原博文:传送门 最长递增子序列(Longest Increasing Subsequence) 下面我们简记为 LIS. 定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则 ...
- 最长递增子序列 O(NlogN)算法
转自:点击打开链接 最长递增子序列,Longest Increasing Subsequence 下面我们简记为 LIS. 排序+LCS算法 以及 DP算法就忽略了,这两个太容易理解了. 假设存在一个 ...
- [LeetCode] 491. Increasing Subsequences 递增子序列
Given an integer array, your task is to find all the different possible increasing subsequences of t ...
- Leetcode 673.最长递增子序列的个数
最长递增子序列的个数 给定一个未排序的整数数组,找到最长递增子序列的个数. 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[ ...
- nyoj 214-单调递增子序列(二) (演算法,PS:普通的动态规划要超时)
214-单调递增子序列(二) 内存限制:64MB 时间限制:1000ms Special Judge: No accepted:11 submit:35 题目描述: 给定一整型数列{a1,a2..., ...
- Java实现 LeetCode 673 最长递增子序列的个数(递推)
673. 最长递增子序列的个数 给定一个未排序的整数数组,找到最长递增子序列的个数. 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列,分别是 [1, 3, 4, ...
- LIS 最长递增子序列
一.最长公共子序列 经典的动态规划问题,大概的陈述如下: 给定两个序列a1,a2,a3,a4,a5,a6......和b1,b2,b3,b4,b5,b6.......,要求这样的序列使得c同时是这两个 ...
- 最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现
关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已 ...
- 最长递增子序列(LIS)
最长递增子序列(Longest Increasing Subsequence) ,我们简记为 LIS. 题:求一个一维数组arr[i]中的最长递增子序列的长度,如在序列1,-1,2,-3,4,-5,6 ...
随机推荐
- Unity算法之A星- A*Pathfind Project插件的使用
先上效果图 首先上 插件地址 (如果没有积分可以评论区联系我) 1.下载完毕后导入unity 导入后可以在Component里面看到多了一个Pathfinding选项 2.场景搭建 首先新建两个层 ...
- Thread 的run方法和start方法的区别
start()方法是用来启动线程,实现了多线程运行 点进去查看源码,发现start方法创建一个线程 并让线程处于就绪状态,并且在start方法内会调用start0()方法,而start0作为本地方法 ...
- python菜鸟学习: 8. 集合基础知识
# -*- coding: utf-8 -*-# 列表的特性:1,去重:2.关系测试list1 = [1, 4, 6, 8, 7, 8, 9]# 集合去重list2 = set(list1)print ...
- python音乐分类--knn
1 #利用knn算法分类音乐,将音乐进行情绪分类 2 #将音乐分为兴奋的(excited), 愤怒的(angry),悲伤的(sorrowful),轻松的(relaxed) 3 4 #可分离因素 5 # ...
- List的初始化方式
在LinkedIn考试考到了,很遗憾没考过,特意记录一下,下次再战!文章不是我写的,看到别人的总结,发在我这里自己看看 在 Java 中几种初始化 List 的方法: 1. List<Strin ...
- Echart 属性解析
<template> <div class="container"> <div id="myEchart" style=" ...
- Context,多个组件公用的数据传导方法
三个组件:输入A组件 输出B组件 TestContext组件,数据x. 方法: 输入端(A): import TestContext from "TestContext组件路径&qu ...
- day01学习小记
# Markdown学习 ## 标题 ### 三级标题 #### 四级标题 ## 字体 Hellow,World! Hellow,world hellow,world! hellow,world ## ...
- springBoot 这货特别火
现在 Spring Boot 非常火,各种技术文章,各种付费教程,多如牛毛,可能还有些不知道 Spring Boot 的,那它到底是什么呢?有什么用?今天给大家详细介绍一下. Spring Boot ...
- Tomcat后端无法返回数据
以前使用的是Tomcat8和9,这次使用的10怎么就无法返回数据呢? 一开始以为是因为这个错误:Using CATALINA_OPTS: "" 但是后来发现怎么尝试都无法取出这 ...