1. 澶у﹀叚绉岖▼搴忓憳瀹炵敤绠楁硶鎺ㄨ崘
绋嫔簭锻桦疄鐢ㄧ畻娉曟湁鐢ㄦ帹钻
绠楁硶涓: 蹇阃熸帓搴忕畻娉
蹇阃熸帓搴忔槸鐢变笢灏悸烽湇灏旀墍鍙戝𪾢镄勪竴绉嶆帓搴忕畻娉曘傚湪骞冲潎鐘跺喌涓嬶纴鎺掑簭 n 涓椤圭洰瑕丱(nlog n)娆℃瘆杈冦傚湪链鍧忕姸鍐典笅鍒欓渶瑕丱(n2)娆℃瘆杈冿纴浣呜繖绉岖姸鍐靛苟涓嶅父瑙併备簨瀹炰笂锛屽揩阃熸帓搴忛氩父鏄庢樉姣斿叾浠朞(n log n) 绠楁硶镟村揩锛屽洜涓哄畠镄勫唴閮ㄥ惊鐜 (inner loop)鍙浠ュ湪澶ч儴鍒嗙殑鏋舵瀯涓婂緢链夋晥鐜囧湴琚瀹炵幇鍑烘潵銆
蹇阃熸帓搴忎娇鐢ㄥ垎娌绘硶绛栫暐𨱒ユ妸涓涓涓茶(list)鍒嗕负涓や釜瀛愪覆琛(sub-lists)銆
绠楁硶浜: 鍫嗘帓搴忕畻娉
鍫嗘帓搴(Heapsort)鏄鎸囧埄鐢ㄥ爢杩欑嶆暟鎹缁撴瀯镓璁捐$殑涓绉嶆帓搴忕畻娉曘傚爢绉鏄涓涓杩戜技瀹屽叏浜屽弶镙戠殑缁撴瀯锛屽苟钖屾椂婊¤冻鍫嗙Н镄勬ц川:鍗冲瓙缁撶偣镄勯敭鍊兼垨绱㈠紩镐绘槸灏忎簬(鎴栬呭ぇ浜)瀹幂殑鐖惰妭镣广
鍫嗘帓搴忕殑骞冲潎镞堕棿澶嶆潅搴︿负O(nlogn)
绠楁硶涓: 褰掑苟鎺掑簭
褰掑苟鎺掑簭(Merge sort锛屽彴婀捐疟浣:钖埚苟鎺掑簭)鏄寤虹珛鍦ㄥ綊婢′綔涓婄殑涓绉嶆湁鏁堢殑鎺掑簭绠楁硶銆傝ョ畻娉曟槸閲囩敤鍒嗘不娉(Divide andConquer)镄勪竴涓闱炲父鍏稿瀷镄勫簲鐢ㄣ
绠楁硶锲:浜屽垎镆ユ垒绠楁硶
浜屽垎镆ユ垒绠楁硶鏄涓绉嶅湪链夊簭鏁扮粍涓镆ユ垒镆愪竴鐗瑰畾鍏幂礌镄勬悳绱㈢畻娉曘傛悳绱犺繃绋嬩粠鏁扮粍镄勪腑闂村厓绱犲紑濮嬶纴濡傛灉涓闂村厓绱犳eソ鏄瑕佹煡镓剧殑鍏幂礌锛屽垯鎼灭礌杩囩▼缁撴潫:濡傛灉镆愪竴鐗 瀹氩厓绱犲ぇ骞叉垨钥呭皬骞蹭腑闂村厓绱狅纴鍒椤湪鏁扮粍澶т簬鎴栧皬骞蹭腑闂村厓绱犵殑闾d竴鍗娄腑镆ユ垒锛岃屼笖璺熷紑濮嬩竴镙蜂粠涓闂村厓绱犲紑濮嬫瘆杈冦傚傛灉鍦ㄦ煇涓姝ラゆ暟缁勪负绌猴纴鍒欎唬琛ㄦ垒涓嶅埌銆傝繖 绉嶆悳绱㈢畻娉曟疮涓娆℃瘆杈冮兘浣挎悳绱㈣寖锲寸缉灏忎竴鍗娿傛姌鍗婃悳绱㈡疮娆℃妸鎼灭储鍖哄烟鍑忓皯涓鍗婏纴镞堕棿澶嶆潅搴︿负O(logn) 銆
绠楁硶浜: BFPRT(绾挎ф煡镓剧畻娉)
BFPRT绠楁硶瑙e喅镄勯梾棰桦崄鍒嗙粡鍏革纴鍗充粠镆恘涓鍏幂礌镄勫簭鍒椾腑阃夊嚭绗琸澶(绗琸灏)镄勫厓绱狅纴阃氲繃宸у欑殑鍒嗘瀽锛孊FPRT鍙浠ヤ缭璇佸湪链鍧忔儏鍐典笅浠崭负绾挎ф椂闂村嶆潅搴︺傝ョ畻 娉旷殑镐濇兂涓庡揩阃熸帓搴忔濇兂鐩镐技锛屽綋铹讹纴涓轰娇寰楃畻娉曞湪链鍧忔儏鍐典笅锛屼緷铹惰兘杈惧埌o(n)镄勬椂闂村嶆潅搴︼纴浜斾綅绠楁硶浣滆呭仛浜嗙簿濡欑殑澶勭悊銆
绠楁硶鍏: BFS(骞垮害浼桦厛鎼灭储)
骞垮害浼桦厛鎼灭储绠楁硶(Breadth-First-Search)锛屾槸涓绉嶅浘褰㈡悳绱㈢畻娉曘傜亩鍗旷殑璇碆FS鏄浠庢牴鑺傜偣寮濮嬶纴娲荤潃镙(锲)镄勫藉害阆嶅巻镙(锲)镄勮妭镣广傚傛灉镓链夎妭镣瑰潎琚璁块梾锛屽垯绠楁硶涓姝銆侭FS钖屾牱灞炰簬鐩茬洰鎼灭储銆备竴鑸鐢ㄩ槦鍒楁暟鎹缁撴瀯𨱒ヨ緟锷╁疄鐜痫FS绠楁硶銆
对于一名优秀的程序员来说,面对一个项目的需求的时候,一定会在脑海里浮现出最适合解决这个问题的方法是什么,选对了算法,就会起到事半功倍的效果,反之,则可能会使程序运行效率低下,还容易出bug。因此,熟悉掌握常用的算法,是对于一个优秀程序员最基本的要求。
那么,常用的算法都有哪些呢?一般来讲,在我们日常工作中涉及到的算法,通常分为以下几个类型:分治、贪心、迭代、枚举、回溯、动态规划。下面我们来一一介绍这几种算法。
一、分治算法
分治算法,顾名思义,是将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。
分治算法一般分为三个部分:分解问题、解决问题、合并解。
分治算法适用于那些问题的规模缩小到一定程度就可以解决、并且各子问题之间相互独立,求出来的解可以合并为该问题的解的情况。
典型例子比如求解一个无序数组中的最大值,即可以采用分治算法,示例如下:
def pidAndConquer(arr,leftIndex,rightIndex):
if(rightIndex==leftIndex+1 || rightIndex==leftIndex){
return Math.max(arr[leftIndex],arr[rightIndex]);
}
int mid=(leftIndex+rightIndex)/2;
int leftMax=pidAndConquer(arr,leftIndex,mid);
int rightMax=pidAndConquer(arr,mid,rightIndex);
return Math.max(leftMax,rightMax);
二、贪心算法
贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪心算法的基本思路是把问题分成若干个子问题,然后对每个子问题求解,得到子问题的局部最优解,最后再把子问题的最优解合并成原问题的一个解。这里要注意一点就是贪心算法得到的不一定是全局最优解。这一缺陷导致了贪心算法的适用范围较少,更大的用途在于平衡算法效率和最终结果应用,类似于:反正就走这么多步,肯定给你一个值,至于是不是最优的,那我就管不了了。就好像去菜市场买几样菜,可以经过反复比价之后再买,或者是看到有卖的不管三七二十一先买了,总之最终结果是菜能买回来,但搞不好多花了几块钱。
典型例子比如部分背包问题:有n个物体,第i个物体的重量为Wi,价值为Vi,在总重量不超过C的情况下让总价值尽量高。每一个物体可以只取走一部分,价值和重量按比例计算。
贪心策略就是,每次都先拿性价比高的,判断不超过C。
三、迭代算法
迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程。迭代算法是用计算机解决问题的一种基本方法,它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。最终得到问题的结果。
迭代算法适用于那些每步输入参数变量一定,前值可以作为下一步输入参数的问题。
典型例子比如说,用迭代算法计算斐波那契数列。
四、枚举算法
枚举算法是我们在日常中使用到的最多的一个算法,它的核心思想就是:枚举所有的可能。枚举法的本质就是从所有候选答案中去搜索正确地解。
枚举算法适用于候选答案数量一定的情况。
典型例子包括鸡钱问题,有公鸡5,母鸡3,三小鸡1,求m钱n鸡的所有可能解。可以采用一个三重循环将所有情况枚举出来。代码如下:
五、回溯算法
回溯算法是一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。
许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。
典型例子是8皇后算法。在8 8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问一共有多少种摆法。
回溯法是求解皇后问题最经典的方法。算法的思想在于如果一个皇后选定了位置,那么下一个皇后的位置便被限制住了,下一个皇后需要一直找直到找到安全位置,如果没有找到,那么便要回溯到上一个皇后,那么上一个皇后的位置就要改变,这样一直递归直到所有的情况都被举出。
六、动态规划算法
动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。
动态规划算法适用于当某阶段状态给定以后,在这阶段以后的过程的发展不受这段以前各段状态的影响,即无后效性的问题。
典型例子比如说背包问题,给定背包容量及物品重量和价值,要求背包装的物品价值最大。