leetcode:14. 最长公共前缀

题目来源

题目描述

在这里插入图片描述

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {

    }
};

题目解析

横向扫描

L C P ( S 1 . . . S n ) LCP(S_1... S_n) LCP(S1...Sn)表示 S 1 . . . S n S_1...S_n S1...Sn的最长公共前缀。

可以得出如下结论:
在这里插入图片描述
基于该结论,可以得到一种查找字符串数组中的最长公共前缀的简单方法。依次遍历字符串数组中的每个字符串,对于每个遍历到的字符串,更新最长公共前缀,当遍历完所有的字符串以后,即可得到字符串数组中的最长公共前缀。
在这里插入图片描述

如果在尚未遍历完所有的字符串时,最长公共前缀已经是空串,则最长公共前缀一定是空串,因此不需要继续遍历剩下的字符串,直接返回空串即可。

class Solution{
public:
    std::string helper(const std::string& str1, const std::string & str2){
        int length = std::min(str1.size(), str2.size());
        int idx = 0;
        while (idx < length && str1[idx] == str2[idx]){
            ++idx;
        }
        return str1.substr(0, idx);
    }
    std::string longestCommonPrefix(std::vector<std::string> & strs){
        if(strs.empty()){
            return "";
        }
        std::string prefix = strs[0];
        for (int i = 1; i < strs.size(); ++i) {
            prefix = helper(prefix, strs[i]);
            if(prefix.empty()){
                break;
            }
        }
        return prefix;
    }
};

在这里插入图片描述
在这里插入图片描述

纵向扫描

方法一是横向扫描,依次遍历每个字符串,更新最长公共前缀。另一种方法是纵向扫描。纵向扫描时,从前往后遍历所有字符串的每一列,比较相同列上的字符是否相同,如果相同则继续对下一列进行比较,如果不相同则当前列不再属于公共前缀,当前列之前的部分为最长公共前缀。
在这里插入图片描述

class Solution{
public:
    std::string longestCommonPrefix(std::vector<std::string> & strs){
        if(strs.empty()){
            return "";
        }

        for (int i = 0; i < strs[0].size(); ++i) {
            char c = strs[0][i];
            for (int j = 1; j < strs.size(); ++j) {
                if(j == i || c != strs[j][i]){
                    return strs[0].substr(0, i);
                }
            }
        }
        
        return strs[0];
    }
};

在这里插入图片描述

分治

注意到LCP的计算满足结合律,有以下结论
在这里插入图片描述

L C P ( S 1 . . . S n ) LCP(S_1... S_n) LCP(S1...Sn)表示 S 1 . . . S n S_1...S_n S1...Sn的最长公共前缀, 1 < k < n 1 < k < n 1<k<n

基于上面结论,可以使用分治法得到字符串数组中的最长公共前缀。

  • 对于问题 L C P ( S i . . . S j ) LCP(S_i... S_j) LCP(Si...Sj),可以分解为两个子问题 L C P ( S i . . . S m i d ) LCP(S_i... S_{mid}) LCP(Si...Smid) L C P ( S m i d + 1 . . . S j ) LCP(S_{mid+1}... S_{j}) LCP(Smid+1...Sj),其中 m i d = ( i + j ) / 2 mid = (i + j) / 2 mid=(i+j)/2
  • 对两个子问题分别求解,然后对两个子问题的解计算最长公共前缀,就是原问题的解

在这里插入图片描述

class Solution{
    std::string getPrefix(std::string lcpLeft, std::string lcpRight){
        int length = std::min(lcpLeft.length(), lcpRight.length());
        for (int i = 0; i < length; ++i) {
            if(lcpLeft[i] != lcpRight[i]){
                return lcpLeft.substr(0, i);
            }
        }
        return lcpLeft.substr(0, length);
    }
    std::string process(std::vector<std::string> & strs, int start, int end){
        if(start == end){
            return strs[start];
        }

        int mid = (start + end) / 2;
        std::string lcpLeft = process(strs, start, mid);
        std::string lcpRight = process(strs, mid + 1, end);
        return getPrefix(lcpLeft, lcpRight);
    }

public:
    
    std::string longestCommonPrefix(std::vector<std::string> & strs){
        if(strs.empty()){
            return "";
        }

        return process(strs, 0, strs.size() - 1);
    }
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值