1.几种基本的算法思想(分治,动态规划,回溯)

1.几种基本的算法思想

首先,我们先认识几个词:分治法,动态规划法,回溯法,分支限界法,贪心法。

我们必须知道,上面五种思想将贯穿我们的算法学习的全过程,这五种思想并没有啥深度和技术含量,他们更像是一种基石。

在我们以后写任何算法的时候,我们都要思考,我们写的这个算法是用的那种思想实现的。

1.1 分治法

1.1.1 分治法概述

分治法是计算机领域中最为常用的算法类型,其核心思想是 分而治之,其原理是:

首先将一个复杂混合的问题拆解为两个或两个以上类型相同的子问题,然后将子问题依然进行分治法处理,直到子问题本身简单到可以求解,
最终按照问题的拆解顺序,从子问题逐步向大问题结果汇总,层层向上,最终得到原问题的解。

分治法的一个典型的应用就是递归

1.1.2 分治法递归问题实例学习

分治法解决的最简单的问题是:

阶乘问题 ,求解N的阶乘(1234…*n)

这个问题看起来很简单:

class Test {
    
    static int jiecheng(int n){
        int result = 1;
        for(int i=2;i<=n;i++){
            result = result*i;
        }
        return result;
    }

   public static void main(String[] args) {
      System.out.println(jiecheng(4));
   }
}

很明显,上面的解法并不是用分治法来解决的,上面我们使用的是递增循环实现的。

下面我们应用分治法来解决这个问题:

首先我们尝试将这个问题拆分,开始我们可以想到:

我们可以将其拆为(123*…(n/2))和((n/2+1)(n/2+2)*…*n)的乘积。

拆到最后其实就是两个数相乘的结果。

所以子问题就是:两个数相乘

好了,现在子问题找到了,下面我们要思考如何将子问题的结果汇总成大问题的结果?

其实想想很简单,我们可以保留每个子问题的结果,然后将这个结果以下个子问题的入参进行求解,以此类推,可以得到最后的结果;

简单来说就是,先算出n*(n-1)的结果,然后将这个结果*(n-2),然后将这个结果*(n-3)依此类推。

写成代码就是:

class Test{
   static int jiecheng(int n){
      if(n==0)
         return 1;
      return jiecheng(n-1)*n;
   }

   public static void main(String[] args) {
      System.out.println(jiecheng(4));
   }
}

1.2.动态规划法

1.2.1 动态规划法概述

动态规划法又叫中间结果记录法,它的原理是:

将问题拆分为多个简单的子问题,对于相对重叠的子问题的结果记录在中间结果表中,当遇到相同的问题时直接查询中间结果表的结果即可。

它有效的避免了重复计算所带来的性能缺陷。

1.2.2 动态规划问题实例学习

动态规划法解决的典型的问题有:计算斐波那契数

问题描述:

给出一个数,求出它的斐波那契数

1,1,2,3,5,8,13是一个斐波那契数列,当n=5时,它的斐波那契数为8,依次类推。

很明显我们可以用递归的方式进行问题解决:

class Test{
   public int Fib(int n){
      if(n<=1)
         return 1;
      else
         return Fib(n-1)+ Fib(n-2);
   }  
}

但是递归存在重复计算的缺陷,我们先分析下用递归进行计算n=6时的计算过程:

在这里插入图片描述

我们可以看到,为了算F6,递归法重复算了F1或F0 最小子问题13次。

造成这个问题的很明显的原因是大问题之间的重复计算。

如果我们新建一个中间结果表,在计算的过程中将为计算的大问题结果存入,并在求解新大问题之前先查询这个结果集,看有没有能匹配上的,如果有直接返回,
这样我们可以节省大量时间!!! 这就是动态规划的精髓所在!!

代码表示如下:

class Test{
   public int FibonacciBetter(int n){
      int last=1;//存储前一个数
      int nextToLast=1;//存储后一个数
      int answer;//存储结果
      for(int i=1;i<n;i++){
         answer=last+nextToLast;
         nextToLast=last;
         last=answer;
      }
      return answer;
   }
}

上面的算法,在计算过程中存储需要用到的中间结果,然后使用,这是动态规划的典型应用。

在这个问题的解法中,中间结果表是:last,nextToLast,answer组成的集合。(请细细体会)

1.3.回溯法

1.3.1 回溯法概述

回溯法是一种通过不断尝试来获得最终解的方法,但并不是一个漫无目的的过程.

它在选择求解目标的过程中会利用当前条件与目标的最优匹配选择进行尝试, 即使当前失败,也能回溯到上一步继续进行最优匹配。(深度优先)

换句话说,回溯法相当于穷举搜索的巧妙实现。

1.3.2 回溯法问题实例学习

用回溯法解决的一个典型的问题就是:背包问题

问题描述:背包问题简单来说就是给定背包最大承重量,在一堆物品中怎样拿才能尽可能使得拿的物品总价值最大。

例如,有一个背包承重量15kg 有如下物品

物品名称物品质量物品价值
A450
B660
C7100
D870

目标:在不超过背包称重量的情况下拿到最大价值的物品集。

下面我们用回溯法来解决这个问题,回溯法相当于穷举的巧妙实现!!

所以下面我们先用普通的穷举方法穷举一下可能的结果:

  • A+B 110
  • A+C 150
  • A+D 120
  • B+C 160
  • B+D 130
  • C+D 170

注意:这里的穷举法省略了不符合要求的组合,在实际的算法中,其实它也是会算出来的,然后再筛掉。

最后我们可以得到,拿物品C ,D是最佳的选择。

但是如果我们按照穷举的方法,计算量为6,直到最后一次我们才能得到正确的结果。

下面我们用回溯法来进行:

使用回溯法的第一步就是选择起点,通过上面的穷举我们可以知道,一个好的起点可以帮我们节省大量时间(假如开始就选择了C作为起点或D作为起点)
如何选择起点我个人认为这要根据具体问题进行选择,例如这个问题我们可以选择单位价值最大的物品作为起点:

物品名称物品质量物品价值
A450
B660
C7100
D870

现在我们以C作为起点,使用回溯法的过程为:

  • C+A 150
  • C+B 160
  • C+D 170

注意:这里的穷举法省略了不符合要求的组合,在实际的算法中,其实它也是会算出来的,然后再筛掉。

得到结果!!! 只需三次!!

1.4.分支限界法

1.4.1 分支界限法概述

分支界限法,是以最小代价进行尝试(广度优先),它与回溯法稍有不同。

1.4.2 分支界限法解决问题

用分支界限法法解决的一个典型的问题就是:背包问题
问题描述:背包问题简单来说就是给定总价值量,在一堆物品中怎样拿才能尽可能使得拿的物品单位价值最大。

例如,有一个背包承重量15kg

物品名称物品质量物品价值
A450
B660
C740
D820

这里的标准不再是最大单位价值,而是以质量为维度来进行选择。以最小的代价获取,也就是 100/总质量最大 的组合。

他其实和回溯法的思想类似,就是维度变了,这里直接给出结果: A+C是最佳选择。

1.5 贪心法

1.5.1 贪心法概述

顾名思义,贪心法是指当前的条件下的最好选择,贪心法没有一个全局对比,也就是说走一步算一步,每步只选择当前最好的一步。
每一步为局部最优解,所以它只适用于保证每一步选择的最优解能通向下一步最优解的问题,否则,这个方法会出现时灵,时不灵的效果。

1.5.2 贪心法解决问题实例

贪心法的精髓是每次都要最好的。
典型的应用场景是,玩扑克时,我们抓牌,连续抓五张,只要保证每次抓的点数是最大的,就能保证最后的五张牌的点数最大。

OK,下面就是具体的算法基础学习阶段了,我们将学习从简单的递归到各种排序到各种数据结构的使用基础,

在学习的过程我们在练习任何一道题时,我希望我们能想到这些算法思想,将其一一对应。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小牧之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值