LeetCode 151. 反转字符串中的单词
题目:https://leetcode.cn/problems/reverse-words-in-a-string/description/
解析:https://programmercarl.com/0151.%E7%BF%BB%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%87%8C%E7%9A%84%E5%8D%95%E8%AF%8D.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
字符串的问题用python解决起来很快,因为有很多内嵌函数可以用。
strip()
可以去除前后空格split()
既可以去除前后空格,又可以去除中间多余空格
反转:
- 字符串经过split变为list,反转list用双指针就可以完成
- 直接反转字符串,再反转每个单词字符串,反转字符串用
[::-1]
可以完成
反转list:
class Solution:
def reverseWords(self, s: str) -> str:
s = s.split()
left = 0
right = len(s) - 1
while left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
return ' '.join(s)
反转字符串:
class Solution:
def reverseWords(self, s: str) -> str:
s = s.strip()[::-1].split()
return ' '.join([c[::-1] for c in s])
卡码网 55. 右旋字符串
题目:https://kamacoder.com/problempage.php?pid=1065
链接:https://programmercarl.com/kama55.%E5%8F%B3%E6%97%8B%E5%AD%97%E7%AC%A6%E4%B8%B2.html#%E6%80%9D%E8%B7%AF
一看到这题就知道,进阶版必然是要求不额外申请空间。
但是我不会)一开始想着用快慢指针,把快指针的值覆盖给慢指针。但无论是从前往后覆盖,还是从后往前覆盖,都会导致数据丢失。所以小小的申请了一下额外空间……
import sys
input_data = sys.stdin.read().strip().splitlines()
n = int(input_data[0])
s = list(input_data[1])
n_list = s[len(s)-n::]
right = len(s) - 1
for left_char in s[len(s)-n-1::-1]:
s[right] = left_char
right -= 1
s[:n] = n_list
print(''.join(s))
中间实践的时候出错了,把for left_char in s[len(s)-n-1::-1]
写成了for left_char in s[len(s)-n-1:-1:-1]
,中间的这个-1是指倒数第一个数(我以为是截止到第一个数)。
如果不申请额外空间应该怎么做呢?用反转做。
先切片反转,再整体反转
import sys
input_data = sys.stdin.read().strip().splitlines()
n = int(input_data[0])
s = str(input_data[1])
s = s[:-n][::-1] + s[-n:][::-1]
s = s[::-1]
print(s)
先整体反转,再切片反转
import sys
input_data = sys.stdin.read().strip().splitlines()
n = int(input_data[0])
s = str(input_data[1])
s = s[::-1]
s = s[:n][::-1] + s[n:][::-1]
print(s)
LeetCode 28. 找出字符串中第一个匹配项的下标
题目:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/
链接:https://programmercarl.com/0028.%E5%AE%9E%E7%8E%B0strStr.html
用到了KMP算法【烤馍片】,建议看视频学习。这个算法是完成字符匹配问题(字符连续相同)。
暴力解法是:把目标串的每一个字符当做起点,截取一段字符串,遍历该字符串与模式串是否匹配。这样需要重复遍历目标串很多次。KMP算法的厉害之处在于,只需要遍历目标串一次。
比如:
目标串是 aabaabaaf
模式串是 aabaaf
在遍历目标串时,发现到下标5的字符(b)的时候,和模式串下标5的字符(f)开始出现区别。于是KMP非常聪明的发现,指向模式串的指针只需要 回退到下标2的字符(b)就可以了。
为什么要回退到下标2的字符?因为我们知道目标串下标5的字符(b)前面的字符有aa,模式串下标2的字符(b)前面也有aa,聪明的KMP算法记住我们已经匹配过aa了,不需要重新匹配一遍了。
为什么KMP算法可以记住aa已经匹配过一遍了?因为当我们的模式串指针指向下标5的字符(f)时发现,前5个字符(aabaa)的前后缀是一样的,那我们就没必要再花时间匹配aa了,把指针直接回退到b就可以了。aabaa前后缀相等的数量是2(aa=aa),那我们回退到下标为2的位置(b)。
这里我们设置一个与模式串等长的数组next,专门放:
模式串前 i 个字符前后缀相等的数量。
i | 前i个字符 | 前后缀相等数量 |
---|---|---|
1 | a | 0 |
2 | aa | 1 |
3 | aab | 0 |
4 | aaba | 1 |
5 | aabaa | 2 |
6 | aabaaf | 0 |
那么next数组为[0,1,0,1,2,0]
,模式串s[5]=='f', next[5-1]==2
,回退到下标2。
怎么通过代码找出next数组呢?这也是字符串匹配问题,保证前缀和后缀匹配。这里的目标串是后缀,模式串是前缀。对目标串(后缀)的处理还是那句话,闷头往前走就行,算法会记住你遍历过什么,对模式串的处理是 要找到他的next数组,有可能会回退。next可以在遍历过程中找到:
不如直接看代码:
class Solution(object):
def get_next(self, s):
j = 0
next = [0]*len(s)
for i in range(1, len(s)):
while s[i] != s[j] and j > 0:
j = next[j-1]
if s[i] == s[j]:
j += 1
next[i] = j
return next
def strStr(self, haystack, needle):
"""
:type haystack: str
:type needle: str
:rtype: int
"""
if len(haystack) < len(needle):
return -1
next = self.get_next(needle)
j = 0
for i in range(len(haystack)):
while needle[j] != haystack[i] and j > 0:
j = next[j-1]
if needle[j] == haystack[i]:
j += 1
if j == len(needle):
return i - len(needle) + 1
return -1
LeetCode 459. 重复的子字符串
题目:https://leetcode.cn/problems/repeated-substring-pattern/description/
链接:https://programmercarl.com/0459.%E9%87%8D%E5%A4%8D%E7%9A%84%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
字符串匹配,依旧KMP,找到s的next。
那next怎么用呢?
这里展示几种next:
a b a b a b
0 0 1 2 3 4
a b a b a
0 0 1 2 3
a b a b c a b
0 0 1 2 0 1 2
因为我也不知道怎么处理,直接看了代码反推:
代码里判断了len(s) % (len(s)-next[-1]) == 0
,这里的(len(s)-next[-1])
指字符串第一个不循环子串。如果len(s) % (len(s)-next[-1]) == 0
表示字符串是循环的。
class Solution(object):
def get_next(self, s):
next = [0]*len(s)
j = 0
for i in range(1, len(s)):
while s[j] != s[i] and j > 0:
j = next[j-1]
if s[j] == s[i]:
j += 1
next[i] = j
return next
def repeatedSubstringPattern(self, s):
"""
:type s: str
:rtype: bool
"""
next = self.get_next(s)
if next[-1] != 0 and len(s) % (len(s)-next[-1]) == 0:
return True
return False