leetcode-78-子集(subsets)-java

版权声明:此文章为许诗宇所写,如需转载,请写下转载文章的地址 https://blog.csdn.net/xushiyu1996818/article/details/84562622

题目及测试

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.
 

猜你喜欢

转载自blog.csdn.net/xushiyu1996818/article/details/84562622
今日推荐