來源於一道微軟面試題,以下php
兩個單詞若是包含相同的字母,次序不一樣,則稱爲字母易位詞(anagram).例如, silent和listen是字母易位詞,而apple和aplee不是易位詞.請定義函數,檢查兩個單詞是不是字母易位詞.能夠假設兩個單詞字母均爲小寫.要求算法複雜度儘可能低.面試
觀察易位詞,發現三個特色算法
1, 長度相同;apache
2, 前面單詞出現過的字母,也必定在後面的單詞中出現過;數組
3, 同一個字母在前面和後面的單詞中出現的次數相同;bash
思路一app
對前面單詞的每一個字母進行循環遍歷,看是否在後面出現過,若是出現過,則將出現的那個字母刪除,而後進行下一次循環.這裏用PHP來實現.函數
//將一個單詞轉化爲數組 function wordToArray($str=''){ $str = is_string($str) ? trim($str) : trim($str.''); $len = strlen($str); $arr = array(); if($len>0){ for($i=0;$i<$len;$i++){ $arr[]=$str[$i]; } } return $arr; } //檢查兩個字符串是否互爲字母易位詞 function checkAnagram($a='',$b=''){ //強制轉換爲字符串 $a = is_string($a) ? trim($a) : trim($a.''); $b = is_string($b) ? trim($b) : trim($b.''); //轉化爲數組 $a = wordToArray($a); $b = wordToArray($b); //檢查字符串長度 $len1 = count($a); $len2 = count($b); if($len1 != $len2){ return false; } //對第一個字符串進行循環遍歷 for($i=0;$i<$len1;$i++){ //相同次數初始化 $sameTime = 0; //對第二個字符串進行遍歷 for($j=0;$j<$len2;$j++){ //若是第一個字符串中某個字母在第二個字符串中被第一次找到 if($a[$i] === $b[$j]){ //若是找到相同的字母+1 $sameTime++; //則將第二個字符串中的該字母刪除,也就是用空字符串將其替代 unset($b[$j]); //刪除後不繼續往下遍歷,開始第一個字符串中下一個字母的循環遍歷 break; } } //若是遍歷玩第二個單詞一次相同的字母都沒有找到則爲否 if(empty($sameTime)) return false; } //若是第二個字符串的全部字母都被刪除了,說明第一個字符串中的字母都在第二個字符串中且出現次數相等 return empty($b) ? true : false; }
用 silent和listen作測試測試
$a = checkAnagram('silent','listen'); var_dump($a);
結果爲真spa
/opt/wwwroot/test/test7.php:157:boolean true
用 apple和aplle作測試,結果爲否
/opt/wwwroot/test/test7.php:157:boolean false
測試OK
思路二
易位詞組成的字母是相同的,只是順序不一樣,若是按照字母順序排序後,二者應該徹底同樣.
//將一個單詞轉化爲數組 function wordToArray($str=''){ $str = is_string($str) ? trim($str) : trim($str.''); $len = strlen($str); $arr = array(); if($len>0){ for($i=0;$i<$len;$i++){ $arr[]=$str[$i]; } } return $arr; } function checkAnagram($a='',$b=''){ //強制轉換爲字符串 $a = is_string($a) ? trim($a) : trim($a.''); $b = is_string($b) ? trim($b) : trim($b.''); //轉化爲數組 $a = wordToArray($a); $b = wordToArray($b); //檢查字符串長度 $len1 = count($a); $len2 = count($b); if($len1 != $len2){ return false; } //對兩個單詞的字母按字母順序排序,返回排序後的新數組 sort($a); sort($b); //若是兩個數組相同,返回真 return ($a==$b)? true : false; }
用 silent 和 listen 測試,返回真
$a = checkAnagram('silent','listen'); var_dump($a);
/opt/wwwroot/test/test7.php:183:boolean true
用 apple 和 aplle 測試,返回否
$a = checkAnagram('apple','aplle'); var_dump($a);
/opt/wwwroot/test/test7.php:184:boolean false
比方法一更輕鬆些
思路三
易位詞的字母組成是同樣的而且字母出現的次數一致,那麼能夠對每一個字母作計數,而後對比兩組計數,相同則爲真
function checkAnagram($str1='',$str2=''){ //強制轉換爲字符串 $str1 = is_string($str1) ? trim($str1) : trim($str1.''); $str2 = is_string($str2) ? trim($str2) : trim($str2.''); //檢查字符串長度 $len1 = strlen($str1); $len2 = strlen($str2); if($len1 != $len2){ return false; } //字符串計數器初始化 $arr1 = $arr2 = array(); //對第一個字符串作遍歷計數 for($i=0;$i<$len1;$i++){ //獲取字母在字母表中的位置 $pos = ord($str1[$i]) - ord('a'); //每出現一次就在該位置上計數+1 $arr1[$pos] +=1; } //對第二個字符串作遍歷計數 for($j=0;$j<$len1;$j++){ //獲取字母在字母表中的位置 $pos = ord($str2[$j]) - ord('a'); //每出現一次就在該位置上計數+1 $arr2[$pos] +=1; } //對兩個數組作比較 return ($arr1==$arr2)? true : false; }
用 silent 和 listen 測試,返回真
$a = checkAnagram('silent','listen'); var_dump($a);
/opt/wwwroot/test/test7.php:183:boolean true
用 apple 和 aplle 測試,返回否
$a = checkAnagram('apple','aplle'); var_dump($a);
/opt/wwwroot/test/test7.php:184:boolean false
比較三種思路的計算量
第一種思路是遍歷裏面再次遍歷,一共有n(n+1)/2次運算,複雜度爲O(n^2);
第二種思路看起來只是對每一個字母作了一次比較,也就是n個計算量.但實際上在比較以前,分別對兩個字符串作了排序處理,把排序運算包括進去後就是(n*logn+n)次運算,複雜度爲O(n*logn);
第三種思路分別對字符串進行了遍歷,最後進行了一次比較,因此計算量爲min(n+n+n, n+n+26),複雜度爲O(n);
算法複雜度
算法複雜度是指算法在編寫成可執行程序後,運行時所須要的資源,資源包括時間資源和內存資源。應用於數學和計算機導論。同一問題可用不一樣算法解決,而一個算法的質量優劣將影響到算法乃至程序的效率。算法分析的目的在於選擇合適算法和改進算法。一個算法的評價主要從時間複雜度和空間複雜度來考慮。
若要獨立於機器的軟、硬件系統來分析算法的時間耗費,則設每條語句執行一次所需的時間均是單位時間,一個算法的時間耗費就是該算法中全部語句的頻度之和。
求兩個n階方陣的乘積 C=A×B,其算法以下:
# define n 100 // n 可根據須要定義,這裏假定爲100 void MatrixMultiply(int A[n][n],int B [n][n],int C[n][n]) { //右邊列爲各語句的頻度 int i ,j ,k; for(i=0; i<n;i++) //n+1 for (j=0;j<n;j++) { //n(n+1) C[i][j]=0; //n² for (k=0; k<n; k++) //n²(n+1) C[i][j]=C[i][j]+A[i][k]*B[k][j];//n³ } }
T(n)=2n3+3n2+2n+1 (1.1)該算法中全部語句的頻度之和(即算法的時間耗費)爲:
分析:
語句(1)的循環控制變量i要增長到n,測試到i=n成立纔會終止。故它的頻度是n+1。可是它的循環體卻只能執行n次。語句(2)做爲語句(1)循環體內的語句應該執行n次,但語句(2)自己要執行n+1次,因此語句(2)的頻度是n(n+1)。同理可得語句(3),(4)和(5)的頻度分別是n2,n2(n+1)和n3。
算法MatrixMultiply的時間耗費T(n)是矩陣階數n的函數。
思考
突然想起了廖老師.