Subsets 系列 Leetcode解題記錄

Subsets

寫這個系列是由於記念一下去年的今天,就是2015年的9月14號,刷題第一天,今天是一週年記念日。當時只敢作easy還得抄答案的我想啥時候能作上medium啊,事到現在,感受都不是啥障礙了,這道題也已經作了第四遍了,抽出來的DFS遞歸模板放在這裏總結一下。
這題內容就是就是給個數組,裏面的數字都是獨一無二的,把它全部的子集都輸出出來。算法

解決思路

題目中給了個例子,好比[1,2,3],第一次抽出1,而後在1的基礎上加2,再加3。加完以後再往回返,去掉3,再去掉2,發現能夠加3,造成[1,3],再到2,以此類推。
思路很容易,可是寫的時候須要用到遞歸的手法,這個仍是須要點兒思惟過程的,推薦用IDE的debug功能一步一步走走看。數組

code

public class Subsets {
    public List<List<Integer>> subsets(int[] nums) {
        //先把輸出的東西擺上去。
        List<List<Integer>> result = new ArrayList<>();
        //排除corner case,就是返回一空的。
        if(nums == null || nums.length == 0) return result;
        //這個就是用來蒐集每一個子集的。
        List<Integer> list = new ArrayList<>();
        dfs(result, list, 0, nums);
        return result;
    }
    public void dfs(List<List<Integer>> result, List<Integer> list, int start, int[] nums){
        //先把當前的子集加上,這裏添加的語法我命名爲『照相法』
        result.add(new ArrayList<>(list));
        //注意這裏要從start位置開始循環,不然就是stackoverflow
        for(int i = start; i < nums.length; i++){
            //添加start位置的數字
            list.add(nums[i]);
            //開始遞歸,好比把1加上去以後,就穩住1,找後面好比2.
            dfs(result, list, i+1, nums);
            //backtrack,就是把以前加上的去掉,至關於往回走,好比以前加到1,2,3
            //就把3去掉,而後再找。
            list.remove(list.size()-1);
        }
    }
}

複雜度分析

算法課講過,這個複雜度是指數次,能實現出來就好了,無法優化。優化

最後再說兩句

這題就是模板,DFS的模板,就是一個容器來回抓,容器的容器每次把這個容器記錄下來。還有遞歸的debug就是人工模仿IDE,一步一步走。debug

Subsets II

稍有不一樣,就是數組裏面的數字可能有重複,同時要求子集輸出不能用重複的元素,一個很是典型的follow up。code

解決思路

重點在於判斷重複數字,把重複的狀況跳過去。模板仍是同樣的。排序

code

public class SubsetsII {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        if(nums == null || nums.length == 0) return result;
        //這裏就須要排序了,給之後跳太重複數字埋下伏筆
        Arrays.sort(nums);
        //剩下都是同樣的
        List<Integer> list = new ArrayList<>();
        dfs(result, list, 0, nums);
        return result;
    }
    public void dfs(List<List<Integer>> result, List<Integer> list, int start, int[] nums){
        result.add(new ArrayList<>(list));
        for(int i = start; i < nums.length; i++){
            //關鍵就在這一句,每次循環起始的數字不能和以前重複。
            if(i > start && nums[i] == nums[i-1]) continue;
            list.add(nums[i]);
            dfs(result, list, i+1, nums);
            list.remove(list.size()-1);
        }
    }
}

複雜度分析

不分析了,反正指數次。遞歸

最後再說兩句

這裏注意用好模板,循環的時候把起始的start寫成了0,直接就爆了。leetcode

相關文章
相關標籤/搜索