组合(力扣)dfs + 回溯 + 剪枝 JAVA

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

示例 1:

输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

示例 2:

输入:n = 1, k = 1
输出:[[1]]

提示:

1 <= n <= 20
1 <= k <= n

解题思路:

1.每个元素有选与不选两种情况,

2.回溯能将选与不选这两种情况都包含

3.递归刚好能满足这个需求

在这里插入图片描述

dfs + 回溯代码:

class Solution {
    public List<List<Integer>> combine(int n, int k) {
           List<List<Integer>> end = new ArrayList<>();
           List<Integer> mb = new ArrayList<>();
           
        	   addmbzh(1, k, end, mb, n);
           
           return end;
    }
    public static void addmbzh(int x, int k, List<List<Integer>> end, List<Integer> none, int n) { 
        if(x > n + 1) return;
    	if(none.size() == k) {
        end.add(new ArrayList<Integer>(none));
        return;
        }
        none.add(x);
        addmbzh(x + 1, k, end, none, n);
    	none.remove(none.size() - 1);
    	addmbzh(x + 1, k, end, none, n);
    }
}

在这里插入图片描述

可以出上述递归树,有很多没有用的分支,可以加入特定判断条件将无用分支剪切掉

if(none.size() + n - x + 1 < k) return;//即剩下元素不足,直接退出

dfs + 回溯 + 剪枝:

class Solution {
    public List<List<Integer>> combine(int n, int k) {
           List<List<Integer>> end = new ArrayList<>();
           List<Integer> mb = new ArrayList<>();
           
        	   addmbzh(1, k, end, mb, n);
           
           return end;
    }
    public static void addmbzh(int x, int k, List<List<Integer>> end, List<Integer> none, int n) { 
        if(none.size() + n - x + 1 < k) return;//退出条件
    	if(none.size() == k) {
          end.add(new ArrayList<Integer>(none));
          return;
        }
        none.add(x);//选
        addmbzh(x + 1, k, end, none, n);
    	none.remove(none.size() - 1);//回溯(不选)
    	addmbzh(x + 1, k, end, none, n);
    }
}

在这里插入图片描述
不难看出爆搜会超时的主要原因是一些无用枝节耗费了大量时间

本代码也可以用全局变量来写,反而更简洁

代码:

class Solution {
    List<List<Integer>> nums = new ArrayList<>();
    List<Integer> num = new ArrayList<>();
	public List<List<Integer>> combine(int n, int k) {
           dfs(1, n, k);
           return nums;
	}
	public  void dfs(int i, int n, int k) {
		if(num.size() + n - i + 1 < k) return;//剪枝
		if(num.size() == k) {
		  nums.add(new ArrayList<Integer>(num));
		  return;
		}//重要的事情最先做
		
		num.add(i);//装
		dfs(i + 1, n, k);
		num.remove(num.size() - 1);//回溯(不装)
		dfs(i + 1, n, k);
	}
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值