记录 1 道算法题
递增子序列
要求: 将一个数组里的递增的子数组收集起来,元素可以是不相邻的,每个子数组至少有两个元素。
比如:[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]]
- 重复
首先要注意重复的问题。就比如 [4,6,7,7] 里面会有两个 [4,6,7]。去重的方法有很多,我们可以使用 set 进行记录。
- 遍历
最简单的做法就是双重遍历。想提升性能的话需要使用递归,首先准备一个记录的数组,推入一个元素之后,进行递归,递归的基础就是当前已经记录的数组元素,然后尝试往里面推入其后面的元素,每次确认一个函数都进行递归。递归结束后将推入的元素进行弹出。所以递归的最小基础模板如下:
temp = [], nums
for(let i = 0; i < nums.length; i++) {
// 记录当前最后一位的数字
temp.push(nums[i])
// 往后面加一位数字
dfs()
// 加完去掉,继续循环,添加下一个
temp.pop()
}
比如 [4,6,7,7] 数组的打印
[4]
[4,6]
// 递归结束,下一轮循环
[4,7]
完整代码如下
function findSubsequences(nums) {
const temp = []
const result = []
const set = new Set()
// 开始遍历
dfs(0, nums, -Infinity, temp, result)
return result
}
function dfs(cur, nums, last, temp, result) {
if (temp.length >= 2) {
// 每次递归都先将当前的数组存起来,再添加
result.push(...[temp])
}
const set = new Set()
// 以 cur 为起点,尝试将元素推入数组
for(let i = cur; i < nums.length; i++) {
const n = nums[i]
// 比数组的最后一个大
if (n >= last) {
// 重复的情况
if (set.has(n)) continue
set.add(n)
temp.push(n)
// 递归
dfs(i + 1; nums, n, temp, result)
temp.pop()
}
}
}