基础算法之回溯算法(上篇)

前言

回溯算法篇 我想带领你把握回溯算法,这是上篇。

说要把握它,那至少得知道它是什么吧,所以我先讲回溯算法是什么。知道它是什么东西后,一个很自然的问题是它有什么用?他能解决什么类型的问题,也就是我们在什么场景下使用这类算法。这就是我论述的思路,好,开始~

论述

什么是回溯算法呢?了解回溯算法的本质之前,我们先看一个题,请跟着我的节奏一起思考。

题目是:

给定一个数n,求1-n范围中(包含1、n)所有的两个数的组合情况。

想到怎么做了吗?你肯定想到用两层for解决它,暴力枚举,这不就很容易就解决了吗?

// c语言版本
void print_combinations(int n) 
{  
    for (int i = 1; i <= n; i++) 
    {  
        for (int j = i; j <= n; j++)
        {  
            printf("%d %d\n", i, j);  
        }  
    }  
}  

 不错,这是一种解决方案,而且对于这个问题,是最优解。但是面对的问题不是这样的呢?让情况更加复杂

给定两个数n,k。求1-n范围中(包含1、n)所有的k个数的组合情况。

 你又该怎么办?你会说不就是更多嘛,k=3时,我嵌套3层,k=5时我就嵌套5层,你拿我没办法。但当你真正写代码的时候,你才会发现问题。因为这个代码结构根本就不是确定的!我无法嵌套!

我该怎么办?回溯算法来救你了,它说把我(for循环)放到递归中,让我在递归中完成它,告诉我递归几次就行。

回溯算法 这种方法给不确定层数for循环结构,创造了一种动态层数for循环结构,而这个层数正是由递归的深入所完成的。

上述问题就是leetcode上第77题https://leetcode.cn/problems/combinations/,以下是针对以上问题的回溯算法模块

void backtracking(int n, int k,int startIndex) 
{
    if(pathTop == k) 
    {
        int* temp = (int*)malloc(sizeof(int) * k);
        int i;
        for(i = 0; i < k; i++) 
        {
            temp[i] = path[i];
        }
        ans[ansTop++] = temp;
        return ;
    }

    int j;
    for(j = startIndex; j <=n ;j++) 
    {
        //将当前结点放入path数组
        path[pathTop++] = j;
        //进行递归
        backtracking(n, k, j + 1);
        //进行回溯,将数组最上层结点弹出
        pathTop--;
    }
}

 大家能看到,里面有两个for循环,从上到下第一个是一个赋值的操作,真正起作用的是下面的for循环,里面还有递归调用自己的逻辑。先不用看懂,先看个大概有个印象。其实这个模块就是在做这样一件事:通过一些条件来控制for循环的层数,来暴力枚举所有情况,将所有的组合收集起来。没错,回溯算法的本质就是暴力枚举,只不过是在递归中枚举罢了,而这也正是它的优点,可以根据情况动态的变化for循环的层数。

你现在应该知道回溯算法是什么了。第二个问题,什么时候用呢?到这了也可以自然回答上:如果当你想要暴力去枚举所有情况,而且循环的层数又是动态不确定的时候,你应该想到回溯算法,连接起、唤醒起你回溯算法相关的记忆。​当然暴力枚举这种方式并不是好的方法,时间复杂度会很高,再加上是递归调用,时间更长了。所以应该不要首选就是回溯,面对具体问题去想想有没有其他可能。

知道了回溯算法是什么,以及什么时候想到去用这算法​,接下来也就是重要的怎么去写出回溯算法了。这个一时半会还说不完,我们下回再聊

总结

回溯算法是什么?回溯算法其实就是通过暴力枚举来解决问题的一种方式。

什么时候用?当你想暴力枚举所有情况,并且循环层数还是动态变化的时候,你就选回溯。

~~~~~~

以上就是我本篇想讲的所有内容了,如果这篇文章对你有价值的话,还请点个赞,你的支持对我非常重要!

我是阿航,一位胆大包天、梦想成为大牛的学生~ 

我们下篇文章再聊

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值