一、力扣题491. 递增子序列
给你一个整数数组 nums
,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。
示例 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]]
提示:
1 <= nums.length <= 15
-100 <= nums[i] <= 100
这道题的主要难点也是去重,同一树层中的相同元素不能重复取用(指的是同一父节点下的同一树层),但和之前去重的题目的不同之处在于,这道题给的数组是不能打乱顺序重新排序的,所以要用别的方法判断重复元素。
这里用到了uset数组,uset数组在每一个树层开始遍历时都会置空,该数组相当于一个map数组,当遍历到一个元素 i 时,定义 uset[ nums[ i ] ] 为 1,所以遍历到第二个重复元素时,判断以该元素值为键名的值存在,则跳过该元素。
实际上就是对同一树层非顺序排列的数组的去重。
class Solution {
private $result = [];
/**
* @param Integer[] $nums
* @return Integer[][]
*/
function findSubsequences($nums) {
if(count($nums) < 2) return [];
$this->backtracking($nums, [], 0, []);
return $this->result;
}
function backtracking($nums, $path, $cur, $uset) {
for($i = $cur; $i < count($nums); $i++) {
if(($path != [] && end($path) > $nums[$i]) || $uset[$nums[$i]] == 1) {
continue;
}
$path[] = $nums[$i];
if(count($path) > 1) {
$this->result[] = $path;
}
$uset[$nums[$i]] = 1;
$this->backtracking($nums, $path, $i + 1,[]);
array_pop($path);
}
}
}
二、力扣题46. 全排列
给定一个不含重复数字的数组 nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1] 输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1] 输出:[[1]]
提示:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums
中的所有整数 互不相同
排列与组合的不同之处在于,组合中两个集合只要含有的元素相同就是重复,但在排列的定义中,即使两个集合含有的元素相同,但只要两个集合中元素排列的顺序不同,都算是不同集合。
总的来说本题就是求出一个集合中元素的全部排列方式。所以解集中所有集合的元素个数都相等。
所以和以前不同的是,每次循环遍历都要从0的位置开始,这里就涉及到一个问题,遍历时遇到已经取用过的元素怎么办?
使用used数组用于标记已取用过的元素。
class Solution {
private $result = [];
/**
* @param Integer[] $nums
* @return Integer[][]
*/
function permute($nums) {
$this->backtracking($nums, [], []);
return $this->result;
}
function backtracking($nums, $path, $used) {
if(count($path) == count($nums)) {
$this->result[] = $path;
return;
}
for($i = 0; $i < count($nums); $i++) {
if($used[$i]) {
continue;
}
$used[$i] = true;
$path[] = $nums[$i];
$this->backtracking($nums, $path, $used);
$used[$i] = false;
array_pop($path);
}
}
}
三、力扣题47. 全排列 II
给定一个可包含重复数字的序列 nums
,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2] 输出: [[1,1,2], [1,2,1], [2,1,1]]
示例 2:
输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
提示:
1 <= nums.length <= 8
-10 <= nums[i] <= 10
本题就是在上一题的基础上加了去重要求,现在不仅要标记已经取用过的元素了,还要同一树层不能取用重复的元素。
同一树层去重可以直接使用map数组,也可以将数组重新排序后用之前的used数组(这里说的used数组作用不是用于标记用过的元素,而是为了去重,同名不同意思)的方法。
这里就直接使用map数组的方法了。
class Solution {
private $result = [];
/**
* @param Integer[] $nums
* @return Integer[][]
*/
function permuteUnique($nums) {
$this->backtracking($nums, [], [], []);
return $this->result;
}
function backtracking($nums, $path, $used, $uset) {
if(count($path) == count($nums)) {
$this->result[] = $path;
return;
}
for($i = 0; $i < count($nums); $i++) {
if($used[$i] || $uset[$nums[$i]]) {
continue;
}
$used[$i] = true;
$uset[$nums[$i]] = true;
$path[] = $nums[$i];
$this->backtracking($nums, $path, $used, []);
$used[$i] = false;
array_pop($path);
}
}
}