LeetCode Day08 | 344. 反转字符串、541. 反转字符串 II、剑指 05. 替换空格、151. 反转字符串中的单词、剑指 58 - II. 左旋转字符串

344. 反转字符串

难度:☆1

数组,相向双指针。一个指针从前往后,另一个指针从后往前,碰头之前交换它们指向的字符。

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        left, right = 0, len(s) - 1
        while left < right:
            s[left], s[right] = s[right], s[left]
            left += 1
            right -= 1

本题一行代码解决反转字符串的 Python 内置函数是 s.reverse()

541. 反转字符串 II

难度:☆4

根据题意模拟,注意每次循环递增量是2 * k。考察了Python语言特性:字符串切片、list()字符串转化为列表、循环递增量、reversed()、join()列表转化为字符串。

策略:反转本身的Python实现有自定义函数、reversed()、切片几种。

a. 自定义反转函数

参考344. 反转字符串。先把字符串转化为列表,最后把列表转化为字符串。

class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        result = list(s)
        for i in range(0, len(s), 2 * k):
            result[i: i + k] = self.reverseSubstring(result[i: i + k])
        return ''.join(result)


    def reverseSubstring(self, s: List[str]) -> List[str]:
        left, right = 0, len(s) - 1
        while left < right:
            s[left], s[right] = s[right], s[left]
            left += 1
            right -= 1
        return s

b. reversed()

用Python内置函数。先把字符串转化为列表,最后把列表转化为字符串。

class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        result = list(s)
        for i in range(0, len(s), 2 * k):
            result[i: i + k] = reversed(result[i: i + k])
        return ''.join(result)

c. 切片相加

不用字符串-列表转化,在字符串原位操作反转、相加。注意 [::-1] 的写法和位置。

class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        p = 0
        while p < len(s):
            s = s[:p] + s[p: p + k][::-1] + s[p + k:]
            p += 2 * k
        return s

剑指 Offer 05. 替换空格

难度:☆2

a. 数组原地扩容

字符串转化为列表,列表扩容字符串长度的两倍(耗费太多空间,不采用),或扩容空格个数的两倍(双指针,从后向前倒序填充,不用申请额外数组空间)。列表的扩容用到 extend() 方法。

class Solution:
    def replaceSpace(self, s: str) -> str:
        counter = s.count(' ')
        res = list(s)
        res.extend([' '] * counter * 2)
        left, right = len(s) - 1, len(res) - 1
        while left >= 0:
            if res[left] != ' ':
                res[right] = res[left]
                right -= 1
            else:
                res[right - 2: right + 1] = '%20'
                right -= 3
            left -= 1
        return ''.join(res)

b. Python内置函数

一行代码解决,仅作参考,不可偷懒。

class Solution:
    def replaceSpace(self, s: str) -> str:
        return "%20".join(s.split(" "))
class Solution:
    def replaceSpace(self, s: str) -> str:
        return s.replace(' ', '%20')

151. 反转字符串中的单词

难度:☆5

a. 字符串操作

分布操作:1 去掉多余空格,2 翻转整个字符串,3 翻转每个单词。其中翻转字符的函数可以翻转整个字符串,也可以由翻转每个单词的函数调用。第2、3步是原地操作。

难以独立做出来,需要再反复研究。

class Solution:
    def trim_spaces(self, s: str) -> list:
        left, right = 0, len(s) - 1
        # 去掉字符串开头的空白字符
        while left <= right and s[left] == ' ':
            left += 1
        
        # 去掉字符串末尾的空白字符
        while left <= right and s[right] == ' ':
            right -= 1
        
        # 将字符串间多余的空白字符去除
        output = []
        while left <= right:
            if s[left] != ' ':
                output.append(s[left])
            elif output[-1] != ' ':
                output.append(s[left])
            left += 1
        
        return output
            
    def reverse(self, l: list, left: int, right: int) -> None:
        while left < right:
            l[left], l[right] = l[right], l[left]
            left, right = left + 1, right - 1
            
    def reverse_each_word(self, l: list) -> None:
        n = len(l)
        start = end = 0
        
        while start < n:
            # 循环至单词的末尾
            while end < n and l[end] != ' ':
                end += 1
            # 翻转单词
            self.reverse(l, start, end - 1)
            # 更新start,去找下一个单词
            start = end + 1
            end += 1
                
    def reverseWords(self, s: str) -> str:
        # 去掉多余空格
        l = self.trim_spaces(s)
        
        # 翻转字符串
        self.reverse(l, 0, len(l) - 1)
        
        # 翻转每个单词
        self.reverse_each_word(l)
        
        # 字符列表重组为字符串输出
        return ''.join(l)

b. 双端队列

维护一个word列表,将单词暂存于word列表中,appendleft到deque中完成翻转,清空word列表,再存下一个单词。不需要多个函数,代码少。

class Solution:
    def reverseWords(self, s: str) -> str:
        left, right = 0, len(s) - 1
        # 去掉字符串开头的空白字符
        while left <= right and s[left] == ' ':
            left += 1
        
        # 去掉字符串末尾的空白字符
        while left <= right and s[right] == ' ':
            right -= 1
            
        d, word = collections.deque(), []
        # 将单词 push 到队列的头部
        while left <= right:
            if s[left] == ' ' and word:
                d.appendleft(''.join(word))
                word = []
            elif s[left] != ' ':
                word.append(s[left])
            left += 1
        d.appendleft(''.join(word))
        
        return ' '.join(d)

c. Python内置函数

一行代码解决,仅作参考,不可偷懒。

class Solution:
    def reverseWords(self, s: str) -> str:
        return ' '.join(reversed(s.split()))
class Solution:
    def reverseWords(self, s: str) -> str:
        return ' '.join(s.split()[::-1])

剑指 Offer 58 - II. 左旋转字符串

难度:☆1

a. 局部反转+整体反转

左右侧分别反转,合并,再整体反转。具体步骤为:反转区间为前n的子串,反转区间为n到末尾的子串,反转整个字符串。最后就可以达到左旋n的目的。优点:完全在本串上操作,而不用定义新的字符串。

用切片反转:

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        return (s[:n][::-1] + s[n:][::-1])[::-1]

用内置函数反转:

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        s = list(s)
        s[:n] = reversed(s[:n])
        s[n:] = reversed(s[n:])      
        return ''.join(reversed(s))

用自定义的函数反转:

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:       
        lst = list(s)
        end = len(lst) - 1
        self.reverseSub(lst, 0, n-1)
        self.reverseSub(lst, n, end)
        self.reverseSub(lst, 0, end)
        return ''.join(lst)
    

    def reverseSub(self, lst, left, right):
        while left < right:
            lst[left], lst[right] = lst[right], lst[left]
            left += 1
            right -= 1

b. 整体反转+局部反转

具体步骤为:反转整个字符串,反转区间为前 len(s)-n 的子串,反转区间为 len(s)-n 到末尾的子串。

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        return s[::-1][:len(s)-n][::-1] + s[::-1][len(s)-n:][::-1]

c. 切片+交换位置

Python切片,再交换位置合并。

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        return s[n:] + s[:n]

d. 扩展字符串+切片

字符串扩展一遍,再切 [n:n+length] 的部分即可。

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        length = len(s)
        s += s
        return s[n:n+length]

e. 双端队列

把字符串放进一个双端队列deque,左侧的弹出来压入右侧。缺点:要另外开辟空间存放s的字符。

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        d = deque()
        for i in s:
            d.append(i)
        for _ in range(n):
            left = d.popleft()
            d.append(left)
        return ''.join(d)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值