LeetCode--47. Permutations II
阿新 • • 發佈:2019-01-01
題目連結: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;
}
}
}