【LeetCode】14.最长公共前缀(python版)

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

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

示例 1:

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

示例 2:

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

说明:

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

思路

本题虽然只是“容易”等级的题目,但是可以有至少五种解法,而且这是一个在搜索领域中很常见的问题,所以还是值得一看。

  1. 暴力解法
    先找到两个字符串的公共前缀,再将前缀与第三个字符串比较…,这种方法最坏情况下的时间复杂度为 O ( S ) O(S) O(S),其中 S 代表所有字符串的总长度。
    在这里插入图片描述
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if len(strs) == 0:
            return ''
        s = strs[0]
        for t in strs[1:]:
            long_common_prefix = ''
            for p, q in zip(s, t):
                if p == q:
                    long_common_prefix += p
                else:
                    break
            s = long_common_prefix
            # 出现空串时提前结束
            if s == '':
            	return ''
        return s
  1. 暴力算法的实现上可以稍微转变思路,传统的寻找共同子串是一个“加法”操作,每找到一个相同字符就就添加进变量 l o n g _ c o m m o n _ p r e f i x long\_common\_prefix long_common_prefix 。实际上也可以采用“减法”操作,在 t 串中寻找 s 串,假如没找到或者不是在开头,就缩短 s 串。这样实际上并没有减少时间复杂度,只是写法上更简单。
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
	    if len(strs) == 0:
	            return ''
        long_common_prefix = strs[0]
        for s in strs[1:]:
            while s.find(long_common_prefix) != 0:
                long_common_prefix = long_common_prefix[:-1]
                if long_common_prefix == '':
                    return ''
        return long_common_prefix
  1. 纵向扫描:可以想象把所有字符串堆叠起来,依次比较所有字符串的第一个字符、第二个字符、第三个字符…,直到遇到某个位置的字符不全相等。同样需要比较所有字符,所以时间复杂度不变
    在这里插入图片描述
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if len(strs) == 0:
            return ''
        for i in range(len(strs[0])):
            for s in strs[1:]:
                if i == len(s) or s[i] != strs[0][i]:
                    return s[:i]
        return strs[0]
  1. 分治法:对于方法2,可以采用分治思想,将数组从中间一分为二,分别求两边子数组的最长公共前缀。而每一个子数组也可以一分为二…

    分治法实际上也没有减少比较的次数,因此时间复杂度不变。同时因为采用了递归,所以空间复杂度为 O ( m ⋅ l o g ( n ) ) O(m\cdot log(n)) O(mlog(n)), n为字符串个数,m为字符串长度
    在这里插入图片描述

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if len(strs) == 0:
            return ''
        return self.split_list(strs, 0, len(strs)-1)

    def split_list(self, strs, start, end):
        if start == end:
            return strs[start]
        else:
            middle = (end + start) // 2
            left_str = self.split_list(strs, start, middle)
            right_str = self.split_list(strs, middle + 1, end)
            return self.get_common_prefix(left_str, right_str)

    def get_common_prefix(self, s, t):
        min_len = min(len(s), len(t))
        for i in range(min_len):
            if s[i] != t[i]:
                return s[:i]
        return s[:min_len]
  1. 二分查找法
    这里借用官方题解的图进行说明。首先找到所有字符串最短的长度,因为这是最终答案的最大可能长度。根据这个最短字符串S进行二分查找,那么查找区间为 ( 0 , m i n L e n ) (0, minLen) (0,minLen)。每次区间一分为二,丢弃不可能包含正确答案的那一半。具体来说二分查找中会出现两种情况:
    ① S[0, mid]是其余所有字符串的前缀,那么对于S[0, i] (i < mid)来说,它都是所有串的公共前缀。由于想要找的是最长的公共前缀,所以可以把前半个区间丢弃
    ② S[0, mid]不是其余所有字符串的前缀,那么对于S[0, i] (i > mid)来说,它更不可能是所有串的公共前缀,所以可以丢弃后半个区间
    在这里插入图片描述
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if len(strs) == 0:
            return ''
            
        def is_common_prefix(prefix, str_list):
            for s in str_list:
                if s[:len(prefix)] != prefix:
                    return False
            return True
            
        min_str = min(strs, key=len)
        start, end = 0, len(min_str)
        while start < end:
            mid = (end + start + 1) // 2
            if is_common_prefix(min_str[:mid], strs):
                start = mid
            else:
                end = mid - 1
        return min_str[:(end + start) // 2]
  1. 一些使用 Python 的奇淫技巧(来自于官方讨论区中 @xshura 用户的回答):
    ① Python 中字符串是可以进行比较的,原生的 min()和 max()函数甚至 sort()函数会根据单个字符的 ascii码排序,例abb, aba,abac,最大为abb,最小为aba。所以只需要比较最大最小的公共前缀就是整个数组的公共前缀
    def longestCommonPrefix(self, strs):
        if not strs: return ""
        s1 = min(strs)
        s2 = max(strs)
        for i,x in enumerate(s1):
            if x != s2[i]:
                return s2[:i]
        return s1

②. 方法三如果使用python,可以有更加简单的写法

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        s = ""
        """ 
        >>> a = [[1,2,3], [4,5,6]]
        >>> zip(*a)
        >>> [[1,4], [2,5], [3,6]]
        """
        for i in zip(*strs):
            if len(set(i)) == 1:
                s += i[0]
            else:
                break
        return s
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你好!对于LeetCode上的问题994.腐烂的橘子,你可以使用Python来解决。下面是一个示例代码: ```python from collections import deque def orangesRotting(grid): # 记录网格的行数和列数 row, col = len(grid), len(grid[0]) # 定义四个方向:上、下、左、右 directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] # 使用队列来保存腐烂的橘子的位置 queue = deque() # 记录新鲜橘子的数量 fresh_count = 0 # 遍历整个网格,初始化队列和新鲜橘子的数量 for i in range(row): for j in range(col): if grid[i][j] == 2: # 腐烂的橘子 queue.append((i, j)) elif grid[i][j] == 1: # 新鲜橘子 fresh_count += 1 # 如果新鲜橘子的数量为0,直接返回0 if fresh_count == 0: return 0 # 初始化分钟数 minutes = 0 # 开始进行BFS,直到队列为空 while queue: # 记录当前分钟数下,队列中的元素数量 size = len(queue) # 遍历当前分钟数下的所有腐烂的橘子 for _ in range(size): x, y = queue.popleft() # 遍历四个方向 for dx, dy in directions: nx, ny = x + dx, y + dy # 判断新位置是否在网格内,并且是新鲜橘子 if 0 <= nx < row and 0 <= ny < col and grid[nx][ny] == 1: # 将新鲜橘子变为腐烂状态 grid[nx][ny] = 2 # 将新鲜橘子的位置加入队列 queue.append((nx, ny)) # 新鲜橘子的数量减1 fresh_count -= 1 # 如果当前分钟数下,没有新鲜橘子了,结束循环 if fresh_count == 0: break # 每遍历完一层,分钟数加1 minutes += 1 # 如果最后还有新鲜橘子,返回-1,否则返回分钟数 return -1 if fresh_count > 0 else minutes ``` 你可以将给定的网格作为参数传递给`orangesRotting`函数来测试它。请注意,该代码使用了BFS算法来遍历橘子,并计算腐烂的分钟数。希望能对你有所帮助!如果有任何疑问,请随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值