Problem 4 Permutation II with duplication

Method 1: Swap- Swap(只对permutation有效)

弄清楚到底哪里重复:总的元素种类与个数相同,那么如果你固定过的元素值一样的话,剩下的元素的种类与个数一定也一样

重点在哪里?

  • duplication point 1:纵着看(swap-swap自动避免)

    • 不同层之间,同一个元素(index相同的元素)只能被固定一次

  • duplication point 2:横着看

    • 同一层上,对于要固定到同一个位置的两个元素value不能重复

吃吐守恒定律,是对什么样的元素进行吃吐?

  • 一定是不同层之间的元素

既然是对同一层的去重?

  • 去重的set需要加在每一层

public List<List<Integer>> permutation(int[] nums) {
    List<List<Integer>> result = new ArrayList<>();
    if (nums == null || nums.length == 0) {
        return result;
    }
    backTracking(result, nums, 0);
    return result;
}

// level: index: 当前层我正要固定index
// [0, index - 1]已经固定好的元素,不能用
// [index, nums.length - 1] 可以用来被固定到当前位置的元素

private void backTracking(List<List<Integer>> result, int[] nums, int level) {
    if (level == nums.length) {
        List<Integer> current = new ArrayList<>();
        for (int num: nums) {
            current.add(num);
        }
        result.add(current);
        return;
    }
    // 纵向上自动避免重复(swap - swap)
    // 横向上需要我们自己去重
    Set<Integer> valueHasBeenFixedInThisLevel = new HashSet<>();
    
    for (int i = level; i < nums.length; i++) {
        if (!valueHasBeenFixedInThisLevel.contains(nums[i])) {
            valueHasBeenFixedInThisLevel.add(nums[i]);
            swap(nums, i, level);
            backTracking(result, nums, level + 1);
            swap(nums, i, level);
        }
        //valueHasBeenFixedInThisLevel.remove(nums[i]); //不能吐,这是同一层,不需要吃吐
    }
}

private void swap(int[] nums, int i, int j) {
    int temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}

思考:

  • if (set.add(..)) vs 是否contains再add?前面可以简单

Method 2 一个个加,怎么把横纵都去重

public List<List<Integer>> permutation(int[] nums) {
    List<List<Integer>> result = new ArrayList<>();
    if (nums == null || nums.length == 0) {
        return result;
    }
    
    //纵向去重
    Set<Integer> dedupIndexOnVerticallySet = new HashSet<>();
    List<Integer> current = new ArrayList<>();
    backTracking(result, nums, current, 0, dedupIndexOnVerticallySet);
    return result;
}

private backTracking(List<List<Integer>> result, int[] nums, List<Integer> current, int index, Set<Integer> dedupIndexOnVerticallySet) {
    // base case
    if (index == nums.length) {
        result.add(new ArrayList<>(current));
    }
    
    // current
    Set<Integer> dedupVallueOnHorizontallySet = new HashSet<>();
    // recursive rule
    for (int i = index; i < nums.length; i++) {
        if (!dedupIndexOnVerticallySet.contains(i)) { //注意这里是index!!!!
            if (!dedupValueOnHorizontallySet.contains(nums[i])) {
                dedupIndexOnVerticallySet.add(i);
                dedupValueOnHorizontallySet.add(nums[i]);
                current.add(nums[i]);
                backTracking(result, nums, current, index + 1,  dedupIndexOnVerticallySet);
                current.remove(current.size() - 1);
                dedupIndexOnVerticallySet.remove(i);
            }
        } 
    }
}

Last updated