--- tags: 提升程式設計師的面試力 --- # 陣列和字串 1.4~1.9 ### 1.4 回文變位數: 你將得到一個字串,請寫一個函式來檢查他是否是一個回文的變位數。回文的意思是單詞或是短語無論向前讀或是向後讀都是一樣的,變位字就是字母的重新排列。回文不局限於字典單詞。 ``` class PalindromePermutationChecker { public static function isPalindromePermutation($str) { $charCounts = []; for ($i=0, $length=strlen($str); $i<$length; $i++) { $char = $str[$i]; // ignore spaces if ($char === ' ') { continue; } $char = strtolower($char); if (array_key_exists($char, $charCounts)) { $charCounts[$char]++; } else { $charCounts[$char] = 1; } } $oddCount = 0; foreach ($charCounts as $char => $count) { if ($count % 2 != 0 && ++$oddCount > 1) { return false; } } return true; } } ``` ### 一個編輯距離:可以對字串執行的編輯有三種,插入一個字元、刪除一個字元,或是替換一個字元。假設有兩個字串,請寫一個函式檢查他們是否為個或是0個的編輯距離。 ``` class OneAwayChecker { public static function isOneOrZeroAway($str1, $str2) { $length1 = strlen($str1); $length2 = strlen($str2); if (abs($length2 - $length1) > 1) { return false; } if ($length1 == $length2) { $diffCount = 0; for ($i=0; $i<$length1; $i++) { if ($str1[$i] !== $str2[$i]) { if (++$diffCount > 1) { return false; } } } } else { if ($length1 > $length2) { $longer = $str1; $shorter = $str2; $longerLength = $length1; $shorterLength = $length2; } else { $longer = $str2; $shorter = $str1; $longerLength = $length2; $shorterLength = $length1; } $diffCount = 0; for ($i=0, $j=0; $i<$longerLength && $j<$shorterLength; $i++, $j++) { $char1 = $longer[$i]; $char2 = $shorter[$j]; if ($char1 === $char2) { continue; } if (++$diffCount > 1) { return false; } $i++; // advance the cursor on the longer string an extra step because we found a diff } } return true; } } ``` ### 1.6 字元壓縮:藉由計算重複字元來實作一個執行基本字串的壓縮方法。例如:字串,aabbccccaaa將變成a2b1c5a3。如果『壓縮』字串不會變得比原來的字串更小,那個你的方法應該回傳原來的字串。可以假設字串只有大寫和小寫字母(a-z)。 ``` class StringCompressor { public static function compress($original) { $originalLength = strlen($original); $compressedTokens = []; $compressedLength = 0; $lastChar = null; $sameCharCount = 0; for ($i=0; $i<$originalLength; $i++) { $char = $original[$i]; if ($lastChar !== null && $char !== $lastChar) { $compressedToken = $lastChar . $sameCharCount; $compressedLength += strlen($compressedToken); if ($compressedLength >= $originalLength) { return $original; } $compressedTokens[] = $compressedToken; $sameCharCount = 1; } else { $sameCharCount++; } $lastChar = $char; } // if the buffer isn't empty, flush it if ($sameCharCount > 0) { $compressedToken = $lastChar . $sameCharCount; $compressedLength += strlen($compressedToken); if ($compressedLength >= $originalLength) { return $original; } $compressedTokens[] = $compressedToken; } return implode($compressedTokens); } } ``` ### 1.7 旋轉矩陣:給定一個由NxN 矩陣 表示的圖像,其中圖像中的每個像素為四個位元組,請撰寫一個方法將圖像旋轉90度,您能在同一塊記憶體中就地完成嗎? ``` class MatrixRotator { public static function rotate(array &$matrix) { // process 1 layer of the matrix at a time // starting from the outside and moving inwards for ($layer=0, $layers=floor(count($matrix)/2), $begin=0, $end=count($matrix)-1; $layer<$layers; $layer++, $begin++, $end--) { for ($i=$begin, $j=$end; $i<$end; $i++, $j--) { // perform a 4-way swap of values in the current layer $tmp = $matrix[$begin][$i]; $matrix[$begin][$i] = $matrix[$j][$begin]; $matrix[$j][$begin] = $matrix[$end][$j]; $matrix[$end][$j] = $matrix[$i][$end]; $matrix[$i][$end] = $tmp; } } } } ``` ### 零矩陣:請撰寫這樣一個演算法,如果MxN矩陣中的一個元素為0M那麼將該元素所在的整個列和欄都設為0。 ``` class ZeroMatrix { public static function zero(array &$matrix) { $leftColumnZero = false; $rowCount = count($matrix); for ($i=0; $i<$rowCount; $i++) { for ($j=0, $columnCount=count($matrix[$i]); $j<$columnCount; $j++) { if ($matrix[$i][$j] === 0) { // use the topmost cell and the leftmost cells in the // matrix to track whether the entire row/column should // be zeroed, respectively. $matrix[$i][0] = 0; if ($j === 0) { // since we are using cell (0,0) in the matrix // to track whether the top row should be zeroed // let's use a single boolean variable to track // whether the left column should be zeroed. $leftColumnZero = true; } else { $matrix[0][$j] = 0; } break; } } } // zero out rows based on zero in the first position for ($i=1; $i<$rowCount; $i++) { if ($matrix[$i][0] === 0) { for ($j=1, $columnCount=count($matrix[$i]); $j<$columnCount; $j++) { $matrix[$i][$j] = 0; } } } // zero out columns based on zero in the first position for ($j=1, $columnCount=count($matrix[0]); $j<$columnCount; $j++) { if ($matrix[0][$j] === 0) { for ($i=1; $i<$rowCount; $i++) { $matrix[$i][$j] = 0; } } } // zero out the top row if needed if ($matrix[0][0] === 0) { for ($j=1, $columnCount=count($matrix[0]); $j<$columnCount; $j++) { $matrix[0][$j] = 0; } } // zero out the left column if needed if ($leftColumnZero) { for ($i=0; $i<$rowCount; $i++) { $matrix[$i][0] = 0; } } } } ``` ### 字串旋轉:假設你有一個名為isSubString的方法,他可以檢查一個單詞是否是另外一個單詞的子字串。假設有兩個字串s1跟s2 ,限定只能使用一次的isSubString呼叫,撰寫程式碼以檢查s2是否是s1的旋轉。 ``` class StringRotationChecker { public static function isRotation($s1, $s2) { if (strlen($s1) != strlen($s2)) { return false; } return self::isSubstring($s1 . $s1, $s2); } public static function isSubstring($haystack, $needle) { if (strpos($haystack, $needle) === false) { return false; } return true; } } ```