Description

找出字串陣列中所有字串的最長公共前綴。如果不存在公共前綴,回傳空字串 ""

Example:

Input: strs = [“flower”,“flow”,“flight”] Output: “fl”

Intuition#

核心思路:逐字元比對所有字串,只要有一個字串不匹配就停止。

  • 公共前綴的長度不會超過最短字串的長度
  • 可以垂直掃描(逐字元比較所有字串)或水平掃描(逐一縮短前綴)

Approaches#

1: 水平掃描#

  • 概念: 以第一個字串為初始前綴,依次與後續字串比較,逐步縮短前綴
  • 時間複雜度: O(S) - S 為所有字串字元總數
  • 空間複雜度: O(1) - 只用指標
class Solution {
    fun longestCommonPrefix(strs: Array<String>): String {
        var prefix = strs[0]
        for (i in 1 until strs.size) {
            while (!strs[i].startsWith(prefix)) {
                prefix = prefix.substring(0, prefix.length - 1)
                if (prefix.isEmpty()) return ""
            }
        }
        return prefix
    }
}

⭐2: 垂直掃描#

  • 概念: 逐字元位置比較所有字串,遇到不匹配或字串結束就停止
  • 時間複雜度: O(S) - S 為所有字串字元總數(最壞情況)
  • 空間複雜度: O(1) - 只用索引
class Solution {
    fun longestCommonPrefix(strs: Array<String>): String {
        for (i in strs[0].indices) {
            val c = strs[0][i]
            for (j in 1 until strs.size) {
                if (i >= strs[j].length || strs[j][i] != c) {
                    return strs[0].substring(0, i)
                }
            }
        }
        return strs[0]
    }
}
補充:排序後比較首尾

排序後,最長公共前綴只需比較第一個和最後一個字串(因為排序保證了字典序的最大差異在首尾)。

class Solution {
    fun longestCommonPrefix(strs: Array<String>): String {
        strs.sort()
        val first = strs.first()
        val last = strs.last()
        var i = 0
        while (i < first.length && i < last.length && first[i] == last[i]) {
            i++
        }
        return first.substring(0, i)
    }
}

🔑 Takeaways#

  • Pattern: 多字串比對的經典題,垂直掃描最直觀且能提前終止
  • 關鍵技巧: 排序後比較首尾是巧妙的技巧,因為字典序排序後差異最大的一定是首尾兩個字串