【笔试面试】六大常见算法及经典题目
推荐大家好好看看《数据结构与算法》...忘了刷,刷了忘...万事开头难...一口吃不成一个胖子;只有多练才能熟练应用各种数据结构和各种算法,后面会分享自己的刷题笔记;
一、递归
- 一个函数调用其自身
- 对应的数据结构:栈
- 递归的数学模型其实就是数学归纳法
- 递归的基本思想就是把规模大的问题转化为规模小的相似的子问题来解决。
- 特别地,在函数实现时,因为解决大问题的方法和解决小问题的方法往往是同一个方法,所以就产生了函数调用它自身的情况,这也正是递归的定义所在。格外重要的是,这个解决问题的函数必须有明确的结束条件,否则就会导致无限递归的情况。
- 明确递归终止条件;
- 给出递归终止时的处理办法;
- 提取重复的逻辑,缩小问题规模;
- 问题的定义是按递归定义的(Fibonacci函数,阶乘,…);
- 问题的解法是递归的(有些问题只能使用递归方法来解决,例如,汉诺塔问题,…);
- 数据结构是递归的(链表、图、树等的操作,包括树的遍历,树的深度,…)
二、暴力法(枚举)
1.概述:
-
一种简单直接地解决问题的方法,just do it;
-
一般来说蛮力策略常常是最容易实现的;
2.基本思想:
简单说是一种简单直接的算法设计策略,也叫作暴力法,枚举法或者穷举法,蛮力法解决问题常常简单粗暴,常常基于问题的描述和所涉及的概念,定义直接求解,逐一列举并且处理问题所涉及的所有情形,然后得到问题的答案。虽然通常情况下蛮力法效率很低,但可以作为衡量同类问题更高效算法的准绳。
-
在求解问题的过程中往往依据循环结构来实现。
-
蛮力法适应能力强,是唯一一种几乎什么问题都能解决的一般性方法。
-
蛮力法一般容易实现,在问题规模不大的情况下,蛮力法能够快速给出一种可接受速度下的求解方法.
3.求解问题所要依据的步骤:
4.典型问题:
-
百鸡百钱问题;
-
排序问题(选择排序、冒泡排序)
-
查找问题;
三、分治法
1. 基本思想:
-
求解问题算法的复杂性一般都与问题规模相关,问题规模越小越容易处理。
-
分治法的基本思想是,将一个难以直接解决的大问题,分解为规模较小的相同子问题,直至这些子问题容易直接求解,并且可以利用这些子问题的解求出原问题的解。各个击破,分而治之。
-
分治法产生的子问题一般是原问题的较小模式,这就为使用递归技术提供了方便。递归是分治法中最常用的技术。
2. 分治法解决问题的先决条件:
-
该问题的规模缩小到一定的程度就可以容易地解决;
-
该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;
-
利用该问题分解出的子问题的解可以合并为该问题的解;
-
该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
-
划分:既然是分治,当然需要把规模为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); //将各子问题的解合并为原问题的解 }
分治法的复杂性分析:
-
分析依据-递推方程
-
两类递推方程:
第二张递推公式经过迭代法可以得到:
-
求解方法:迭代法,递归树,Master定理;
-
大整数乘法;
-
排列问题 ;
-
整数划分问题;
-
二分搜索 ;
-
矩阵乘法;(Strassen乘法)
-
归并排序;
-
快速排序;
-
线性时间选择;
-
最近点对问题;
-
棋盘覆盖问题;
四、动态规划
- 多阶段决策过程最优;
- 与分治法类似,其思想把求解的问题分成许多阶段或多个子问题,然后按顺序求解各子问题。最后一个阶段或子问题的解就是初始问题的解。
- 动态规划中分解得到的子问题往往不是互相独立的。但不同子问题的数目常常只有多项式级。用分治法求解时,有些子问题被重复计算了许多次,从而导致分治法求解问题时间复杂度较高。
- 动态规划基本思想是保留已解决的子问题的解,在需要时再查找已求得的解,就可以避免大量重复计算,进而提升算法效率。
- 求解的问题是组合优化问题;
- 求解过程需要多步判断,从小到大依次求解;
- 子问题目标函数最优解之间存在依赖关系;
- 思路
- 基本步骤
- 要素
- 01背包问题
- 换钱的方法数
- 最长公共子序列
- 最长公共子串
五、贪心算法
- 作出的选择只是在某种意义上的局部最优选择;
- 贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。
- 在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很好近似。
- 贪心算法的每步判断时,不考虑子问题的计算结果,而是根据当时情况采取“只顾眼前”的贪心策略决定取舍;
- 最优子结构性质;
- 贪心选择性质;
- 针对具体问题不同,贪心策略的选择可能有多种,如何选择合适的贪心策略并证明该策略的正确性是贪心算法设计中的一个关键问题。
- 一般可以通过对算法步数的归纳或通过对问题规模的归纳来证明贪心法的正确性。
- 会议室安排问题
- 买卖股票问题
- 分糖果问题
六、回溯法
- 子集树:当所给的问题是从n个元素的集合S中找出满足某种性质的子集时,相应的解空间树称为子集树。子集树通常有2n个叶结点
- 排列树:当所给的问题是确定n个元素满足某种性质的排列时,相应的解空间树称为排列树。排列树通常有n!个叶结点。
- 岛屿数量
- 括号生成
- 没有重复项数字的所有排列
- 二叉树根节点到叶子节点和为指定值的路径
#搞技术你要知道##笔经##Java##学习路径##校招##社招##读书笔记#分支限界法的核心思想:分支限界法中,每一个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生其所有儿子结点。在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。
此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。这个过程一直持续到找到所需的解或活结点表为空时为止。
常见的两种分支限界法
- 队列式(FIFO)分支限界法:按照队列先进先出(FIFO)原则选取下一个结点为扩展结点。
- 优先队列式分支限界法:按照优先队列中规定的优先级选取优先级最高的结点成为当前扩展结点。
回溯法 VS 分支限界法:
- 求解目标:回溯法的求解目标是找出解空间树中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出在某种意义下的最优解。
- 搜索方式的不同:回溯法以深度优先的方式搜索解空间树,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树。