算法通关村——最长公共前缀问题解析

本节我们来讲一道经典的字符串问题——最长公共前缀问题,虽然该题目难度不大,但是对字符串的考察比较综合。

LeedCode14
在这里插入图片描述
要解答该问题,我们首先需要看一下公共前缀的分布有什么特点,如下图:
在这里插入图片描述
可以看到,第一种方式,我们可以采用纵向逐个字符对比的方式,每次对比完各个字符的同一位置,就向后前进一个位置,只要在某一轮对比时不相等就立即结束,返回此时前面遍历过的所有字符组成的字符串。
第二种方式,我们可以采取横向对比的方式,先比较前面两个找到公共前缀fix1,然后再和第三个比较公共前缀得到fix2,我们可以确定fix2一定不会比fix1长,然后再和第四个比较得到fix4,重复以上操作,直到最后一个fixn。我们每次得到的fix都不会比前面得到的长,最后比较完了还剩下的就是需要找的前缀了。
看到这里你是否有种似曾相识的感觉,我们前面合并K个数组或者K个链表不也是类似的思路吗?是的,就是类似的思路。
第三种方式, 我们是否可以对第二种进行优化一下,借鉴归并的思想,先两两一组找fix,然后将找到的fix再两两归并呢?当然可以了,这就是归并的方式,具体实现这里就不展开讲了,感兴趣的小伙伴可以自己尝试一下。

方法1:纵向扫描

我们来看看第一种实现方法,纵向比较。在纵向扫描时,从前往后遍历所有字符串的每一列,比较相同列上的字符是否相同,如果相同则继续对下一列进行比较,若不相同则当前列不再属于公共前缀,当前列之前的部分为最长公共前缀。

public static String longestCommonPrefix1(String[] strs) {
    // 检查输入是否为空或数组长度为0,若是则返回空字符串
    if (strs == null || strs.length == 0) {
        return "";
    }
    
    // 获取第一个字符串的长度作为最大比较长度
    int length = strs[0].length();
    int count = strs.length; // 字符串数组的长度
    
    // 逐个字符比较,从第一个字符开始
    for (int i = 0; i < length; i++) {
        // 遍历除第一个字符串外的其他字符串
        for (int j = 1; j < count; j++) {
            // 如果当前字符位置已经超过了某个字符串的长度
            // 或者当前字符位置的字符不同于第一个字符串的对应位置的字符
            if (i == strs[j].length() || strs[0].charAt(i) != strs[j].charAt(i)) {
                // 返回第一个字符串的从开头到当前位置的子串,即最长公共前缀
                return strs[0].substring(0, i);
            }
        }
    }
    
    // 若未在循环中返回,说明第一个字符串就是最长公共前缀
    return strs[0];
}

方法2:横向扫描

第二种是横着依次比较,依次遍历字符串数组中的每个字符串,对于每个遍历到的字符串,更新最长公共前缀(其实就是看是否要缩短,一定不会变长),当遍历完所有的字符串以后,即可得到字符串数组中的最长公共前缀。如果在尚未遍历完所有的字符串时,最长公共前缀已经是空串,则最长公共前缀一定是空串,因此不需要继续遍历剩下的字符串,直接返回空串即可。

public static String longestCommonPrefix(String[] strs) {
		//检查输入字符串是否为空或长度为0,若是则直接返回空字符串
        if (strs == null || strs.length == 0)
            return "";
        //初始化前缀为字符串数组中第一个字符串
        String fix = strs[0];
        int n = strs.length;
        //遍历所有字符串元素进行比较
        for (int i = 1; i < n; i++) {
        	//每次取当前的前缀字符串与下一个字符串比较,然后更新前缀字符串为比较后两字符串的相同部分
        	//前缀只减不增
            fix = longestCommonPrefix(fix,strs[i]);
            //当前缀长度为0时,不需要再进行比较,直接跳出循环
            if (fix.length() == 0){
                break;
            }
        }
        return fix;
    }

     // 求两个字符串的最长公共前缀
    public static String longestCommonPrefix(String str1, String str2) {
        int count = Math.min(str1.length(), str2.length()); // 取较短字符串的长度
        int index = 0;
        
        // 逐个字符比较直到不匹配或到达较短字符串的末尾
        while (index < count && str1.charAt(index) == str2.charAt(index)) {
            index++;
        }
        return str1.substring(0, index); // 返回公共前缀
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值