leetcode-78-子集(subsets)-java

題目及測試

package pid078;

import java.util.List;

/*子集

給定一組不含重複元素的整數數組 nums,返回該數組所有可能的子集(冪集)。

說明:解集不能包含重複的子集。

示例:

輸入: nums = [1,2,3]
輸出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]



*/
public class main {
	
	public static void main(String[] args) {
		int[] testTable = {1,2,3};
		test(testTable);
	}
		 
	private static void test(int[] ito) {
		Solution solution = new Solution();
		long begin = System.currentTimeMillis();
		System.out.println("ito= ");
		for (int i = 0; i < ito.length; i++) {
		    System.out.print(ito[i]+" ");
		}//開始時打印數組
		System.out.println();
		
		List<List<Integer>> rtn=solution.subsets(ito);//執行程序
		long end = System.currentTimeMillis();		
		for (int i = 0; i < rtn.size(); i++) {
		   for(int j=0;j<rtn.get(i).size();j++){
			   System.out.print(rtn.get(i).get(j)+" ");
		   }
		   System.out.println();
		}//打印結果幾數組
		System.out.println();
		System.out.println("耗時:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

自己沒想出來

解法1(別人的)

不錯的方法

https://blog.csdn.net/wodedipang_/article/details/52996928

使用位操作,不使用遞歸。首先,計算一下該數組nums一共有多少個子集,設數組nums的長度爲n,那麼它的子集總數爲num=2^n。
設置一個變量index,其初始值爲1。那麼從0到2^n-1中數,對於每一個數i,用index(從1到10,100,100(2進制))與這個i進行與操作,如果得出的結果大於0,則把該數輸入到List<>中取,比較n次,因爲數組的長度爲n。

 public List<List<Integer>> subsets(int []nums) { 
List<List<Integer>> list=new ArrayList<List<Integer>>(); 
if(nums==null||nums.length==0) { 
return list; } 
int n=nums.length; //數組的長度 
int num=(int)Math.pow(2,n); 
for(int i=0;i<num;i++) //這裏是2^n次的 { 
int index=1; List<Integer> temp=new ArrayList<Integer>(); 
for(int j=0;j<n;j++) //數組的長度 { 
int data=i&index; //一共要計算num*n次的位與操作 
System.out.println("data="+data); 
if(data>0)//選取data大於0的數,說明該數還沒有被選擇過的。 { 
temp.add(nums[j]); } 
index=index<<1;//左乘2的1次方 } 
list.add(temp); } 
return list; }

解法2(別人的)

回溯算法

這道題需要求給定數組的子集,特別要求有:
1、必須是升序
2、不能出現重複的

所以做法其實也就是,首先排序,然後回溯。。和昨天那題一樣,可以回去看一下。記得選擇下一個的時候,別和當前的值重複就可以了。

public class Solution {
    /**
     * 原來這道題是不在乎順序的。。我用的方式是我習慣的。。沒亮點,所以用List了。。
     * 用bit位可也咯,用boolean數組代替也好。。。都可以。。看你習慣哪種了,反正沒添加一個,都要遍歷一次,心累
     *
     * 對了,List是引用。。所以要重新創建一個新的對象才行哦。。。不然就掛了。。
     * */
    int[] nums;
    List<List<Integer>> result;
    public void find(int index,List<Integer> last){
        if(index>=nums.length)
            return ;
        ArrayList<Integer> item=new ArrayList<Integer>();
        item.addAll(last);
        item.add(nums[index]);
        result.add(item);
        find(index+1,last);
        find(index+1,item);


    }
    public List<List<Integer>> subsets(int[] nums) {
        Arrays.sort(nums);
        this.nums=nums;
        this.result=new ArrayList<List<Integer>>();
        int i=0;
        ArrayList<Integer> tmp=new ArrayList<Integer>();
        result.add(tmp);
        find(i,tmp);
        return result;


    }
}

解法3(別人的)

回溯算法|遞歸實現

本解法採用回溯算法實現,回溯算法的基本形式是“遞歸+循環”,正因爲循環中嵌套着遞歸,遞歸中包含循環,這才使得回溯比一般的遞歸和單純的循環更難理解,其實我們熟悉了它的基本形式,就會覺得這樣的算法難度也不是很大。原數組中的每個元素有兩種狀態:存在和不存在。

① 外層循環逐一往中間集合 temp 中加入元素 nums[i],使這個元素處於存在狀態

② 開始遞歸,遞歸中攜帶加入新元素的 temp,並且下一次循環的起始是 i 元素的下一個,因而遞歸中更新 i 值爲 i + 1

③ 將這個從中間集合 temp 中移除,使該元素處於不存在狀態

 

   public class Solution {
        public List<List<Integer>> subsets(int[] nums) {
            List<List<Integer>> res = new ArrayList<List<Integer>>();
            List<Integer> temp = new ArrayList<Integer>();
            dfs(res, temp, nums, 0);
            return res;
        }
        private void dfs(List<List<Integer>> res, List<Integer> temp, int[] nums, int j) {
            res.add(new ArrayList<Integer>(temp));
            for(int i = j; i < nums.length; i++) {
                temp.add(nums[i]);  //① 加入 nums[i]
                dfs(res, temp, nums, i + 1);  //② 遞歸
                temp.remove(temp.size() - 1);  //③ 移除 nums[i]
            }
        }
    }

10 / 10 test cases passed. Runtime: 2 ms  Your runtime beats 61.73% of javasubmissions.

解法4(別人的)

組合|非遞歸實現

這種方法是一種組合的方式

① 最外層循環逐一從 nums 數組中取出每個元素 num

② 內層循環從原來的結果集中取出每個中間結果集,並向每個中間結果集中添加該 num 元素

③往每個中間結果集中加入 num

④將新的中間結果集加入結果集中

  

  public class Solution {
        public List<List<Integer>> subsets(int[] nums) {
            List<List<Integer>> res = new ArrayList<List<Integer>>();
            res.add(new ArrayList<Integer>());
            for (int num : nums) {  // ①從數組中取出每個元素
                int size = res.size();
                for (int i = 0; i < size; i++) {
                    List<Integer> temp = new ArrayList<>(res.get(i));  // ②逐一取出中間結果集
                    temp.add(num);  // ③將 num 放入中間結果集
                    res.add(temp);  // ④加入到結果集中
                }
            }
            return res;
        }
    }

10 / 10 test cases passed. Runtime: 2 ms  Your runtime beats 61.73% of javasubmissions.
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章