1.递增子序列
给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。
输入: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]]
注意:本题不能对原数组进行排序操作,
去重,同一树层不能重复使用相同的元素,所取元素小于子序列最后一个元素;
递归可以不加终止条件,startIndex 每次都会+1,不会无限递归;取树上所有符合条件的节点;
/**
* @param {number[]} nums
* @return {number[][]}
*/
var findSubsequences = function(nums) {
let result = [];
let path = [];
let startIndex = 0;
var backTracking = function (startIndex) {
if (path.length > 1) {
result.push(Array.from(path))
}
let used = new Array(200).fill(0);
for (let i = startIndex; i < nums.length; i++) {
if(path.length > 0 && nums[i] < path[path.length-1] || (used[nums[i]+100] === 1)){
continue;
}
path.push(nums[i]);
//记录这个元素在本层使用过了,本层后面不能再用
used[nums[i]+100] = 1;
backTracking(i+1);
path.pop();
}
}
backTracking(startIndex);
return result;
};
findSubsequences([1,2,1,1]);
2.全排列1
给定一个没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
排列是有序的,[1,2],[2,1]是两个集合,需要标记已经选择的元素;
叶子节点就是所有符合条件的子集;当收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点;
var permute = function(nums) {
let result = [];
let path = [];
let used = [];
var backTracking = function () {
if(path.length == nums.length){
result.push([...path]);
return;
}
for(let i = 0;i<nums.length;i++){
if (used[i]== true) {
continue;
}
used[i] = true;
path.push(nums[i]);
backTracking();
path.pop();
used[i] = false;
}
}
backTracking();
return result;
};
permute([1,2,3])
3.全排列2
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
输入:nums = [1,1,2] 输出: [[1,1,2], [1,2,1], [2,1,1]]
去重一定要对元素进行排序,方便通过相邻的节点来判断是否重复使用;
同一树层,前一位如果使用过,那么就要去重;
组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果;
var permuteUnique = function(nums) {
let result = [];
let path = [];
let used = [];
nums = nums.sort((a,b)=>{return a-b});
var backTracking = function () {
if(path.length == nums.length){
result.push([...path]);
return;
}
for(let i = 0;i<nums.length;i++){
// used[i - 1] == true,说明同一 树枝 nums[i - 1]使用过
// used[i - 1] == false,说明同一 树层 nums[i - 1]使用过
// 如果同一树层nums[i - 1]使用过则直接跳过
if (i > 0 && nums[i] === nums[i-1] && !used[i-1]) {
continue;
}
if (!used[i]) {
// 因为每层都是从下标0开始遍历的,树枝上相同的不符合
used[i] = true;
path.push(nums[i]);
backTracking();
path.pop();
used[i] = false;
}
}
}
backTracking();
return result;
};
permuteUnique([1,1,3])
https://programmercarl.com/0047.%E5%85%A8%E6%8E%92%E5%88%97II.html#%E6%80%9D%E8%B7%A