leetcode 经典回溯算法题目(思路、方法、code)

用于回顾数据结构与算法时刷题的一些经验记录

  • 回溯与递归都要注意剪枝,避免重复计算

  • 回溯的问题,一定要把整个树图画出来,然后再去考虑如何缩小问题,还要注意恢复状态

  • 回溯算法的大致模板:

    • 根据这个模板,然后根据自己画出的树图,基本所有回溯问题都可以搞定。
    void backtrack(已经做的选择, 选择列表):
        if 当前达到了结束位置:
            result.push(最终的选择序列)
        for 每个选择 in 选择列表:
            做选择 //可能这里需要判断选择是否可行
            backtrack(新的已选择, 新的选择列表) //这里的已选择和选择列表都要更新
            撤销选择
    
    //在此基础上,如果部分节点已经无解,则将它能够推理出的无解的树枝均剪掉
    

46. 全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:
输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

分析: 全排列的发现过程:

在这里插入图片描述

因此,每一步,我们需要确定一下当前深度的位置的元素,然后就可以继续向下展开。例如:如果在第一个位置选择了1,则在第二个位置可以选择2或者3,选择后再次选择第三个位置的元素。

如果在第i个位置选过后,则之后等价于前i个位置的元素排列已经确定,而后面实际上就是还没有排列的元素的全排列。这里就可以发现递归的思想。

因此回溯的大致思路为:

  • 函数需要保存的内容有:当前已经确定的序列,当前的位置,序列的总长度
  • 每次判断,是否已经遍历完,即当前位置是否等于序列的总长度,如果等于说明当前序列已经是一个结果,存储
  • 如果没有遍历完,则确定一下该位置的元素,然后继续递归,递归时需要将当前位置右移
  • 在这里确定元素时,可以用循环的方式直接确定,但是每次递归结束后,需要恢复现场,将状态均恢复,否则将导致回溯的难以结束或者结果不足
class Solution {
   
public:
	vector<vector<int> > result;
    vector<vector<int> > permute(vector<int>& nums) 
	{
   
    	backtrack(nums,0,nums.size());    
    	return result;
    }
    void backtrack(vector<int>& output,int first,int len) 
    //output为当前已有的排列,first表示现在排列到的位置,len为长度
	{
   
		if(first==len)
		{
   
			result.emplace_back(output);
			return ;
		}
		for(int i=first;i<len;i++) //进行回溯,每次确定好当前位置的元素后继续递归即可
		{
   
			swap(output[i],output[first]); //将目前的位置依次换成output[i]
			backtrack(output,first+1,len);
			swap(output[first],output[i]);  //回溯的关键,在于递归后要恢复现场 
		}		 
	 } 
};
78. 子集

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

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

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

分析:

方法一:枚举或递归的思想

对于 n u m s nums nums 中每个元素,都有两种考虑,即选择或者不选择,因此最终结果数目是 2 n 2^n 2n ,时间复杂度也是 O ( n 2 n ) O(n2^n) O(n2n),因为每个结果都需要加到列表中,这是一个 O ( n ) O(n) O(n

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode是一个非常受欢迎的在线技术面试准备平台,提供了各种各样的编程题目。这些题目涵盖了算法、数据结构、字符串、数组、链表等等各个方面的知识点,是面试中经常会被问到的题目类型。在这些题目中,有一些是比较经典题目,对于提高编程能力和理解算法思想非常有帮助。 对于解决这些经典题目,可以采用多种方法。首先,要理解题目的要求,搞清楚问题的规模和限制条件。然后,可以尝试用不同的数据结构或算法去解决问题,比如使用哈希表、双指针、动态规划等等。在实现解决方案的过程中,需要注意边界条件的处理,避免出现错误或运行时异常。 解题的过程中,可以采用自顶向下的递归或自底向上的迭代等不同的思路,也可以尝试从暴力解法逐步优化到更高效的解法。在遇到困难或卡壳的时候,可以参考其他人的解题思路或查看相关的讨论和解析,从而找到问题的突破口。 除了解题思路算法实现,还要注意代码的可读性和可维护性。良好的代码结构、注释和命名规范可以使代码更易理解和修改。 LeetCode经典题目全解析不仅能帮助我们更好地掌握基本的编程知识和算法思想,也能提高我们解决实际问题的能力和效率。通过反复练习和思考,我们可以逐渐熟悉常见的问题类型和解题技巧,提高我们在面试和工作中的竞争力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值