Day28_Backtracking, Leetcode 491, 46, 47

Leetcode 491

-Leetcode

题目的第一想法:

这道题的要求是挑出一段连续上升的subsequence。要求满足连续上升,不更改本来数组的位置且剔除重复数字的这些条件。这道题我最一开始的想法是不计用过的数字,然后看到重复的数字直接跳过。这个办法在可以对数组排序时是有用的,因为数组在被排序后,重复的数字会排在一起,所以这个逻辑可以用来跳过所有重复的数字。但当他们没有排列在一起时,就有可能无法剔除所有重复的数字。于是还是用了一个数据结构来记录存在过的数字。

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

    void helper(List<List<Integer>> rlist, List<Integer> list, int[] nums, int index){
        if(list.size() >= 2) rlist.add(new ArrayList<>(list));
        int[] used = new int[202];
        for(int i = index; i < nums.length; i++){
            if(used[101 + nums[i]] == 1) continue;
            if(list.size() == 0 || list.get(list.size() - 1) <= nums[i]){
                list.add(nums[i]);
                used[101 + nums[i]] = 1;
                helper(rlist, list, nums, i + 1);
                int num = list.remove(list.size() - 1);
                while(i < nums.length - 1 && num == nums[i + 1]) i++;
            }
        }
    }
}

Leetcode 46

-Leetcode

题目的第一想法:

这道题是关于permutation的。我第一次尝试没有改其他的值,只是把for循环里的对i的赋值从index改成了0。发现有很多数字重复出现了。我在这里没有尝试去重,而是尝试用把值从表里面拿出来然后使用过后再放回去的办法。但后来发现与其一直更改表的内容,不如直接把数字对调要更好一些。我对于数字对调的逻辑是,做双循环,外循环从nums的头部循环到尾,内循环从尾部循环到外循环的i值。这样的话可以确保i值和每个数字的对调的同时前进。写法是这样的

class Solution {
    List<List<Integer>> rlist;
    List<Integer> list;
    public List<List<Integer>> permute(int[] nums) {
        rlist = new ArrayList<>();
        list = new LinkedList<>();
        helper(nums, 0);
        return rlist;
    }

    public void helper(int[] nums, int index){
        List<Integer> list = new LinkedList<>();
        for(int i: nums){
            list.add(i);
        }
        rlist.add(new LinkedList<>(list));
        for(int i = index; i < nums.length; i++){
            for(int j = nums.length - 1; j > i; j--){
                swap(nums, i, j);
                helper(nums, i + 1);
                swap(nums, i, j);
            }
        }
    }

    void swap(int[] nums, int i1, int i2){
        int temp = nums[i1];
        nums[i1] = nums[i2];
        nums[i2] = temp;
    }
}

看完代码随想录之后的想法:

发现其实第一次的逻辑只要通过一些去重手段来去掉已经用过的数字也可以得到结果。

Leetcode 47

-Leetcode

题目的第一想法:

这道题是关于permutation去重的。因为刚刚做了上一道题,我第一想法依旧是使用swap来解决这个问题。但这个逻辑我感觉不是很好想。后来还是用了used来做。在用used时感觉思路依旧不是很清楚。直感是保留之前的used[i] == true,然后加一个or后面连去重的条件。但困住我的问题是,之前去重时,重复的数字只要跳过就好了,但这道题感觉上跳过数字的话会跳过本应该被记入的排列组合。不过是我的想法有问题了因为每次的nums都会是不同的nums,所以在这一树层跳过的话也会在上一层补回来。

class Solution {
    List<List<Integer>> rlist;
    List<Integer> list;
    public List<List<Integer>> permuteUnique(int[] nums) {
        rlist = new ArrayList<>();
        list = new LinkedList<>();
        int used[] = new int[nums.length];
        Arrays.sort(nums);
        helper(nums, used);
        return rlist;
    }

    public void helper(int[] nums, int[] used){
        if(list.size() == nums.length){
            rlist.add(new ArrayList<>(list));
            return;
        }
        for(int i = 0; i < nums.length; i++){
            if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == 0 || used[i] == 1) continue; 
            list.add(nums[i]);
            used[i] = 1;
            helper(nums, used);
            list.remove(list.size() - 1);
            used[i] = 0;
        }
    }
}

看完代码随想录之后的想法:

用来判断前一个used可以为真也可以为假,感觉上这个逻辑还是挺难理解的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值