LeetCode-14 最长公共前缀

该文介绍了两种方法来找出字符串数组中的最长公共前缀:一种是暴力模拟,从第一个字符串开始,逐个检查其他字符串是否包含当前前缀;另一种是使用二分法,通过不断缩小可能的前缀长度来提高效率。在二分法中,特别注意了循环结束条件应为`low<=high`,以确保不会错过可能的公共前缀情况。
摘要由CSDN通过智能技术生成

题目描述

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

示例 1:
输入:strs = [“flower”,“flow”,“flight”]
输出:“fl”
示例 2:
输入:strs = [“dog”,“racecar”,“car”]
输出:“”
解释:不存在公共前缀。

思路

暴力模拟

默认将str的第一个子串作为最长公共前缀prefix。遍历每一个子串,判断当前的prefix是否是其公共前缀。
如果是,继续判断下一个子串;
如果不是,缩短当前prefix,如果prefix缩短为空字符串,那就说明str内没有公共前缀。

判断当前的prefix是否是某一子串的公共前缀可以用String类中的indexOf函数。strs[i].indexOf(prefix) 表示查找字符串 prefix 在字符串 strs[i] 中第一次出现的位置的索引,如果返回值不是 0,说明 prefix 不是 strs[i] 的前缀。
例如:

String str = "hello";
System.out.println(str.indexOf("he"));  // 输出 0
System.out.println(str.indexOf("lo"));  // 输出 3
System.out.println(str.indexOf("abc")); // 输出 -1
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++) {
            while (strs[i].indexOf(prefix) != 0) {
                prefix = prefix.substring(0, prefix.length() - 1);
                if (prefix.isEmpty()) {
                    return ""; // r
                }
            }
        }
        
        return prefix;
    }
}
二分法

显然,最长公共前缀的长度不会超过字符串数组中的最短字符串的长度minLen。还是默认在第一个字符串中查找[0,minLen]范围内的最长公共前缀。
初始设定mid为最长公共前缀右区间端点,判断前缀[0,mid]是否为所有的字符串中的公共前缀。
如果是,那么范围[0,mid]可以延长:low=mid+1
如果不是,那么范围[0,mid]得缩短:high=mid-1
二分法为什么比模拟法的效率高,是因为模拟法搜索最长公共前缀时搜索的“步幅”是1,即由[0,minLen]逐个缩减;而二分法则是将范围通过mid = (low + high) / 2减半来进行搜索。

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) return "";
        int minLen = Integer.MAX_VALUE;
        for (String str : strs)
            minLen = Math.min(minLen, str.length());
        int low = 0;
        int high = minLen-1;
        while (low <= high) {
            int middle = (low + high) / 2;
            if (isCommonPrefix(strs, mid))
                low = mid + 1;
            else
                high = mid - 1;
        }
        return strs[0].substring(0, mid);
    }

    private boolean isCommonPrefix(String[] strs, int len){
        String str1 = strs[0].substring(0,len);
        for (int i = 1; i < strs.length; i++)
            if (!strs[i].startsWith(str1)) // 枚举字符串数组中的每个字符串,检查它们是否具有该前缀。
                return false;
        return true;
    }
}

思考

为什么循环结束条件是low<=high而不是low<high呢?
因为当 low = high 时,仍然有可能存在公共前缀。例如,对于字符串数组 strs = {"abc", "abd", "acd"},最终长公共前缀的长度为1,此时 low = high = 0。如果使用 low < high 的条件,则不会在此情况下检查存在公共前缀的可能性。
二分法 什么时候用low<high 什么时候用low<=high
在二分法中,决定使用 low < high 还是 low <= high 的条件主要取决于解决的问题和答案定义。
如果答案在区间 [low, high) 中,则通常使用 low < high 的条件。
如果答案在区间 [low, high] 中,则通常使用 low <= high 的条件。
在这道题中,显然我们需要截取的前缀[0, mid]是闭区间,所以low=high时我们也得考虑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值