力扣每日一题,78. 子集

我的成绩

用了将近20分钟写的,一次通过了,运气爆棚。这说明我的回溯法技能经验又+1。
在这里插入图片描述
不过通过后我回过头区看题目标签,
在这里插入图片描述
这题居然涉及位运算,我没想过哪里可以用到位运算,得去题解去看看大佬们的操作才行。

题目描述

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

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

思路

回溯,回溯,这题和全排列一个尿性。
假如是123进行全排列,算法图解如下:
图是我用visio画的,看不清除可下载原visio文件
https://o8.cn/L12taX密码:zsnh(本地高速是下载器)

在这里插入图片描述
我们可以观察到这题的结果其实在全排列过程中已经出来了,如下图所示:
在这里插入图片描述
同时我们可以发现,存在可以进行剪枝的结点(我用蓝色框框出来的结点)它的特点是存在逆序(前面的数大于后面的数),所以在回溯过程中,可以判断当前结点是否逆序,是就直接return

	if(!isBackward(path)){
			res.add(new ArrayList<Integer>(path));
		}else{
			return;
		}
	private boolean isBackward(List<Integer> a) {
		for (int i = 0; i < a.size()-1; i++) {
			if(a.get(i)>a.get(i+1)){
				return true;
			}
		}
		return false;
	}

回溯法模板如下:

回溯法模板

void backtrack(int i, int n, other parameters) {
    if (i == n) {
        //获取一个答案
        return;
    }
       //一般子结点有多少个就循环多少次
    for (){
        backtrack(i + 1, n, other parameters);
    }
}

提交代码

package 子集;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class Solution {
	@Test
	public void testBacktrace() throws Exception {
		int nums[] = {1,2,3};
		boolean used[] = new boolean[nums.length];
		List<Integer> path = new ArrayList<Integer>();
		List<List<Integer>> res = new ArrayList<List<Integer>>();
		backtrace(0, nums.length, nums, used,path,res);
		System.out.println(res);
		
	}
    public List<List<Integer>> subsets(int[] nums) {
		boolean used[] = new boolean[nums.length];
		List<Integer> path = new ArrayList<Integer>();
		List<List<Integer>> res = new ArrayList<List<Integer>>();
		backtrace(0, nums.length, nums, used,path,res);
		return res;
    }
	private void backtrace(int i ,int n,int nums[],boolean used[],List<Integer> path,List<List<Integer>> res) {
		if(!isBackward(path)){
			res.add(new ArrayList<Integer>(path));
		}else{
			return;
		}
		//以下这个递归终止条件的判断完全可以删除,是我进行全排列观察打印结果用的。
		if(i==n){
			System.out.println(path);
			return;
		}
		for (int j = 0; j < nums.length; j++) {
			if(!used[j]){
				used[j] = true;
				path.add(nums[j]);
				backtrace(i+1, n, nums, used,path,res);
				path.remove(path.size()-1);
				used[j] = false;
			}
		}
	}
	private boolean isBackward(List<Integer> a) {
		for (int i = 0; i < a.size()-1; i++) {
			if(a.get(i)>a.get(i+1)){
				return true;
			}
		}
		return false;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值