【前端er每日算法】递增子数组和全排列

99 阅读1分钟

题目一 491. 递增子序列

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

思路

递增子数组,要去重,并且数组顺序不能改变,因为求递增子序列,所以不能排序,这样导致数组去重逻辑不一样,重复的是因为同层有相同元素,所以这种情况要排除掉。那判断重复的功能就是通过添加一个set来记录同层已经出现过的元素,如果已经出现过,则跳过,同时需要满足前后两个数字是递增的顺序。

递归获取子集的情况还是通过回溯算法来逐个获取到。

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var findSubsequences = function(nums) {
    let result = [];
    let path = [];
    let len = nums.length;
    let used = [];
    const backTracking = startIndex => {
        if (path.length > 1) {
            result.push(path.slice());
        }
        let usedSet = new Set();
        for (let i = startIndex; i < len; i++) {
            if ((path.length && nums[i] < path[path.length - 1])
                || usedSet.has(nums[i])) {
                continue;
            }
            usedSet.add(nums[i]);
            path.push(nums[i]);
            backTracking(i + 1);
            path.pop();
        }
    }
    backTracking(0);
    return result;
};

题目二 46. 全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

思路

数组的所有全排列,这样循环的时候,每次都从0开始遍历,但是同一路径长,已经使用过的元素,不能再次使用,所以需要used数组来记录下,本次路径已经使用的元素,然后排除这个元素。回退后,再恢复used元素状态。

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function(nums) {
    let result = [];
    let path = [];
    let len = nums.length;
    let used = [];
    const backTracking = () => {
        if (path.length === len) {
            result.push(path.slice());
            return;
        }
        for (let i = 0; i < len; i++) {
            if (used[i]) {
                continue;
            }
            path.push(nums[i]);
            used[i] = true;
            backTracking();
            path.pop();
            used[i] = false;
        }
    }
    backTracking();
    return result;
};

题目三 47. 全排列 II

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

思路

在上一道的基础上,需要加上同层元素的去重。其实和组合元素去重是一样的逻辑,先排序,然后同层排除,或者用一个set记录下当层已经使用过的元素。

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permuteUnique = function(nums) {
    let result = [];
    let path = [];
    let used = [];
    let len = nums.length;
    const backtracking = () => {
        if (path.length === len) {
            result.push(path.slice());
            return;
        }
        const levelUsedSet = new Set();
        for (let i = 0; i < len; i++) {
            if (used[i] || levelUsedSet.has(nums[i])) {
                continue;
            }
            path.push(nums[i]);
            used[i] = true;
            levelUsedSet.add(nums[i]);
            backtracking();
            path.pop();
            used[i] = false;
        }
    }
    backtracking();
    return result;
};