1. 程式人生 > >LeetCode--47. Permutations II

LeetCode--47. Permutations II

題目連結:https://leetcode.com/problems/permutations-ii/

這個題目就是跟https://blog.csdn.net/To_be_to_thought/article/details/85126156這篇思路類似,就是在46. Permutations的基礎上用HashSet進行去重操作。程式碼的邏輯結構基本一致:

class Solution {
    
    public static List<List<Integer>> ret;
    public static boolean[] visited;
    public static int[] record;
    public static int num;
    public static HashSet<String> hs;
    
    
    public List<List<Integer>> permuteUnique(int[] nums) {
        
        ret=new LinkedList<List<Integer>>();
        num=nums.length;
        hs=new HashSet<String>();
        record=new int[num];
        visited=new boolean[num];
        recursive(nums,num);
        return ret;
    }
    
    public static void recursive(int[] nums,int k)
    {
        if(k==0)
        {
            StringBuilder sb=new StringBuilder();
            for(int i=0;i<num;i++)
                sb.append(record[i]);
            String st=sb.toString();
            if(hs.contains(st))
                return;
            else
            {
                hs.add(st);
                LinkedList<Integer> tmp=new LinkedList<Integer>();
                for(int i=0;i<num;i++)
                    tmp.add(record[i]);
                ret.add(tmp);
            }
                
        }
        for(int i=0;i<nums.length;i++)
        {
            if(!visited[i])
            {
                record[k-1]=nums[i];
                visited[i]=true;
                recursive(nums,k-1);
                visited[i]=false;
            }
        }
    }
}

效率一如既往地很一般,是很菜!!!

我們能不能在搜尋的時候就直接去重,避免生成序列後再檢查。我們舉個例子[3,3,0,3]看看為什麼會產生重複。

                                              原陣列:   

如下兩種選擇產生的結果都一樣,index是指選擇的數在原陣列中的索引:

                                        

當然,產生3330的結果不止這兩種情況,我們發現在某個位置i上進行選數時,首先原陣列中以前選過的位置上的數是不能選的,也就是需要一個訪問記錄陣列來記錄訪問情況,另外在某個位置i上,遇到相等的數(之前在i位置上選過這個值,但不是這同一個位置)時,要判斷上一次是否選擇這個數,上次沒選這個數值的這一次可以選,上次選了這個數值的不能選直接跳過。

除了在陣列位置上不能重複選擇(索引一致數值必然一致),在每個合法結果的位置i上選擇也要判重(索引不一致,數值可能相同),這裡採用HashSet做一下判重。程式碼如下:

class Solution {
    
    public static List<List<Integer>> ret;//儲存最終答案
    public static boolean[] visited;//儲存被選陣列的索引訪問記錄
    public static int[] record;//存合法的每個答案
    public static int num;
    
    
    public List<List<Integer>> permuteUnique(int[] nums) {
        
        ret=new LinkedList<List<Integer>>();
        num=nums.length;
        record=new int[num];
        visited=new boolean[num];
        recursive(nums,num);
        return ret;
    }
    
    public static void recursive(int[] nums,int k)
    {
        if(k==0)
        {
            LinkedList<Integer> tmp=new LinkedList<Integer>();
            for(int i=0;i<num;i++)
                tmp.add(record[i]);
            ret.add(tmp);
            return;
        }
        
        HashSet<Integer> chosen=new HashSet<>(); 
        for(int i=0;i<nums.length;i++)
        {
            if(chosen.contains(nums[i]) || visited[i])
               continue;
            record[k-1]=nums[i];
            chosen.add(nums[i]);
            visited[i]=true;
            recursive(nums,k-1);
            visited[i]=false;
        }
    }
}

還有一種比較奇怪的操作,效率更高,就是先將被選陣列排序:

if(visited[i] || (i>0 && nums[i-1]==nums[i] && visited[i-1]))
                continue;

if(visited[i] || (i>0 && nums[i-1]==nums[i] && !visited[i-1]))
                continue;

都能AC

class Solution {
    
    public static List<List<Integer>> ret;
    public static boolean[] visited;
    public static int[] record;
    public static int num;
    
    
    public List<List<Integer>> permuteUnique(int[] nums) {
        
        ret=new LinkedList<List<Integer>>();
        num=nums.length;
        record=new int[num];
        visited=new boolean[num];
        Arrays.sort(nums);
        recursive(nums,num);
        return ret;
    }
    
    public static void recursive(int[] nums,int k)
    {
        if(k==0)
        {
            LinkedList<Integer> tmp=new LinkedList<Integer>();
            for(int i=0;i<num;i++)
                tmp.add(record[i]);
            ret.add(tmp);
        }
        for(int i=0;i<nums.length;i++)
        {
            if(visited[i] || (i>0 && nums[i-1]==nums[i] && visited[i-1]))
                continue;
            record[k-1]=nums[i];
            visited[i]=true;
            recursive(nums,k-1);
            visited[i]=false;
        }
    }
}