LeetCode Cookbook 字符串习题 上篇
开始 字符串部分了,这一部分的花的时间不少了 今天上午给整理出来,主要就是一些有关字符串的基本函数应用,非常需要勤加练习.
13. 罗马数字转整数
题目链接:13. 罗马数字转整数
题目大意:罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
- 例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
- I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
- X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
- C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
- 给定一个罗马数字,将其转换成整数。
例如:
输入: s = "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
解题思路:非常基础的一道题 使用哈希表是不错的选择.
class Solution:
def romanToInt(self, s: str) -> int:
hash_map = {
'I':1,'IV':4,'V':5, 'IX':9,
'X':10,'XL':40,'L':50,'XC': 90,
'C':100,'CD':400 ,'D':500,'CM':900,
'M':1000
}
idx,n = 0,len(s)
ans = 0
while idx < n:
if s[idx:idx+2] in hash_map:
ans += hash_map[s[idx:idx+2]]
idx += 2
else:
ans += hash_map[s[idx]]
idx += 1
return ans
28. 实现 strStr()
题目链接:28. 实现 strStr()
题目大意:实现 strStr() 函数。给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
说明:
- 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
- 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。
例如:
输入:haystack = "hello", needle = "ll"
输出:2
输入:haystack = "aaaaa", needle = "bba"
输出:-1
解题思路: 简单题 直接使用 in 函数就很简单.
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if len(needle) == 0: return 0
if needle not in haystack:
return -1
for i,ch in enumerate(haystack):
if ch == needle[0]:
if haystack[i:i+len(needle)] == needle:
return i
67. 二进制求和
题目链接:67. 二进制求和
题目大意:给你两个二进制字符串,返回它们的和(用二进制表示)。输入为 非空 字符串且只包含数字 1 和 0。
例如:
输入: a = "11", b = "1"
输出: "100"
输入: a = "1010", b = "1011"
输出: "10101"
解题思路:经典习题啊! 需要额外设置 进位位 carry,具体看代码.
class Solution:
def addBinary(self, a: str, b: str) -> str:
n1,n2 = len(a),len(b)
ans = ''
i,j,carry = n1-1,n2-1,0
while i>=0 or j>=0:
num1 = int(a[i]) if i>=0 else 0
num2 = int(b[j]) if j>=0 else 0
tmp = num1 + num2 + carry
carry = tmp // 2
ans = str(tmp%2) + ans
i -= 1
j -= 1
return '1'+ans if carry else ans
91. 解码方法 **
题目链接:91. 解码方法
题目大意:一条包含字母 A-Z 的消息通过以下映射进行了 编码 :
'A' -> "1"
'B' -> "2"
...
'Z' -> "26"
要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,“11106” 可以映射为:
- “AAJF” ,将消息分组为 (1 1 10 6)
- “KJF” ,将消息分组为 (11 10 6)
- 注意,消息不能分组为 (1 11 06) ,因为 “06” 不能映射为 “F” ,这是由于 “6” 和 “06” 在映射中并不等价。
- 给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数 。
- 题目数据保证答案肯定是一个 32 位 的整数。
例如:
输入:s = "12"
输出:2
解释:它可以解码为 "AB"(1 2)或者 "L"(12)。
输入:s = "226"
输出:3
解释:它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。
解题思路: 动态规划经典题,一看就懵,要多背一背这类题的求解方式,有点类似于递归的思想.
class Solution:
def numDecodings(self, s: str) -> int:
n = len(s)
dp = [1] + [0]*n
for i in range(1,n+1):
if s[i-1] != '0':
dp[i] += dp[i-1]
if i>=2 and s[i-2] != '0' and int(s[i-2:i])<=26:
dp[i] += dp[i-2]
print(dp)
return dp[n]
125. 验证回文串
题目链接:125. 验证回文串
题目大意: 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。字母和数字都属于字母数字字符。给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 。
例如:
输入: s = "A man, a plan, a canal: Panama"
输出:true
解释:"amanaplanacanalpanama" 是回文串。
输入:s = "race a car"
输出:false
解释:"raceacar" 不是回文串。。
解题思路: 简单题,重拳出击,两种编写方法,思路是一致的.
(一) 使用 循环分解字符串
class Solution:
def isPalindrome(self, s: str) -> bool:
if len(s) == 0: return True
s = ''.join(ch.lower() for ch in s if ch.isalnum())
return s == s[::-1]
(二)使用 filter 迭代器 分解字符串 稍微快一些
class Solution:
def isPalindrome(self, s: str) -> bool:
# filter 函数要比使用循环快一些
s = ''.join(filter(str.isalnum,s)).lower()
return s == s[::-1]
151. 反转字符串中的单词
题目链接:151. 反转字符串中的单词
题目大意:给你一个字符串 s ,请你反转字符串中 单词 的顺序。单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
- 注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
例如:
输入:s = "the sky is blue"
输出:"blue is sky the"
解题思路 :大胆做就成 其实也可以使用 reversed 函数
class Solution:
def reverseWords(self, s: str) -> str:
return ' '.join(s.split()[::-1])
205. 同构字符串
题目链接:205. 同构字符串
题目大意: 给定两个字符串 s 和 t ,判断它们是否是同构的。如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字符上,相同字符只能映射到同一个字符上,字符可以映射到自己本身。
例如:
输入:s = "egg", t = "add"
输出:true
输入:s = "foo", t = "bar"
输出:false
解题思路: 后面好像有一道更难一点的,一会比较一下!
class Solution:
def isIsomorphic(self, s: str, t: str) -> bool:
if len(set(s)) != len(set(t)): return False
seen = dict()
for ch1,ch2 in zip(s,t):
if ch1 not in seen:
seen[ch1] = ch2
else:
if seen[ch1] != ch2:
return False
return True
344. 反转字符串
题目链接:344. 反转字符串
题目大意: 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
例如:
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]
解题思路:简单题 这里使用的是切片的方法.
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
n = len(s)
for i in range(n//2):
s[i],s[n-1-i] = s[n-1-i],s[i]
345. 反转字符串中的元音字母
题目链接:345. 反转字符串中的元音字母
题目大意:给你一个字符串 s ,仅反转字符串中的所有元音字母,并返回结果字符串。元音字母包括 ‘a’、‘e’、‘i’、‘o’、‘u’,且可能以大小写两种形式出现。
例如:
输入:s = "hello"
输出:"holle"
解题思路: 双指针 不难.
class Solution:
def reverseVowels(self, s: str) -> str:
def isVowel(ch: str) -> bool:
if ch in 'aeiouAEIOU':
return True
else:
return False
n = len(s)
c = list(s)
i,j = 0,n-1
while i<j:
while i<=n-1 and not isVowel(c[i]):
i += 1
while j>=0 and not isVowel(c[j]):
j -= 1
if i<j:
c[i],c[j] = c[j],c[i]
i += 1
j -= 1
return ''.join(c)
387. 字符串中的第一个唯一字符
题目链接:387. 字符串中的第一个唯一字符
题目大意:给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1
例如:
输入: s = "leetcode"
输出: 0
解题思路: Counter 特别好用.
class Solution:
def firstUniqChar(self, s: str) -> int:
counter = collections.Counter(s)
for i,ch in enumerate(s):
if counter[ch] == 1:
return i
return -1
# 最好不要用 s.count 太tm慢了
# for i,ch in enumerate(s):
# if s.count(ch) == 1:
# return i
# return -1
409. 最长回文串
题目链接:409. 最长回文串
题目大意:「给定一个包含大写字母和小写字母的字符串 s ,返回 通过这些字母构造成的 最长的回文串 。在构造过程中,请注意 区分大小写 。比如 “Aa” 不能当做一个回文字符串。
例如:
输入:s = "abccccdd"
输出:7
解释:我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。
解题思路: 全部偶数+一个奇数或没有奇数
class Solution:
def longestPalindrome(self, s: str) -> int:
n = len(s)
if n == 1: return 1
counter = collections.Counter(s)
tmp = 0
for ch in counter:
if counter[ch] % 2 == 1:
tmp += 1
return n-tmp+1 if tmp else n
412. Fizz Buzz
题目链接:412. Fizz Buzz
题目大意:给你一个整数 n ,找出从 1 到 n 各个整数的 Fizz Buzz 表示,并用字符串数组 answer(下标从 1 开始)返回结果,其中:
answer[i] == “FizzBuzz” 如果 i 同时是 3 和 5 的倍数。
answer[i] == “Fizz” 如果 i 是 3 的倍数。
answer[i] == “Buzz” 如果 i 是 5 的倍数。
answer[i] == i (以字符串形式)如果上述条件全不满足。
例如:
输入:n = 5
输出:["1","2","Fizz","4","Buzz"]
解题思路: if条件判断
class Solution:
def fizzBuzz(self, n: int) -> List[str]:
ans = []
for i in range(1,n+1):
if i % 3 == 0 and i % 5 == 0:
ans.append("FizzBuzz")
elif i % 3 == 0:
ans.append("Fizz")
elif i % 5 == 0:
ans.append('Buzz')
else:
ans.append(str(i))
return ans
500. 键盘行 **
题目链接:500. 键盘行
题目大意:
给你一个字符串数组 words ,只返回可以使用在 美式键盘 同一行的字母打印出来的单词。键盘如下图所示。
美式键盘 中:
第一行由字符 “qwertyuiop” 组成。
第二行由字符 “asdfghjkl” 组成。
第三行由字符 “zxcvbnm” 组成。
例如:
输入:words = ["Hello","Alaska","Dad","Peace"]
输出:["Alaska","Dad"]
解题思路: all 函数 很好用!
class Solution:
def findWords(self, words: List[str]) -> List[str]:
hash_map =["qwertyuiop","asdfghjkl","zxcvbnm"]
ans = []
for word in words:
flag = 0
word1 = word.lower()
for i in range(3):
if all(ch in hash_map[i] for ch in word1):
ans.append(word)
return ans
537. 复数乘法
题目链接:537. 复数乘法
题目大意:复数 可以用字符串表示,遵循 “实部+虚部i” 的形式,并满足下述条件:
- 实部 是一个整数,取值范围是 [-100, 100]
- 虚部 也是一个整数,取值范围是 [-100, 100]
- i 2 = = − 1 i^2 == -1 i2==−1
- 给你两个字符串表示的复数 num1 和 num2 ,请你遵循复数表示形式,返回表示它们乘积的字符串。
例如:
输入:num1 = "1+1i", num2 = "1+1i"
输出:"0+2i"
解释:(1 + i) * (1 + i) = 1 + i2 + 2 * i = 2i ,你需要将它转换为 0+2i 的形式。
解题思路: 按照题意进行即可,需要注意 map split 等函数的运用.
class Solution:
def complexNumberMultiply(self, num1: str, num2: str) -> str:
real1, imag1 = map(int,num1[:-1].split('+'))
real2, imag2 = map(int,num2[:-1].split('+'))
real = real1*real2 - imag1*imag2
imag = real1*imag2 + real2*imag1
return str(real)+'+'+str(imag)+'i'
# return f'{real}+{imag}i'
541. 反转字符串 II
题目链接:541. 反转字符串 II
题目大意:给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
- 如果剩余字符少于 k 个,则将剩余字符全部反转。
- 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
例如:
输入:s = "abcdefg", k = 2
输出:"bacdfeg"
解题思路: reversed() 函数挺好用的!
class Solution:
def reverseStr(self, s: str, k: int) -> str:
s = list(s)
n = len(s)
# 切片[::-1] 有返回值, reverse()函数没有返回值
# 使用反向切片注意 start > end
for i in range(0,n,2*k):
# 方法1
s[i:i+k] = reversed(s[i:i+k])
# 方法2 切片的 end 位置不能写-1 即[:-1:-1] 返回空数组
# s[i:i+k] = s[i:i+k][::-1]
return ''.join(s)
557. 反转字符串中的单词 III
题目链接:557. 反转字符串中的单词 III
题目大意:给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。
例如:
输入:s = "Let's take LeetCode contest"
输出:"s'teL ekat edoCteeL tsetnoc"
解题思路: 切片倒序
class Solution:
def reverseWords(self, s: str) -> str:
ans = s.split()
for i,word in enumerate(ans):
ans[i] = word[::-1]
# print(ans)
return ' '.join(ans)
总结
字符串这一部分还是 比较简单 这一部分就只有上下了! 加油,努力,奋斗!