【笔试面试】六大常见算法及经典题目

推荐大家好好看看《数据结构与算法》...忘了刷,刷了忘...万事开头难...一口吃不成一个胖子;
只有多练才能熟练应用各种数据结构和各种算法,后面会分享自己的刷题笔记;

一、递归

1.递归概述:
  • 一个函数调用其自身
  • 对应的数据结构:栈
  • 递归的数学模型其实就是数学归纳法
2.递归的基本思想:
  • 递归的基本思想就是把规模大的问题转化为规模小的相似的子问题来解决。
  • 特别地,在函数实现时,因为解决大问题的方法和解决小问题的方法往往是同一个方法,所以就产生了函数调用它自身的情况,这也正是递归的定义所在。格外重要的是,这个解决问题的函数必须有明确的结束条件,否则就会导致无限递归的情况。
3.递归的三要素
  • 明确递归终止条件;
  • 给出递归终止时的处理办法;
  • 提取重复的逻辑,缩小问题规模;
4.递归的应用场景:
在我们实际学习工作中,递归算法一般用于解决三类问题:
  • 问题的定义是按递归定义的(Fibonacci函数,阶乘,…);
  • 问题的解法是递归的(有些问题只能使用递归方法来解决,例如,汉诺塔问题,…);
  • 数据结构是递归的(链表、图、树等的操作,包括树的遍历,树的深度,…)

二、暴力法(枚举)

1.概述

  • 一种简单直接地解决问题的方法,just do it;
  • 一般来说蛮力策略常常是最容易实现的;

2.基本思想

简单说是一种简单直接的算法设计策略,也叫作暴力法,枚举法或者穷举法,蛮力法解决问题常常简单粗暴,常常基于问题的描述和所涉及的概念,定义直接求解,逐一列举并且处理问题所涉及的所有情形,然后得到问题的答案。虽然通常情况下蛮力法效率很低,但可以作为衡量同类问题更高效算法的准绳。

  • 在求解问题的过程中往往依据循环结构来实现。

  • 蛮力法适应能力强,是唯一一种几乎什么问题都能解决的一般性方法。

  • 蛮力法一般容易实现,在问题规模不大的情况下,蛮力法能够快速给出一种可接受速度下的求解方法.

3.求解问题所要依据的步骤:

(1)确定扫描和枚举变量。
(2)确定枚举变量的范围,设置相应的循环。
(3)根据问题的描述确定约束的条件,以便找到合理的解。

4.典型问题:

  • 百鸡百钱问题;
  • 排序问题(选择排序、冒泡排序)
  • 查找问题;

三、分治法

1. 基本思想:

  • 求解问题算法的复杂性一般都与问题规模相关,问题规模越小越容易处理。

  • 分治法的基本思想是,将一个难以直接解决的大问题,分解为规模较小的相同子问题,直至这些子问题容易直接求解,并且可以利用这些子问题的解求出原问题的解。各个击破,分而治之。

  • 分治法产生的子问题一般是原问题的较小模式,这就为使用递归技术提供了方便。递归是分治法中最常用的技术。

2. 分治法解决问题的先决条件:

  • 该问题的规模缩小到一定的程度就可以容易地解决;

  • 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;

  • 利用该问题分解出的子问题的解可以合并为该问题的解;

  • 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。

如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然也可用分治法,但一般用动态规划较好;

3.分治法解决问题的基本步骤:
  • 划分:既然是分治,当然需要把规模为n的原问题划分为k个规模较小的子问题,并尽量使这k个子问题的规模大致相同。

  • 求解子问题:各子问题的解法与原问题的解法通常是相同的,可以用递归的方法求解各个子问题,有时递归处理也可以用循环来实现。

  • 合并:把各个子问题的解合并起来,合并的代价因情况不同有很大差异,分治算法的有效性很大程度上依赖于合并的实现
divide-and-conquer(P){ 
     if ( | P | <= n0) adhoc(P);   //解决小规模的问题 
  
     divide P into smaller subinstances P1,P2,...,Pk;//分解问题 
  
     for (i=1; i<=k; i++) 
         yi=divide-and-conquer(Pi);  //递归的解各子问题 
  
     return merge(y1,...,yk);  //将各子问题的解合并为原问题的解 
} 
在用分治法设计算法时,最好使子问题的规模大致相同。即将一个问题分成大小相等的k个子问题的处理方法是行之有效的。这种使子问题规模大致相等的做法是出自一种平衡(balancing)子问题的思想,它几乎总是比子问题规模不等的做法要好;

分治法的复杂性分析:
  • 分析依据-递推方程

  • 两类递推方程:

第二张递推公式经过迭代法可以得到:

  • 求解方法:迭代法,递归树,Master定理;

4.分治法求解问题的典型案例:
  • 大整数乘法;
  • 排列问题 ;
  • 整数划分问题;
  • 二分搜索 ;
  • 矩阵乘法;(Strassen乘法)
  • 归并排序;
  • 快速排序;
  • 线性时间选择;
  • 最近点对问题;
  • 棋盘覆盖问题;

四、动态规划

1. 动态规划基本思想:(递归,递推)
  • 多阶段决策过程最优;
  • 与分治法类似,其思想把求解的问题分成许多阶段或多个子问题,然后按顺序求解各子问题。最后一个阶段或子问题的解就是初始问题的解
  • 动态规划中分解得到的子问题往往不是互相独立的。但不同子问题的数目常常只有多项式级。用分治法求解时,有些子问题被重复计算了许多次,从而导致分治法求解问题时间复杂度较高。
  • 动态规划基本思想是保留已解决的子问题的解,在需要时再查找已求得的解,就可以避免大量重复计算,进而提升算法效率。
2. 动态规划算法的适用条件:
  • 求解的问题是组合优化问题;
  • 求解过程需要多步判断,从小到大依次求解;
  • 子问题目标函数最优解之间存在依赖关系;
3. 动态规划算法设计的思路、基本步骤和要素:
  • 思路
(1)将原问题分解成子问题:子问题与原问题形式相同或类似,仅仅是规模变小;
(2)确定状态:和子问题相关的各个变量的一组取值,称为一个状态;一个状态对应于一个或多个子问题,所谓某个状态下的值,就是这个状态所对应的的子问题的解;
(3)确定一些初始状态(边界状态)的值;
(4)确定状态转移方程
  • 基本步骤
(1)找出最优解的性质,并刻画其结构特征。
(2)递推地定义最优值。
(3)以自底向上的方式计算出最优值。
(4)根据计算最优值时得到的信息,构造最优解。
  • 要素
(1)最优子结构
(2)重叠子问题
(3)备忘录(表格)
4.动态规划经典题目
  • 01背包问题
  • 换钱的方法数
  • 最长公共子序列
  • 最长公共子串

五、贪心算法

1.基本思想:
  • 作出的选择只是在某种意义上的局部最优选择
  • 贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。
  • 在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很好近似。
  • 贪心算法的每步判断时,不考虑子问题的计算结果,而是根据当时情况采取“只顾眼前”的贪心策略决定取舍;
2.贪心算法的适用条件:
一般具有两个重要的性质:
  • 最优子结构性质;
  • 贪心选择性质;
贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法与动态规划算法的主要区别。
动态规划算法通常以自底向上的方式求解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题;
3.贪心算法的正确性问题:
  • 针对具体问题不同,贪心策略的选择可能有多种,如何选择合适的贪心策略并证明该策略的正确性是贪心算法设计中的一个关键问题。
  • 一般可以通过对算法步数的归纳或通过对问题规模的归纳来证明贪心法的正确性。
4.贪心算法的经典例题:
  • 会议室安排问题
  • 买卖股票问题
  • 分糖果问题

六、回溯法

1. 基本思想:在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。
2. 一般步骤:
(1)针对所给问题,确定问题的解空间:首先应明确定义问题的解空间,问题的解空间应至少包含问题的一个(最优)解。
(2)确定结点的扩展搜索规则
(3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
3. 两类典型的解空间树:
  • 子集树:当所给的问题是从n个元素的集合S中找出满足某种性质的子集时,相应的解空间树称为子集树。子集树通常有2n个叶结点
  • 排列树:当所给的问题是确定n个元素满足某种性质的排列时,相应的解空间树称为排列树。排列树通常有n!个叶结点。
4.详细的描述则为:
回溯法按深度优先策略搜索问题的解空间树。首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。回溯法的基本行为是搜索,搜索过程使用剪枝函数来为了避免无效的搜索。其中剪枝函数包括两类:
1. 使用约束函数,剪去不满足约束条件的路径;
2.使用限界函数,剪去不能得到最优解的路径。
5.经典题目:
  • 岛屿数量
  • 括号生成
  • 没有重复项数字的所有排列
  • 二叉树根节点到叶子节点和为指定值的路径
分支限界法的核心思想:
分支限界法中,每一个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生其所有儿子结点。在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。
此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。这个过程一直持续到找到所需的解或活结点表为空时为止。
常见的两种分支限界法
  • 队列式(FIFO)分支限界法:按照队列先进先出(FIFO)原则选取下一个结点为扩展结点。
  • 优先队列式分支限界法:按照优先队列中规定的优先级选取优先级最高的结点成为当前扩展结点。
回溯法 VS 分支限界法:
  1. 求解目标:回溯法的求解目标是找出解空间树中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出在某种意义下的最优解。
  2. 搜索方式的不同:回溯法以深度优先的方式搜索解空间树,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树。


本文正在参与【内行知多少】 征文活动,一起来聊聊内行人才懂的那些事吧,高额牛币和百元京东卡等你来领~


#搞技术你要知道##笔经##Java##学习路径##校招##社招##读书笔记#
全部评论
.建议大家收藏这篇帖子..忘了刷,刷了忘... 万事开头难...一口吃不成一个胖子;
1 回复
分享
发布于 2022-05-31 21:21

相关推荐

8 40 评论
分享
牛客网
牛客企业服务