面试经典:字符串
字符串
LeetCode中的字符串题目是指需要对字符串进行操作或处理的题目,包括字符串的匹配、替换、排序、翻转、去重、分割等等操作。字符串题目常见的难点在于如何处理字符串的边界条件,如空字符串、只包含空格的字符串、字符串长度为1等特殊情况,以及字符串中的特殊字符(如空格、数字、字母等)的处理。
常见的字符串题目有:
-
实现 strStr() 函数:在一个字符串中查找另一个字符串的位置
-
反转字符串:将一个字符串反转
-
反转字符串中的单词:将一个字符串中的单词顺序反转
-
有效的括号:判断一个字符串中的括号是否匹配
-
最长公共前缀:查找多个字符串中最长的公共前缀
-
翻转字符串里的单词 III:将一个字符串中每个单词反转
-
字符串转换整数 (atoi):将一个字符串转换为整数
-
无重复字符的最长子串:查找一个字符串中最长的不包含重复字符的子串
这些题目对于掌握字符串的基本操作、边界处理以及算法思想都有很好的练习作用。
151. 反转字符串中的单词 - 力扣(Leetcode)
给你一个字符串 s
,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s
中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意: 输入字符串 s
中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 1:
输入: s = "the sky is blue"
输出: "blue is sky the"
示例 2:
输入: s = " hello world "
输出: "world hello"
解释: 反转后的字符串中不能存在前导空格和尾随空格。
示例 3:
输入: s = "a good example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。
提示:
1 <= s.length <= 104
s
包含英文大小写字母、数字和空格' '
s
中 至少存在一个 单词
进阶: 如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 O(1)
额外空间复杂度的 原地 解法。
class Solution:
def reverseWords(self, s: str) -> str:
s = s.split(' ')
ans = ''
for i in range(len(s)-1,-1,-1):
if s[i]:
ans += s[i] + ' '
return ans.strip()
函数的实现方法是先使用 split()
方法将字符串按照空格分割成一个个单词,然后从后往前遍历每个单词,并将非空单词加入答案字符串 ans
中,并在单词之间加上一个空格。最后返回答案字符串时,使用 strip()
方法将首尾多余的空格去掉。
这个函数的时间复杂度为 O(n)O(n)O(n),其中 nnn 是字符串的长度。空间复杂度取决于单词的个数,因为需要将每个单词存储在一个新的字符串中,所以空间复杂度为 O(k)O(k)O(k),其中 kkk 是单词的个数。
在 Python 中,字符串是不可变(immutable)的数据类型,这意味着一旦创建了一个字符串对象,就无法修改它的值。如果需要修改一个字符串,需要创建一个新的字符串对象,而不是修改原始的字符串对象。这个特性是由于 Python 中的字符串被视为一系列 Unicode 字符的序列,而这些字符在创建后是不能更改的。如果需要进行字符串的修改操作,可以使用一些字符串操作函数来完成,例如字符串切片、连接、替换等。
所以, 进阶问题我选择不进阶。
14. 最长公共前缀 - 力扣(Leetcode)
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例 1:
输入: strs = ["flower","flow","flight"]
输出: "fl"
示例 2:
输入: strs = ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。
提示:
1 <= strs.length <= 200
0 <= strs[i].length <= 200
strs[i]
仅由小写英文字母组成
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
ans = ''
for i in zip(*strs):
if len(set(i)) == 1:
ans += i[0]
else:
break
return ans
这个函数接受一个字符串数组 strs
作为输入,返回一个字符串,表示数组中所有字符串的最长公共前缀。
函数使用了 zip(*strs)
技巧,将字符串数组转换为元组数组,并按列进行迭代。对于每一列中的字符,如果它们都相同,则将其加入到最长公共前缀中,直到出现不同的字符或者所有字符串遍历完毕。最终返回最长公共前缀即可。
需要注意的是,如果输入的字符串数组为空或者其中任意一个字符串为空,则最长公共前缀应该是空字符串。
28. 找出字符串中第一个匹配项的下标 - 力扣(Leetcode)
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
****。
示例 1:
输入: haystack = "sadbutsad", needle = "sad"
输出: 0
解释: "sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。
示例 2:
输入: haystack = "leetcode", needle = "leeto"
输出: -1
解释: "leeto" 没有在 "leetcode" 中出现,所以返回 -1 。
提示:
1 <= haystack.length, needle.length <= 104
haystack
和needle
仅由小写英文字符组成
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
return haystack.index(needle) if needle in haystack else -1
代码实现了如下逻辑:
-
判断needle是否存在于haystack中,如果存在,返回needle在haystack中第一次出现的位置,即使用index()函数返回的结果;
-
如果needle不存在于haystack中,返回-1。
需要注意的是,当needle不存在于haystack中时,调用index()函数会抛出ValueError异常,因此在代码中使用了if语句进行了异常处理,将其转换为返回-1的结果。
这个算法的时间复杂度是 O(nm),其中 n 是 haystack 字符串的长度,m 是 needle 字符串的长度。这是因为在最坏情况下,需要比较 haystack 字符串中的每个位置和 needle 字符串中的每个位置,才能确定 needle 是否存在于 haystack 中。
空间复杂度是 O(1),因为算法中只使用了常数级别的额外空间。
6. N 字形变换 - 力扣(Leetcode)
将一个给定字符串 s
根据给定的行数 numRows
,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "PAYPALISHIRING"
行数为 3
时,排列如下:
P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"
。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入: s = "PAYPALISHIRING", numRows = 3
输出: "PAHNAPLSIIGYIR"
示例 2:
输入: s = "PAYPALISHIRING", numRows = 4
输出: "PINALSIGYAHRPI"
解释:
P I N
A L S I G
Y A H R
P I
示例 3:
输入: s = "A", numRows = 1
输出: "A"
提示:
1 <= s.length <= 1000
s
由英文字母(小写和大写)、','
和'.'
组成1 <= numRows <= 1000
class Solution:
def convert(self, s: str, numRows: int) -> str:
if numRows<2: return s
res = ['' for _ in range(numRows)]
i = 0
flag = -1
for c in s:
res[i] += c
if i==0 or i == numRows-1:
flag = -flag
i += flag
return ''.join(res)
这段代码实现了将一个字符串按照锯齿形排列并输出的功能。锯齿形排列的行数由参数numRows
给定,每个字符被填充在对应行上,最终从上到下、从左到右依次读出每个字符得到输出结果。
该方法的主要思路是模拟整个锯齿形状的过程,用一个数组res
来保存每行的字符,初始时所有行都为空字符串。然后遍历字符串s
中的每个字符,将其加入到res
中对应的行。i
表示当前正在处理的行号,flag
表示i
的变化方向,当i
到达第一行或最后一行时,需要将flag
取反,以改变i
的增减方向。最后将res
数组中的每行拼接起来即可。
这个方法的时间复杂度为O(n)
,其中n
为字符串s
的长度,因为只需要遍历一次s
就可以得到最终结果。空间复杂度为O(numRows)
,需要一个数组来保存每行的字符。如果numRows
非常大,空间开销会很大,因此需要根据实际情况进行优化。
转载自:https://juejin.cn/post/7225009769092874297