字符串 · 3/8

字符串最长公共前缀

实现查找字符串数组中最长公共前缀的算法

问题

编写一个函数,查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""

示例:

  • 输入:["flower", "flow", "flight"],输出:"fl"
  • 输入:["dog", "racecar", "car"],输出:""

解答

方法一:横向扫描

依次比较相邻字符串,逐步缩小公共前缀。

function longestCommonPrefix(strs) {
  // 空数组直接返回
  if (strs.length === 0) return "";
  
  // 以第一个字符串作为初始前缀
  let prefix = strs[0];
  
  // 依次与后面的字符串比较
  for (let i = 1; i < strs.length; i++) {
    // 不断缩短前缀,直到匹配
    while (strs[i].indexOf(prefix) !== 0) {
      prefix = prefix.slice(0, -1);
      // 前缀为空,说明没有公共前缀
      if (prefix === "") return "";
    }
  }
  
  return prefix;
}

// 测试
console.log(longestCommonPrefix(["flower", "flow", "flight"])); // "fl"
console.log(longestCommonPrefix(["dog", "racecar", "car"]));    // ""

方法二:纵向扫描

逐列比较所有字符串的同一位置字符。

function longestCommonPrefix(strs) {
  if (strs.length === 0) return "";
  
  // 遍历第一个字符串的每个字符
  for (let i = 0; i < strs[0].length; i++) {
    const char = strs[0][i];
    
    // 检查其他字符串同一位置的字符
    for (let j = 1; j < strs.length; j++) {
      // 超出长度或字符不匹配
      if (i >= strs[j].length || strs[j][i] !== char) {
        return strs[0].slice(0, i);
      }
    }
  }
  
  // 第一个字符串本身就是公共前缀
  return strs[0];
}

方法三:排序后比较首尾

排序后只需比较第一个和最后一个字符串。

function longestCommonPrefix(strs) {
  if (strs.length === 0) return "";
  if (strs.length === 1) return strs[0];
  
  // 字典序排序
  strs.sort();
  
  const first = strs[0];
  const last = strs[strs.length - 1];
  let i = 0;
  
  // 比较首尾字符串
  while (i < first.length && first[i] === last[i]) {
    i++;
  }
  
  return first.slice(0, i);
}

关键点

  • 横向扫描:时间 O(S),S 为所有字符总数,空间 O(1)
  • 纵向扫描:遇到不匹配立即返回,适合公共前缀较短的情况
  • 排序法:排序后首尾字符串差异最大,只需比较它们
  • 边界处理:空数组、单元素数组、空字符串
  • 实际应用:自动补全、文件路径处理、URL 匹配