Fork me on GitHub

简单-14-最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""。

示例 1:

输入: ["flower","flow","flight"]
输出: "fl"
示例 2:

输入: ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。
说明:

所有输入只包含小写字母 a-z 。

 

横向扫描法(暴力):先取数组首位为目标值,再遍历其余数组元素,与目标值各个字符依次比较,遇到不等的比较下一个数组元素并更新目标值。

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if(strs.length==0)
            return "";
        StringBuilder res = new StringBuilder(strs[0]);
        for(int i=1; i<strs.length; i++){
            int j=0;
            for(; j<strs[i].length()&&j<res.length(); j++){
                if(res.charAt(j)!=strs[i].charAt(j))
                    break;
            }
            res.delete(j,res.length());
            if(res.length()==0)
                return "";
        }
        return res.substring(0);
    }
}
/*

时间复杂度:O(mn)O(mn),其中 mm 是字符串数组中的字符串的平均长度,nn 是字符串的数量。最坏情况下,字符串数组中的每个字符串的每个字符都会被比较一次。


空间复杂度:O(1)O(1)。使用的额外空间复杂度为常数。

*/
 

纵向扫描法:从前往后依次遍历字符串的每一列,比较相同列的字符,直到某个字符达到长度上限或字符不等。

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if(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()||c!=strs[j].charAt(i))
                    return strs[0].substring(0,i);
            }
        }
        return strs[0];
    }
}
/*

时间复杂度:O(mn)O(mn),其中 mm 是字符串数组中的字符串的平均长度,nn 是字符串的数量。最坏情况下,字符串数组中的每个字符串的每个字符都会被比较一次。


空间复杂度:O(1)O(1)。使用的额外空间复杂度为常数。

*/

 分治法:递归思想,分别找出字符串数组前一半和后一半的公共前缀,再比较这两个字符串的公共前缀。

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if(strs.length==0)
            return "";
        return recursive(strs,0,strs.length-1);
    }
    public String recursive(String[]strs,int start,int end){
        if(start==end)
            return strs[start];
        int mid=(start+end)/2;
        String strLeft=recursive(strs,start,mid);
        String strRight=recursive(strs,mid+1,end);
        return commonPrefix(strLeft,strRight);
    }
    public String commonPrefix(String left, String right){
        for(int i=0; i<Math.min(left.length(),right.length()); i++){
            if(left.charAt(i)!=right.charAt(i))
                return left.substring(0,i);
        }
        return left.length()<right.length()?left:right;
    }
}
/*

时间复杂度:O(mn)O(mn),其中 mm 是字符串数组中的字符串的平均长度,nn 是字符串的数量。时间复杂度的递推式是 T(n)=2 \cdot T(\frac{n}{2})+O(m)T(n)=2⋅T(
2
n

)+O(m),通过计算可得 T(n)=O(mn)T(n)=O(mn)。


空间复杂度:O(m \log n)O(mlogn),其中 mm 是字符串数组中的字符串的平均长度,nn 是字符串的数量。空间复杂度主要取决于递归调用的层数,层数最大为 \log nlogn,每层需要 mm 的空间存储返回结果。

*/
 

 

 

二分法:依旧是用目标值遍历数组的思想。不过重点在于快速找到前缀的末索引,先将索引缩小到最小的数组元素长度,再对该索引用二分查找,如果中间值是公共前缀,则目标值大于等于它,否则相反。

该方法优化横向扫描法。

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

    public boolean isCommonPrefix(String[] strs, int length) {
        String str0 = strs[0].substring(0, length);
        int count = strs.length;
        for (int i = 1; i < count; i++) {
            String str = strs[i];
            for (int j = 0; j < length; j++) {
                if (str0.charAt(j) != str.charAt(j)) {
                    return false;
                }
            }
        }
        return true;
    }
}
/*

时间复杂度:O(mn \log m)O(mnlogm),其中 mm 是字符串数组中的字符串的最小长度,nn 是字符串的数量。二分查找的迭代执行次数是 O(\log m)O(logm),每次迭代最多需要比较 mnmn 个字符,因此总时间复杂度是 O(mn \log m)O(mnlogm)。


空间复杂度:O(1)O(1)。使用的额外空间复杂度为常数。

*/
 

 

 

排序后比较首尾元素  摘自该用户在题解下评论

//计算复杂度应考虑排序字符串数组
class
Solution { public: string longestCommonPrefix(vector<string>& strs) { if(strs.empty()) return string(); sort(strs.begin(), strs.end()); string st = strs.front(), en = strs.back(); int i, num = min(st.size(), en.size()); for(i = 0; i < num && st[i] == en[i]; i ++); return string(st, 0, i); } };

 

posted @ 2020-06-15 23:48  Faded828x  阅读(175)  评论(0编辑  收藏  举报