14.最长公共前缀

Posted summerday152

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了14.最长公共前缀相关的知识,希望对你有一定的参考价值。

14.最长公共前缀

题目描述

编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。(所有输入只包含小写字母 a-z )

官方题解

水平扫描

解题思路:将第一个字符串作为暂时的公共前缀,往后遍历,逐渐得到所有字符串的公共前缀。
技术图片

public static String longestCommonPrefix00(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){//不等于0说明第一个字符串并不是该字符串的前缀,则向前推移
            //prefix.substring(0,prefix.length()-1)  除去该字符串的最后一个字符
            prefix = prefix.substring(0,prefix.length()-1);
            //取到第一个字符,还是没有公共前缀,返回“”
            if(prefix.isEmpty()) return "";
        }
    }
    return prefix;
}

复杂度分析

  • 时间复杂度:O(S),S 是所有字符串中字符数量的总和。

    最坏的情况下,n 个字符串都是相同的。算法会将 S1 与其他字符串都做一次比较。这样就会进行 S 次字符比较,其中 S 是输入数据中所有字符数量。

  • 空间复杂度:O(1),我们只需要使用常数级别的额外空间。

垂直扫描

解题思路
从前往后枚举字符串的每一列,先比较每个字符串相同列上的字符(即不同字符串相同下标的字符)然后再进行对下一列的比较。

public static String longestCommonPrefix01(String[] strs){
    if(strs==null||strs.length==0) return "";
    //该for循环表示从前往后遍历比较某一个字符串每个位上的字符
    for(int i = 0;i<strs[0].length();i++){
        char c = strs[0].charAt(i);
        //该for循环表示从第二个字符串开始,从前往后遍历传入数组中的每个字符串
        for(int j = 1;j<strs.length;j++){
            // 两个判断条件:i
            // 1.i==strs[j].length()
            // i表示第一个字符串的位数,如果i和后面字符串的长度相等,就不对(位数是从0开始计数的,长度从1开始的)
            // 2.strs[j].charAt(i)!=c
            // 后面的字符串在相同位数时,字符不一致,即不对。
            // 两者情况任一满足一个,就返回第一个字符串0~i-1位数的字符串

            if(i==strs[j].length()||strs[j].charAt(i)!=c){
                //public String substring(int beginIndex,int endIndex)
                //返回一个字符串,该字符串是此字符串的子字符串。
                // 子串开始于指定beginIndex并延伸到字符索引endIndex - 1 。
                return strs[0].substring(0,i);

            }
        }
    }
    return strs[0];
}

复杂度分析

  • 时间复杂度:o(s),s是所有字符串的总字符数。
    最坏的情况,输入n个长度为m的相字符串,s=nm。最坏的情况和第一种一样,但是最好的情况下,只需要进行[字符串个数][最短字符串的长度]次数的比较。
  • 空间复杂度:o(1),只需要常数级别的额外空间。

分治解法

解题思路:即将所有字符串拆分,每一部分的公共前缀的公共前缀,必然是所有字符串的公共前缀。
技术图片

    public static String longestCommonPrefix02(String[] strs){
        if(strs == null||strs.length==0) return "";
        return longestCommonPrefix(strs,0,strs.length-1);
    }
    private static String longestCommonPrefix(String[] strs,int left,int right){
        //跳出递归的情况
        if(left==right){
            return strs[left];
        }
        else{
            //分治
            int mid = (left+right)/2;
            String lcpLeft = longestCommonPrefix(strs,left,mid);
            String lcpRight = longestCommonPrefix(strs,mid+1,right);
            return CommonPrefix(lcpLeft,lcpRight);
        }
    }
    //普通比较两个字符串的最长前缀的方法,按字符比较,最多是到其中较短的字符串的长度位数位置
    private static String CommonPrefix(String left,String right){
        //min变量存储较短字符串的长度
        int min = Math.min(left.length(),right.length());
        for (int i = 0; i < min; i++) {
            //两边字符串对应字符比较,一旦不一样,就截取到之前一位
            if(left.charAt(i)!=right.charAt(i)) return left.substring(0,i);
        }
        //跳出for循环,说明较短的字符串就是公共前缀
        return left.substring(0,min);
    }

复杂度分析

  • 时间复杂度:o(s),s是所有字符串的总字符数。
    最坏的情况,输入n个长度为m的相字符串。但是最好的情况下,只需要进行[字符串个数]*[最短字符串的长度]次数的比较。
  • 空间复杂度:o(mlog(n))
    内存开支主要是递归过程中使用栈空间所消耗。log(n)次递归,每次需要m的空间存储返回结果。

二分查找

解题思路:最短字符串的长度就是公共前缀的最大可能长度。将字符串一分为二,每次经过判断,丢弃一部分,最终找到公共前缀。
技术图片

public static String longestCommonPrefix03(String[] strs){
    if(strs==null||strs.length==0) return "";
    int minLen = Integer.MAX_VALUE;
    //最长公共前缀的最大可能长度就是最短的字符串长度
    //找出字符串数组中最短字符串的长度  minLen
    for(String str:strs)
        minLen = Math.min(minLen,str.length());
    int low = 1;
    int high = minLen;
    while(low<=high){
        //将查找空间一分为二
        int mid =(low+high)/2;
        //如果第一个字符串前面一半字符是所有串的公共前缀,那么就可以丢弃前一半查找空间
        if(isCommonPrefix(strs,mid))
            low = mid +1;
        //如果不是的话,丢弃后一半
        else
            high = mid -1;
    }
    //找到最长前缀的最后位置,并返回
    return strs[0].substring(0,(low+high)/2);
}
//判断传入数组的第一个字符串的前len位是不是后面的前缀,是返回true, 不是返回false
private static 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;
}

复杂度分析

  • 时间复杂度:o(s·log(n)),s是所有字符串的总字符数。
    最坏的情况,输入n个长度为m的相字符串。一共进行log(n)次迭代,每次都会进行s次比较。
  • 空间复杂度:o(1),只需要常数级别的额外空间。

以上是关于14.最长公共前缀的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode第19天 - 14. 最长公共前缀

leetcode14最长公共前缀

leetCode第14题——最长公共前缀

[leetcode 14] 最长公共前缀

2021-09-15:最长公共前缀。编写一个函数来查找字符串数组中的最长公共前缀,如果不存在公共前缀,返回空字符串 ““。力扣14。

LeetCode 14. 最长公共前缀