【算法】回溯问题常见题目 ——全排列、组合总和

回溯作为常见的算法之一,相信大家也曾经遇到过回溯相关的问题,觉得摸不着头脑,实际上回溯相关的问题也是有套路的。

一、什么是回溯

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就 “回溯” 返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为 “回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。
回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。
(以上解释摘自Leetcode回溯专题介绍,另外建议大家可以按照专题来刷题)

所以可以看出来,回溯就是一种深度优先遍历,先选择一条路走,直到走不通就退回来选择另一条路。

二、回溯的框架

有了上面的初步解释后,就可以得到回溯的基本框架,我们需要一些变量:所有合理的路径就是结果集,正在进行的某一个路径

   定义结果集
   定义当前路径
   back(路径,选择列表){
   
   		if(结束条件){
   
   			结果集中加入当前路径
   		}
   		for(选择 in 选择列表){
   
	   		在可选择路径中选择一条路
			back(当前路径,可继续选择的分支节点)
			撤销选择
   		}
	}
   

所以我们在考虑结果集时,就得考虑什么时候结束、选择列表分别表示什么

三、全排列

全排列系列的两题:46.全排列47.全排列II

[46] 全排列

在这里插入图片描述
首先题目声明:没有重复,那么我们就不需要使用一个数据保存已经使用过的节点状态。只要当前路径中没有存在过该数,就加入。
由于是全排列,每个数字都能作为开头,所以我们在循环时就要从nums[0]开始循环。如果遇到使用过的节点就跳过。代码如下:

class Solution {
   

    List<List<Integer>> res = new ArrayList<>();
    List<Integer> tmp = new ArrayList<>();

    public List<List<Integer>> permute(int[] nums) {
   
        if (nums.length == 0) {
   
            return res;
        }
        back(nums);
        return res;
    }

    private void back(int[] nums) {
   
        if (tmp.size() == nums.length) {
   
            res.add(new ArrayList(tmp));
            return ;
        }

        for (int i = 0; i < nums.length; i ++) {
     //每次都从0开始
            if (tmp.contains(nums[i])) continue;  //遇到使用过的就跳过

            tmp.add(nums[i]);          //选择
            back(</
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值