易位詞的匹配

來源於一道微軟面試題,以下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的函數。

 

思考

突然想起了廖老師.

相關文章
相關標籤/搜索