力扣笔记 1 —— 简单 14 最大公共前缀

力扣 简单 14 最大公共前缀


14 最大公共前缀

作者:powcai

链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/duo-chong-si-lu-qiu-jie-by-powcai-2/

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

题目描述

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

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= strs.length <= 200
  • 0 <= strs[i].length <= 200
  • strs[i] 仅由小写英文字母组成

我的解答

不会

参考答案解析

作者:powcai

链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/duo-chong-si-lu-qiu-jie-by-powcai-2/

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

参考答案1

#解答思路1 根据python特性,取每一个单词相同为止的字母,看是否相同
def longestCommonPrefix(strs) :
    res = ""
    
    for tmp in zip(*strs): #同时取每个单词的同一位置的字母
        tmp_set = set(tmp) # 把同一位置的字母生成一个集合
        if len(tmp_set) == 1 : # 如果集合的长度为1,表示是同一个字母
            res += tmp[0]
        else:  #对应的字母不相同,退出循环
            break
    return res

zip函数的用法

来自菜鸟教程

Python zip() 函数 | 菜鸟教程 (runoob.com)

描述

zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。

我们可以使用 list() 转换来输出列表。

如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 ***** 号操作符,可以将元组解压为列表。

语法

zip 语法:

zip([iterable, ...])

参数说明:

  • iterabl -- 一个或多个迭代器;

返回值

返回一个对象。

实例

以下实例展示了 zip 的使用方法:

image-20220106105009929

python 在列表,元组,字典变量前加号。。_l_l_jh的博客-CSDN博客_python 变量前加

可以发现,在列表前加*号,会将列表拆分成一个一个的独立元素,不光是列表、元组、字典,由numpy生成的向量也可以拆分;

zip是将一个或多个可迭代对象进行包装压缩,返回将结果是列表;

通俗的说:zip()压缩可迭代对象,*号解压可迭代对象;

最后需要注意的是:

  • 可迭代对象才可以使用*号拆分;
  • 带*号变量严格来说并不是一个变量,而更应该称为参数,它是不能赋值给其他变量的,但可以作为参数传递;
#给出一个字符串组成的列表
strsList = ["flower","fa","fba"]
#输出列表 ,查看当前类型
print(strsList)
print(type(strsList))
#看一下将列表strs压缩后的结果以及类型
#逐个输出压缩后的列表里的元素以及类型
print(zip(strsList))
print(type(zip(strsList)))
for tmp in zip(strsList):
    print(tmp)
    print(type(tmp))
print("\n")
#看一下将列表strs压缩后,再解压的结果

print(*zip(strsList))
print("\n")

# 查看给列表外面加一个*的结果
# 查看 *strs 里面的元素的类型
# for循环逐个查看
print(*strsList)
mylist = [*strsList]
for elm in mylist:
    print(type(elm))
print("\n")
# 查看 将*strs 压缩后的结果
# 逐个查看将*strs压缩后的每个元素以及类型
print(zip(*strsList))
for tmp in zip(*strsList):
    print(tmp)
    print(type(tmp))
print("\n")
# 查看 将zip(*strs)解压后的结果
# 逐个输出将zip(*strs)解压后里每个元素以及类型
print(*zip(*strsList))
mylist = [*zip(*strsList)]
for elm in mylist:
    print(elm)
    print(type(elm))

结果解析

['flower', 'fa', 'fba']
<class 'list'>  # 显然, strsList是一个由字符串组成的列表,其格式为list

<zip object at 0x000001519A63B7C8>
<class 'zip'> #将其压缩后 , 变成一个zip压缩包 , 其格式为zip 类型

('flower',)  #在压缩包里每个元素是一个tuple , 由‘字符串’和",“构成
<class 'tuple'>
('fa',)
<class 'tuple'>
('fba',)
<class 'tuple'>


('flower',) ('fa',) ('fba',) #将压缩包解压,就得到了里面的这三个tuple元素




flower fa fba  
<class 'str'>
<class 'str'>
<class 'str'> #给列表list外面加一个* ,我们得到了三个字符串元素,相当于是把列表给解压了



<zip object at 0x000001519A63BA48> 
('f', 'f', 'f')
<class 'tuple'>
('l', 'a', 'b')
<class 'tuple'> #然后我们在把这三个字符串元素进行压缩 , 得到了两个tuple元素 , 每一个元素的结果都是字符串相同位置的字母 , 这个结果和直接对三个字符串压缩的结果是一样的 ,也就是下列代码的结果是一样的
print(zip('flower','fa','fba'))
for tmp in zip('flower','fa','fba'):
    print(tmp)
    print(type(tmp))
print("\n")



('f', 'f', 'f') ('l', 'a', 'b')
('f', 'f', 'f')
<class 'tuple'>
('l', 'a', 'b')
<class 'tuple'> #我们将这三个字符串形成的压缩包解压 , 得到了里面的元素 ,元素的类型是tuple ,每一个元素的结果都是字符串相同位置的字母 

参考答案2

# 思路2取一个单词 s,和后面单词比较,看 s 与每个单词相同的最长前缀是多少!遍历所有单词。
def longestCommonPrefix( s) :
        if not s: #如果字符串列表为空,返回空字符串
            return ""
        res = s[0]  #取字符串列表中第一个字符串
        i = 1
        while i < len(s): #遍历字符串列表中每个字符串

            while s[i].find(res) != 0:  
                 #在每个字符串s[i]中寻找第一个字符串res , 
                 # 其中 find函数返回下标,不包含返回-1 当返回值为0表示是从位置0开始找到了字符串res,也就是我们要找的前缀
                 # 由于我们是从完整的字符不断向前缩短的,也就是当前的最大前缀
                res = res[0:len(res)-1] #如果没有找到,我们缩短第一个字符串res,继续寻找

            i += 1
        return res

find函数

版权声明:本文为CSDN博主「交小通」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_46291589/article/details/105876080

1、find

函数功能:find函数用于检测字符串中是否包括子字符串,如果指定检测的开始和结束范围,则在该范围内进行检测,默认在整个字符串内部检测。

返回值:如果包括子字符串,则返回其下标;如果不包含则返回-1(需要注意并不返回错误类型)。

函数语法:str.find(sub[,start[.end]])

sub:指定检索的字符串
start:开始索引的位置,默认是0
end:结束索引的位置,默认是字符串的长度

2、index

函数功能:index函数用于检测字符串中是否包含子字符串,如果指定检测的开始和结束范围,则在该范围内进行检测,默认在整个字符串内部检测。

返回值:如果包括子字符串,则返回其下标;如果不包含钻返回valueerror。(这里是和find函数不同之处)

函数语法:str.index(sub[,start[.end]])

sub:指定检索的字符串
start:开始索引的位置,默认是0
end:结束索引的位置,默认是字符串的长度

3、count

函数功能:count函数用于统计字符串中子字符串出现的次数,如果指定检测的开始和结束范围,则在该范围内进行检测,默认在整个字符串内部检测。

返回值:该函数返回子字符串在字符串中出现的次数。

函数语法:str.count(sub[,start[.end]])

sub:指定检索的字符串
start:开始索引的位置,默认是0
end:结束索引的位置,默认是字符串的长度

参考答案三

#思路三 按字典排序数组,比较第一个,和最后一个单词,有多少前缀相同。

def longestCommonPrefix(strs):
        if not strs:
            return ""
        strs.sort()  #先将字符串进行排序,排序结果为按着字典顺序升序
        starts = strs[0] # 字符串列表第一个元素,第一个字符串
        ends = strs[len(strs)-1]# 字符串列表最后一个元素,最后一个字符串
        '''经过字典顺序排序后,最后一个与第一个在第i个字母必然不一致'''
        
        res = ""

        for i in range(len(starts)):
            if starts[i] == ends [i]:
                res += starts[i]
            else:
                break
        return res

sort函数

Python3 list 排序字符串排序_俊晗的博客-CSDN博客_python列表字符串排序

我觉得使用python给出的这个三个答案都很巧妙,很好得使用了Python的特性

又看了一个java写的代码

参考答案四

思路
标签:链表
当字符串数组长度为 0 时则公共前缀为空,直接返回
令最长公共前缀 ans 的值为第一个字符串,进行初始化
遍历后面的字符串,依次将其与 ans 进行比较,两两找出公共前缀,最终结果即为最长公共前缀
如果查找过程中出现了 ans 为空的情况,则公共前缀不存在直接返回
时间复杂度:O(s),s 为所有字符串的长度之和
代码

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if(strs.length == 0)  //当数组为空,直接返回空字符串
            return "";
        
        String ans = strs[0]; //将第一个字符串元素赋值给ans
        
        for(int i =1;i<strs.length;i++) { //遍历字符串列表中的每一个元素
            int j=0; //j表示相同前缀的下标,
            //找到后面每个字符串与第一个字符串的公共前缀
            for(;j<ans.length() && j < strs[i].length();j++) { //下标j要小于第一个字符串元素的长度和当前字符串的长度
                if(ans.charAt(j) != strs[i].charAt(j)) //当不在相等的时候,我们跳出循环
                    break;
            }
            
            ans = ans.substring(0, j); //把最后一个截取掉
            
            if(ans.equals(""))
                return ans;
        }
        return ans;
    }
}

画解

https://pic.leetcode-cn.com/8ccbc8d811c6d4864173ec0d09508eb11514a98157d1ce8fa4241c735a4319df-frame_00005.png

作者:guanpengchn
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/hua-jie-suan-fa-14-zui-chang-gong-gong-qian-zhui-b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

官方解答

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/zui-chang-gong-gong-qian-zhui-by-leetcode-solution/
来源:力扣(LeetCode)

https://video.leetcode-cn.com/24244423c6374e87b5abc368e498b231/f6aefcf041854c05890147c69081cb4b-c45d134a4587406c8a1f2ce03d56f930-hd.m3u8

📖 文字题解

方法一:横向扫描

image-20220106144517259

基于该结论,可以得到一种查找字符串数组中的最长公共前缀的简单方法。依次遍历字符串数组中的每个字符串,对于每个遍历到的字符串,更新最长公共前缀,当遍历完所有的字符串以后,即可得到字符串数组中的最长公共前缀。

fig1

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

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if (!strs.size()) {
            return "";
        }
        string prefix = strs[0];
        int count = strs.size();
        for (int i = 1; i < count; ++i) {
            prefix = longestCommonPrefix(prefix, strs[i]);
            if (!prefix.size()) {
                break;
            }
        }
        return prefix;
    }

    string longestCommonPrefix(const string& str1, const string& str2) {
        int length = min(str1.size(), str2.size());
        int index = 0;
        while (index < length && str1[index] == str2[index]) {
            ++index;
        }
        return str1.substr(0, index);
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/zui-chang-gong-gong-qian-zhui-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度分析

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

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

方法二:纵向扫描

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

fig2

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if (!strs.size()) {
            return "";
        }
        int length = strs[0].size();
        int count = strs.size();
        for (int i = 0; i < length; ++i) {
            char c = strs[0][i];
            for (int j = 1; j < count; ++j) {
                if (i == strs[j].size() || strs[j][i] != c) {
                    return strs[0].substr(0, i);
                }
            }
        }
        return strs[0];
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/zui-chang-gong-gong-qian-zhui-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度分析

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

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

方法三:分治

image-20220106144547879

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if (!strs.size()) {
            return "";
        }
        else {
            return longestCommonPrefix(strs, 0, strs.size() - 1);
        }
    }

    string longestCommonPrefix(const vector<string>& strs, int start, int end) {
        if (start == end) {
            return strs[start];
        }
        else {
            int mid = (start + end) / 2;
            string lcpLeft = longestCommonPrefix(strs, start, mid);
            string lcpRight = longestCommonPrefix(strs, mid + 1, end);
            return commonPrefix(lcpLeft, lcpRight);
        }
    }

    string commonPrefix(const string& lcpLeft, const string& lcpRight) {
        int minLength = min(lcpLeft.size(), lcpRight.size());
        for (int i = 0; i < minLength; ++i) {
            if (lcpLeft[i] != lcpRight[i]) {
                return lcpLeft.substr(0, i);
            }
        }
        return lcpLeft.substr(0, minLength);
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/zui-chang-gong-gong-qian-zhui-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度分析

image-20220106144432004

方法四:二分查找

image-20220106144658825

fig4

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if (!strs.size()) {
            return "";
        }
        int minLength = min_element(strs.begin(), strs.end(), [](const string& s, const string& t) {return s.size() < t.size();})->size();
        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].substr(0, low);
    }

    bool isCommonPrefix(const vector<string>& strs, int length) {
        string str0 = strs[0].substr(0, length);
        int count = strs.size();
        for (int i = 1; i < count; ++i) {
            string str = strs[i];
            for (int j = 0; j < length; ++j) {
                if (str0[j] != str[j]) {
                    return false;
                }
            }
        }
        return true;
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/zui-chang-gong-gong-qian-zhui-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度分析

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

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

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

posted @ 2022-01-06 14:51  英飞  阅读(206)  评论(0编辑  收藏  举报