1. 程式人生 > >演算法菜鳥的學習之路

演算法菜鳥的學習之路

  前言:演算法,一直是每個程式設計師的心病,確是程式的核心,很多人覺得演算法很難,沒錯,但是世界上真的有很難的事情嗎?如果不去嘗試,只去抱怨,不去嘗試,我覺得可能一輩子也就只能當一名普通的程式設計師了。有一句老話說的挺好,成功的人遇到一個難題,第一反應是想著怎麼解決它,而不是先擔心不會做,做不懂,如果不邁出第一步,後面只會更加難過。博主是個多愁善感的程式猿,不過我覺得有些東西,不該逃避的絕對不能去逃避。只有勇於面對困難,才能真正去戰勝它,哈哈,感覺有點像心靈雞湯了,好吧,開始我的初級演算法學習之路了。

一、演算法好壞的判別標準:

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),效果較好

哈哈,這就是演算法的奧妙了。