Leetcode最长公共前缀

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

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

示例一

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

示例二

输入: ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。
  • 说明: 所有输入只包含小写字母 a-z 。

题解

1、垂直扫描法

先拿到数组中第一个字符串的第一个字符,然后与数组中其它字符串的第一个字符对比,如果相等,那么继续扫描下一个位置;如果不相等,则返回。

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.size() == 0) return "";
 
     // 求出所有字符串的最小位数
        int min = strs[0].size();
        for(int k=1; k<strs.size(); k++){
            if(strs[k].size() < min) min = strs[k].size();
        }

        for(int i=0; i<min; i++){
            for(int j=1; j<strs.size(); j++){
                if(strs[0][i] != strs[j][i]){
                    strs[0][i] = '\0'; // '\0'表示字符串最后一个位置
                    break;
                }
            }
        }
 
     // 最终输出值的位数小于等于min
        if(strs[0].size() > min) strs[0][min] = '\0';
        return strs[0];
    }
};

 2. 水平扫描法

对于字符串数组S1, S2, ...Sn,先求得S1和S2的最长公共前缀,然后用求得的公共前缀和S3进行操作,这样一直执行下去。执行过程中,如果求得的最长公共前缀为空,那么直接返回""

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.size() == 0) return "";

        string a = strs[0];
        string s = ""; // 存储最长公共前缀
        for(int i=1; i<strs.size(); i++){
            int j =0;
            while(j < a.size()){
                if(a[j] == strs[i][j]) {
                    s += a[j];
                    j++;
                }
                else j = a.size(); // 目的是退出while循环
            }
            a = s;
            if(a == "") return ""; // 最长公共前缀为空,直接返回
            s = "";
        }
        return a;
    }
};

 3. 分治法

为了求LCP(Si, Sj),可以将它分为两个子问题LCP(Si, Smid)和LCP(Smid+1, Sj),其中,mid = (i + j) / 2。所以,我们只需要求得两个子问题的解lcp_LEFT和lcp_RIGHT,然后再对两个解取的公共部分即可。

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.size() == 0) return "";

        int mid = strs.size() / 2;
        string LCP_left = LCP(0, mid-1, strs);
        string LCP_right = LCP(mid, strs.size()-1, strs);

        string s = "";
        int min = (LCP_left.size() > LCP_right.size())?LCP_right.size():LCP_left.size();

        for(int i=0; i<min; i++){
            if(LCP_left[i] == LCP_right[i]) s += LCP_left[i];
            else break;
        }
        return s;
    }

    string LCP(int start, int end, vector<string> strs){
        int min = strs[start].size();
        for(int k=start+1; k<=end; k++){
            if(strs[k].size() < min) min = strs[k].size();
        }

        for(int i= 0; i<min; i++){
            for(int j=start+1; j<=end; j++){
                if(strs[start][i] != strs[j][i]){
                    strs[start][i] = '\0';
                    break;
                }
            }
        }
        
        if(strs[start].size() > min) strs[start][min] = '\0';
        return strs[start];
    }
};

 4、二分查找法

想法就是应用二分查找法找到所有字符串的公共前缀的最大长度L。算法的查找区间是[1, minLen],其中minLen是输入数据中最短的字符串的长度,同时也是答案的最长可能长度。每一次将区间一分为二,然后丢弃一定不包含最终答案的那一个。

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.size() == 0) return "";
        if(strs.size() == 1) return strs[0];

        int min = strs[0].size();
        for(int i=1; i<strs.size(); i++){
            if(strs[i].size() < min) min = strs[i].size();
        }

        int low = 1;
        int high = min;
        while(low <= high){
            int middle = (low + high) / 2;
            if(LCP(strs, middle)) low = middle + 1;
            else high = middle - 1;
        }
        cout<<low<<high;
        strs[0][(high+low)/2] = '\0';
        return strs[0];
    }

    bool LCP(vector<string> strs, int len){
        bool flag = true; // 指示字符串的前len个字符是否都相等
        for(int j=0; j<len; j++){
            for(int k=1; k<strs.size(); k++){
                if(strs[0][j] != strs[k][j]) {
                    flag = false;
                    break;
                }
            }
        }
        
        if(!flag) return false;
        else return true;
    }
};

 5. 仅比较两个字符串

首先,假设有两个单词 "abcd"和"abcde",那么在一本涵盖了所有字母排列的字典中,这两个单词之间的单词也一定有前缀"abcd"(可以看做26进制的数)
于是,我们就只需要比较最小字典序的字符串和最大字典序的字符串。那么sort一遍数组,然后取strs[0]与strs[n-1],比较求解即可
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.size() == 0) return "";
      // sort(first, last, comp): first排序数组起始地址,last排序数组最后一个元素的后一个地址,comp排序方法,不写时默认是升序排序。
        sort(strs.begin(), strs.end()); // 默认是从大到小排序
        int i=0;
        for(i=0; i<min(strs[0].size(), strs[strs.size()-1].size()); i++){
            if(strs[0][i] != strs[strs.size()-1][i]) break;
        }
        return strs[0].substr(0, i);
    }
};

 

posted @ 2020-04-29 18:49  Crazy_Coding  阅读(159)  评论(0)    收藏  举报