演算法菜鳥的學習之路
前言:演算法,一直是每個程式設計師的心病,確是程式的核心,很多人覺得演算法很難,沒錯,但是世界上真的有很難的事情嗎?如果不去嘗試,只去抱怨,不去嘗試,我覺得可能一輩子也就只能當一名普通的程式設計師了。有一句老話說的挺好,成功的人遇到一個難題,第一反應是想著怎麼解決它,而不是先擔心不會做,做不懂,如果不邁出第一步,後面只會更加難過。博主是個多愁善感的程式猿,不過我覺得有些東西,不該逃避的絕對不能去逃避。只有勇於面對困難,才能真正去戰勝它,哈哈,感覺有點像心靈雞湯了,好吧,開始我的初級演算法學習之路了。
一、演算法好壞的判別標準:
1.1 時間複雜度
無論是什麼東西,總有一個判別的標準,演算法也是,並不是說你說這個演算法好就好,界內是有一個專門的標準的,在保證演算法的準確性後,這個判別標準就是演算法的時間複雜度,學過資料結構的同學不會對此陌生,評價一個演算法流程的好壞,是先看時間複雜度的指標,我們在然後再分析不同資料樣本下的實際執行時間,也就是常數項時間。
通常我們一般使用O(讀作big 歐 )來表示,具體來說,在常數運算元量的表示式中,只要高階項,不要低階項,也不要高階項的係數,剩下的部分,如果記為f(N),那麼時間複雜度為O(f(N))。
下面我用上家公司的一道面試演算法題來大致說明:
題目大致是:有兩個已排序的陣列,分別是N=[ 1,2,4,5,6,7] M=[ 2,3,5,6,9,12,15,17] ,請用原生的語言將其交集求出,假設N是一個有n個元素的陣列,M是有m個元素的陣列,求出其演算法時間複雜度(要求,不用任何關於陣列內建方法或函式)
當初我碰到這道題的時候,就知道肯定是有多種演算法來解決的,現在看來大致有著三種,每種的演算法複雜度都不同。下面我用PHP語言結合程式碼對其進行說明,(本想用c的,不過真的忘了)
第一種演算法,也是最為簡單的,兩個迴圈進行遍歷即可:
<?php $m = [2,3,5,6,9,12,15,17]; $n = [1,2,4,5,6,7]; $tempArray = []; //臨時陣列 for($i = 0;$i < count($n); $i++){ for($a = 0;$a < count($m); $a++){ //如果某個陣列遍歷到最後 if(!$n[$i]||!$m[$a]){ break 2; } //匹配到相等的則放入臨時陣列中 if($n[$i] ==$m[$a]){ $tempArray[] = $n[$i]; break; } } } var_dump($tempArray);
我們簡單分析一下這種簡單粗暴的方式,基本上不懂演算法的人也會用這種方式,實際上就是遍歷而已,那麼這種所謂的演算法的時間複雜度是多少呢?
這時候我們可以引入一個概念:語言頻度
語句頻度:一條語句的重複執行次數
我們可以看出兩個迴圈的語句頻度分別為m,n,則最內層的程式碼執行的語句頻度為m*n,那麼我們可以說這個演算法的時間複雜度為O(n*m)
第二種演算法:使用二分查詢法
什麼是二分查詢法:二分查詢也稱折半查詢(Binary Search),它是一種效率較高的查詢方法。但是,折半查詢要求線性表必須採用順序儲存結構,而且表中元素按關鍵字有序排列,實現的程式碼如下:
<?php
$M = [2,3,5,6,9,12,15,17,20,34];
$N = [1,2,5,6,9,12,13,34];
$tempArray = [];
$m = 0;
$n = 0;
while($n < (count($N)-1)||$m < (count($M)-1)){
if($N[$n] < $M[$m]){
$n += 1;
}elseif($N[$n] > $M[$m]){
$m += 1;
}else{
$tempArray[] = $N[$n];
$n +=1;
}
}
var_dump($tempArray);
簡單總結一下三種演算法的差異
第一種:直接遍歷,時間複雜度為O(n*m) 效果較差
第二種:使用二分法 ,時間複雜度為O(n*log2m) 效果比上個好
第三種:使用外排法 ,時間複雜度為O(n+m),效果較好
哈哈,這就是演算法的奧妙了。