LeetCode:字符串(一)

本组囊括字符串相关题目,难度不等。

3. Longest Substring Without Repeating Characters

题目描述:中等

想到的第一种思路是暴力解法,遍历数组每次去找最长不重复子串,最后这些子串比长短。时间复杂度太高O(n²)。


此题的模式识别一:看到不含有重复,即只出现一次,一旦涉及出现次数,想到使用散列表
一般来说对于字符串,都是让字符作为键, 出现次数作为值来构建散列表。


模式识别二:字符串涉及子串,考虑滑动窗口解法。
具体做法:以一个左指针从0开始,是指滑动窗口的左边界,依次遍历完字符串,目的是找到每一个以当前字符串为头的最长不重复子串,最后可做比较;
以一个右指针从-1开始,在定了左边界后不断往右滑动,直到出现和窗口中某一数字重复的情况。
在上面的流程中,我们还需要使用一种数据结构来判断是否有重复的字符,常用的数据结构为哈希集合(即 C++ 中的 std::unordered_set,Java 中的 HashSet,Python 中的 set, JavaScript 中的 Set)。在左指针向右移动的时候,我们从哈希集合中移除一个字符,在右指针向右移动的时候,我们往哈希集合中添加一个字符。

解法(二):滑动窗口

 1 class Solution:
 2     def lengthOfLongestSubstring(self, s: str) -> int:
 3         sub = set()
 4         ans = 0
 5         n = len(s)
 6         # 左指针为i,右指针为rk
 7         rk = -1
 8         for i in range(n):
 9             if i != 0:
10                 sub.remove(s[i-1])
11             while rk+1 < n and s[rk+1] not in sub:
12                 sub.add(s[rk+1])
13                 rk += 1
14             ans = max(ans, rk-i+1) # 长度为rk-i+1,右边界-左边界+1
15         return ans

 

 

14. Longest Common Prefix

题目描述:简单

解法(一):横向扫描

采用分治的思想,也就是官方解法一的水平扫描,从左到右依次比较第一个str和下一个str的最长公共前缀;
单独写一个找两个字符串的最长公共前缀的函数,然后递归调用。

 1 class Solution:
 2     def longestCommonPrefix(self, strs: List[str]) -> str:
 3         if len(strs) == 0:
 4             return ""
 5         elif len(strs) == 1:
 6             return strs[0]
 7         else:
 8             prefix = strs[0]
 9             for i in range(1, len(strs)):
10                 prefix = self.__twoStringCommonPrefix(prefix, strs[i])
11                 if prefix == "":
12                     return prefix
13             
14             return prefix
15     
16     def __twoStringCommonPrefix(self, s1, s2):
17         n = min(len(s1), len(s2))
18         for i in range(0, n):
19             if  s1[i] != s2[i]:
20                 return s1[0:i] # 这里也是包头不包尾 记住!
21                 # 注:如果s1[0] != s2[0], 那么返回的s1[0:0]就为""!
22         return s1[0:n]

 

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

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

解法(二):纵向扫描

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

 1 class Solution:
 2     def longestCommonPrefix(self, strs: List[str]) -> str:
 3         if not strs:
 4             return ""
 5         
 6         length, count = len(strs[0]), len(strs)
 7         for i in range(length):
 8             c = strs[0][i]
 9             if any(i == len(strs[j]) or strs[j][i] != c for j in range(1, count)):
10                 return strs[0][:i]
11         
12         return strs[0]

 

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

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

 

13. Roman to Integer

题目描述:简单

首先考虑映射问题,可使用哈希表来保存罗马数字对应的十进制数值,以罗马数字为键;
发现规律:从左到右看下罗马数字,可以发现如果右边的数字小于等于左边的数字,则直接加上左边的数字,如果右边数字大于左边的数字,则减去左边的数字,遍历字符串即可,由于最后一位数字右边没有数了,最后直接加上最后一位数字即可。

解法(一):

 1 class Solution:
 2     def romanToInt(self, s: str) -> int:
 3         sum = 0
 4         hashmap = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
 5         for i in range(len(s)-1):
 6             num1 = hashmap[s[i]]
 7             num2 = hashmap[s[i+1]]
 8             if num2 > num1:
 9                 sum -= num1
10             else:    
11                 sum += num1
12         
13         sum += hashmap[s[-1]] # 最后一位右边没有数了,直接加上即可
14         return sum

 

posted @ 2020-11-10 10:18  Jesse-jia  阅读(153)  评论(0编辑  收藏  举报