LeetCode刷题 之 回溯法

LeetCode中回溯法的一些题总结

最近刷LeetCode(惭愧,前两页还没刷完···)发现在好多问题中都碰到了回溯法,并且有一个固定的模板。于是想试着总结一下,并加深记忆,希望以后碰到类似的问题能信手拈来~
利用回溯的题目,比较好识别,特点就是需要穷举才能得到答案。所以肯定是需要递归的。(吐槽一下自己,树的问题基本都需要递归,我每次碰到都要想半天···)
话不多说,上题:

  • LeetCode46 全排列
    给定一个没有重复数字的序列,返回其所有可能的全排列。
    示例:
输入:[1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

代码:

class Solution{
	public List<List<Integer>> permute(int[] nums){
		List<List<Integer>> res = new ArrayList<>();
		backtrack(res, new ArrayList<>(), nums);
		return res;
	}
	public void backtrack(List<List<Integer>> res, List<Integer> list, int[]nums){
		if(list.size() == nums.length){
			res.add(new ArrayList<>(list));
		} else {
			for(int i = 0; i < nums.length; i++){
				if(list.contains(nums[i])){
					continue;
				}
				list.add(nums[i]);
				backtrack(res, list, nums);
				list.remove(list.size()-1);
			}
		}
	}
}
  • LeetCode 47 给定一个可包含重复数字的排列,返回所有不重复的全排列
    示例:
输入:[1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]

和上面的题相比,除了回溯外,为了不引入重复项,需要进行剪枝操作.因此,我们引入一个标记是否被访问过的变量。
在这里插入图片描述
图片来自微信公众号Leetcode名企之路
下面是代码

class Solution{
	public List<List<Integer>> permuteUnique(int[] nums){
		List<List<Integer>> res = new ArrayList<>();
		Arrays.sort(nums);
		boolean[] used = new boolean[nums.length];//标记是否被访问过
		backtrack(res, new ArrayList<>(), nums, used);
		return res;
	}
	public void backtrack(List<List<Integer>> res, List<Integer> list, int[] nums, boolean[] used){
		if(list.size() == nums.length){
			res.add(new ArrayList<>(list));
		} else {
			for(int i = 0; i < nums.length; i++){
				if(used[i]) continue;
				if(i > 0 && nums[i-1] == nums[i] && !used[i - 1]) continue;
				used[i] = true;
				list.add(nums[i]);
				backtrack(res, list, nums, used);
				used[i] = false;
				list.remove(list.size()-1);
			}
		}
	}
}
  • LeetCode77 组合
    给定两个整数n和k,返回1~n中所有可能的k个数的组合
    示例:
输入:n=4, k= 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4]
]

直接上代码

class Solution{
	public List<List<Integer>> combine(int n, int k){
		List<List<Integer>> res = new ArrayList<>();
		backtrack(res, new ArrayList<>(), n, k, 1);
		return res;
	}
	public void backtrack(List<List<Integer>> res, List<Integer> list, int n, int k, int start){
		if(list.size() == k){
			res.add(new ArrayList<>(list));
		} else{
			for(int i = start; i <= n; i++){
				list.add(i);
				backtrack(res, list, n, k, i+1);
				list.remove(list.size()-1);
			}
		}
	}
}
  • LeetCode78 子集
    在这里插入图片描述
    代码
class Solution{
	public List<List<Integer>> subsets(int[] nums){
		List<List<Integer>> res = new ArrayList<>();
		Arrays.sort(nums);
		backtrack(res, new ArrayList<>(), nums, 0);
		return res;
	}
	public void backtrack(List<List<Integer>> res, List<Integer> list, int[] nums, int start){
		res.add(new ArrayList<>(list));
		for(int i = start; i < nums.length; i++){
			list.add(nums[i]);
			backtrack(res,list,nums,i+1);
			list.remove(list.size()-1);
		}
	}
}

全排列和子集的区别:全排列的话需要约束每一项的元素个数,而且for循环里永远是从0开始的;子集不需要约束元素个数,因此每个解都要加入到最终解集中去,为了防止重复项,需要设置一个start,标记每次回溯从哪里开始。

代码和图参考公众号LeetCode名企之路,安利一波。

技术选型 【后端】:Java 【框架】:springboot 【前端】:vue 【JDK版本】:JDK1.8 【服务器】:tomcat7+ 【数据库】:mysql 5.7+ 项目包含前后台完整源码。 项目都经过严格调试,确保可以运行! 具体项目介绍可查看博主文章或私聊获取 助力学习实践,提升编程技能,快来获取这份宝贵的资源吧! 在当今快速发展的信息技术领域,技术选型是决定一个项目成功与否的重要因素之一。基于以下的技术栈,我们为您带来了一份完善且经过实践验证的项目资源,让您在学习和提升编程技能的道路上事半功倍。以下是该项目的技术选型和其组件的详细介绍。 在后端技术方面,我们选择了Java作为编程语言。Java以其稳健性、跨平台性和丰富的库支持,在企业级应用中处于领导地位。项目采用了流行的Spring Boot框架,这个框架以简化Java企业级开发而闻名。Spring Boot提供了简洁的配置方式、内置的嵌入式服务器支持以及强大的生态系统,使开发者能够更高效地构建和部署应用。 前端技术方面,我们使用了Vue.js,这是一个用于构建用户界面的渐进式JavaScript框架。Vue以其易上手、灵活和性能出色而受到开发者的青睐,它的组件化开发思想也有助于提高代码的复用性和可维护性。 项目的编译和运行环境选择了JDK 1.8。尽管Java已经推出了更新的版本,但JDK 1.8依旧是一种成熟且稳定的选择,广泛应用于各类项目中,确保了兼容性和稳定性。 在服务器方面,本项目部署在Tomcat 7+之上。Tomcat是Apache软件基金会下的一个开源Servlet容器,也是应用最为广泛的Java Web服务器之一。其稳定性和可靠的性能表现为Java Web应用提供了坚实的支持。 数据库方面,我们采用了MySQL 5.7+。MySQL是一种高效、可靠且使用广泛的关系型数据库管理系统,5.7版本在性能和功能上都有显著的提升。 值得一提的是,该项目包含了前后台的完整源码,并经过严格调试,确保可以顺利运行。通过项目的学习和实践,您将能更好地掌握从后端到前端的完整开发流程,提升自己的编程技能。欢迎参考博主的详细文章或私信获取更多信息,利用这一宝贵资源来推进您的技术成长之路!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值