当前位置: 首页 > news >正文

力扣14. 最长公共前缀:Java四种解法详解

力扣14. 最长公共前缀:Java四种解法详解

题目描述

编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""
示例
输入:strs = ["flower","flow","flight"] → 输出:"fl"
输入:strs = ["dog","racecar","car"] → 输出:""


解法一:横向扫描(逐步缩小前缀)

代码实现

public class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) return "";
        String prefix = strs[0];
        for (int i = 1; i < strs.length; i++) {
            int j = 0;
            while (j < prefix.length() && j < strs[i].length() && prefix.charAt(j) == strs[i].charAt(j)) {
                j++;
            }
            prefix = prefix.substring(0, j);
            if (prefix.isEmpty()) break;
        }
        return prefix;
    }
}

复杂度分析

  • 时间复杂度:O(mn),其中 m 是字符串平均长度,n 是数组长度。最坏情况下每个字符串都需完全比较。
  • 空间复杂度:O(1),仅需常数空间存储中间变量。

核心思路

以第一个字符串为初始前缀,依次与其他字符串逐字符比较,逐步缩小前缀范围。若中途前缀为空,则提前终止。


解法二:纵向扫描(逐列比较)

代码实现

public class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) return "";
        for (int i = 0; i < strs[0].length(); i++) {
            char c = strs[0].charAt(i);
            for (int j = 1; j < strs.length; j++) {
                if (i >= strs[j].length() || strs[j].charAt(i) != c) {
                    return strs[0].substring(0, i);
                }
            }
        }
        return strs[0];
    }
}

复杂度分析

  • 时间复杂度:O(mn),逐列比较所有字符串的每个字符。
  • 空间复杂度:O(1),无需额外存储。

核心思路

从第一个字符开始,依次比较所有字符串的同一列字符,直到某一列不匹配,返回当前列之前的子串。


解法三:排序后首尾比较

代码实现

import java.util.Arrays;

public class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) return "";
        Arrays.sort(strs);
        String first = strs[0], last = strs[strs.length - 1];
        int minLen = Math.min(first.length(), last.length());
        int i = 0;
        while (i < minLen && first.charAt(i) == last.charAt(i)) {
            i++;
        }
        return first.substring(0, i);
    }
}

复杂度分析

  • 时间复杂度:O(n log n + m),排序耗时 O(n log n),比较首尾字符串耗时 O(m)
  • 空间复杂度:O(log n),排序的栈空间开销。

核心思路

排序后,最长公共前缀只需比较首尾字符串的公共部分。排序后首尾差异最大,因此公共前缀即全局公共前缀。


解法四:利用 startsWith 方法优化

代码实现

public class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) return "";
        String prefix = strs[0];
        for (String s : strs) {
            while (!s.startsWith(prefix)) {
                prefix = prefix.substring(0, prefix.length() - 1);
                if (prefix.isEmpty()) return "";
            }
        }
        return prefix;
    }
}

复杂度分析

  • 时间复杂度:O(mn),最坏情况下每个字符均需截取。
  • 空间复杂度:O(1),直接操作字符串。

核心思路

以第一个字符串为基准,逐步缩短前缀长度,直到所有字符串均以该前缀开头。利用 startsWith 简化字符比较逻辑。


各解法对比

解法优点缺点适用场景
横向扫描逻辑清晰,代码简洁需要频繁截取子串通用场景
纵向扫描直接比较,无额外操作对空字符串处理需谨慎字符串长度差异小的场景
排序后比较减少比较次数,代码高效排序可能引入额外时间开销字符串数量较少的场景
startsWith代码简洁,易读频繁截取可能影响性能快速实现需求

示例解析

以输入 ["flower", "flow", "flight"] 为例:

  1. 横向扫描
    • 初始前缀 "flower",与 "flow" 比较后缩小为 "flow"
    • 再与 "flight" 比较,最终得到 "fl"
  2. 纵向扫描
    • 比较所有字符串的第0列字符 f,第1列字符 l,第2列字符 oi 不匹配,返回前两列 "fl"

总结

以上四种方法均可高效解决问题,推荐根据场景选择:

  • 纵向扫描:适用于字符串长度差异较小的场景,直接逐列比较效率高。
  • 排序法:若字符串数量较少,排序后首尾比较更高效。
  • startsWith:适合快速实现,代码简洁但需注意性能。

可直接复制代码到力扣运行,保证通过!


欢迎在评论区留言讨论其他优化思路或问题!

相关文章:

  • const count = ref(0);是什么意思。count最终会是什么值
  • 矩阵篇---矩阵的应用
  • 棱镜七彩受邀出席“供应链安全国家标准贯标应用深度行”活动并做主题分享
  • 动态IP与静态IP该如何选?
  • 什么是矩阵账号
  • node.js笔记
  • 实践结合理论:道路运输安全员考试知识应用与学习
  • Vue Kubernetes项目 局部布局 下拉菜单
  • 告别照片管理难题!PowerPhotos 重塑 Mac 照片管理体验
  • Docker技术系列文章,第四篇——容器数据管理
  • Windows 10/11 RDP | 冻结 / 挂起
  • 《Python实战进阶》No34:卷积神经网络(CNN)图像分类实战
  • ambiq apollo3 ADC实例程序注释
  • 认识 Express.js:Node.js 最流行的 Web 框架
  • Android面试之基础算法总结
  • 【R语言可视化】人口金字塔
  • Windows系统添加路由
  • 什么是ETL
  • Mac上Github加速方案
  • MySQL-视图
  • iis建设网站/电脑学校培训
  • 烟台免费网站建设/搜索引擎优化排名培训
  • 我是做装修的怎么样投资网站/搜索引擎优化的根本目的
  • 在线建设房屋设计网站/磁力宝
  • 怎么把做的网页放入网站/seo渠道是什么意思
  • 做网站需要哪些人手/关键词搜索优化公司