第七章 回溯算法part05

110 阅读1分钟

491. Non-decreasing Subsequences

Given an integer array nums, return all the different possible non-decreasing subsequences of the given array with at least two elements. You may return the answer in any order.

题目解析:

  • 求递增序列,所以不能排序,从而不能只比较前一个,而是要比较之前所有是否出现过

代码:

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backtracking(nums, 0, new ArrayList<>());
        return result;
    }

    public void backtracking(int[] nums, int start, List<Integer> comb) {
        if (comb.size() >=2) {
            result.add(new ArrayList<>(comb));
        }
        Set<Integer> set = new HashSet<>();
        for (int i = start; i < nums.length; i++) {
            if (set.contains(nums[i])) continue;
            set.add(nums[i]);
            // if (i > start && nums[i] == nums[i-1]) continue;
            if (comb.isEmpty() || nums[i] >= comb.get(comb.size()-1)) {
                comb.add(nums[i]);
                backtracking(nums, i + 1, comb);
                comb.remove(comb.size() - 1);
            }
        }
    }
}

46. Permutations

Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order.

题目解析:

  • 排列需要考虑顺序

代码:

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> permute(int[] nums) {
        backtracking(nums, new ArrayList<>());
        return result;
    }

    public void backtracking(int[] nums, List<Integer> path) {
        if (path.size() == nums.length) {
            result.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (!path.contains(nums[i])){
                path.add(nums[i]);
                backtracking(nums, path);
                path.remove(path.size() - 1);
            }
        }
    }
}

47. Permutations II

Given a collection of numbers, nums, that might contain duplicates, return all possible unique permutations in any order.

题目解析:

  • 为了记录元素是否已经使用,可以使用一个布尔数组存储,或者通过存储下标index来判断,之后在转化成具体值
  • 因为存在重复元素,所以同样需要使用一个set记录在同一个位置是否使用过相同值的元素,如果有,则需跳过

代码:

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        boolean[] used = new boolean[nums.length];
        backtracking(nums, new ArrayList<>(), used);
        return result;
    }

    public void backtracking(int[] nums, List<Integer> path, boolean[] used) {
        if (path.size() == nums.length) {
            // List<Integer> comb = path.stream().map(i -> nums[i]).collect(Collectors.toList());
            result.add(new ArrayList<>(path));
            return;
        }
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            if (!used[i] && !set.contains(nums[i])) {
                set.add(nums[i]);
                used[i] = true;
                path.add(nums[i]);
                backtracking(nums, path, used);
                path.remove(path.size() - 1);
                used[i] = false;
            }
        }
    }
}

总结

对于排列问题,因为不同的顺序代表不同的排列,所以每次循环需要从0开始

  1. 一个元素不能使用两次,如果有值重复的元素,可以通过下标来区分,比如定义一个boolean数组来存储是否使用
  2. 如果有值重复元素,为了避免重复,同一个位置,不能使用值相同的元素(下标不同):
    • 如果原数组可以排序,则需要在for循环中比较前一个元素是否与当前元素一样
    • 如果原数组不可以排序,则需要定义一个set来判断是否之前出现过