leetcode分类刷题:字符串及单词翻转

1、本文此次总结的题型“leetcode分类刷题:字符串及单词翻转”较为简单,是双指针法在字符串及单词翻转类题型中的应用
2、如果单词翻转类题型加了O(1)空间复杂度的要求,算法思路会变得稍微复杂一点

344. 反转字符串

该题为字符串翻转的基础题型,为后续题目提供了算法模板

from typing import List
'''
344. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
示例 1:
    输入: s = ["h","e","l","l","o"]
    输出: ["o","l","l","e","h"]
题眼:字符串数组原地反转
思路:双指针分别指向数组两端进行两两交换。
'''


class Solution:
    def reverseString(self, s: List[str]) -> None:
        left, right = 0, len(s) - 1
        while left < right:  # 不同的两个字符串交换,所以不用取等号
            s[left], s[right] = s[right], s[left]
            left += 1
            right -= 1


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            s = [n[1: -1] for n in input().strip().split('=')[1].strip()[1: -1].split(',')]
            print(s)
            obj.reverseString(s)
            print(s)
        except EOFError:
            break

541. 反转字符串 II

“344. 反转字符串”的扩展; 每隔 2k 个字符的前 k 个字符进行反转

from typing import List
'''
541. 反转字符串 II
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例 1:
    输入: s = "abcdefg", k = 2
    输出: "bacdfeg"
题眼:字符串反转
思路:“344. 反转字符串”的扩展; 每隔 2k 个字符的前 k 个字符进行反转
'''


class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        # 注意不是按照字符数组的形式给定了,需要一开始就转换为字符数组
        sList = list(s)
        for i in range(0, len(sList), 2 * k):
            # “344. 反转字符串”的模板代码
            left = i
            right = left + k - 1  # 注意这里需要-1
            if right >= len(sList):  # 剩余字符少于 k 个,则将剩余字符全部反转
                right = len(sList) - 1
            while left < right:
                sList[left], sList[right] = sList[right], sList[left]
                left += 1
                right -= 1
        return ''.join(sList)


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            s = in_line[1].strip().split(',')[0][1: -1]
            k = int(in_line[2].strip())
            print(s, k)
            print(obj.reverseStr(s, k))
        except EOFError:
            break

345. 反转字符串中的元音字母

“344. 反转字符串”的扩展; 额外增加了对元音字母的检索

from typing import List
'''
345. 反转字符串中的元音字母
给你一个字符串 s ,仅反转字符串中的所有元音字母,并返回结果字符串。
元音字母包括 'a'、'e'、'i'、'o'、'u',且可能以大小写两种形式出现。
示例 1:
    输入:s = "hello"
    输出:"holle"
题眼:字符串反转
思路:
'''


class Solution:
    def reverseVowels(self, s: str) -> str:
        # 字符串转换为字符串数组
        sList = list(s)
        hashTable = {'a', 'A', 'e', 'E', 'i', 'I', 'o', 'O', 'u', 'U'}
        left, right = 0, len(sList) - 1
        while left < right:
            while left < right and sList[left] not in hashTable:  # 注意添加 left < right
                left += 1
            while left < right and sList[right] not in hashTable:  # 注意添加 left < right
                right -= 1
            if left < right:  # 注意添加 left < right
                sList[left], sList[right] = sList[right], sList[left]
                left += 1
                right -= 1
        return ''.join(sList)


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            s = input().strip().split('=')[1].strip()[1: -1]
            print(obj.reverseVowels(s))
        except EOFError:
            break

151. 反转字符串中的单词

1、字符串中的单词翻转题目里最难的一道题,搞清楚这道题目O(1)空间复杂度的算法思路,后续几道题都会比较简单
2、第一步,按照“27.移除元素”移除所有空格稍加改动,并给单词之间添加一个空格;第二步,将所有元素翻转;第三步,将每个单词翻转
3、注意 添加单词到新的字符串数组删除字符串中的多余空格将每个单词翻转 都可以套用同一个模板,即 按照“27.移除元素”移除所有空格稍加改动 的模板

from typing import List
'''
151. 反转字符串中的单词
给一个字符串s,请反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 2:
    输入:s = "  hello world  "
    输出:"world hello"
    解释:反转后的字符串中不能存在前导空格和尾随空格。
题眼:单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串
思路1、第一步,将单词取出来,并存放到一个待定List[str]中 —— 用双指针之左右指针的思路;第二步,将List[str]反转
思路2、O(1)空间复杂度;第一步,按照“27.移除元素”移除所有空格稍加改动,并给单词之间添加一个空格;第二步,将所有元素翻转;第三步,将每个单词翻转
'''


class Solution:
    def reverseWords(self, s: str) -> str:
        # # 思路1、两步操作
        # # 第一步,将输入转换为字符串数组
        # # 新的思路写法:双指针之快慢指针,快指针遍历字符串:检测单词左边界+标记单词右边界,慢指针标记单词左边界
        # sList = []
        # slow, fast = 0, 0
        # while fast < len(s):
        #     if s[fast] != ' ':  # 检测到单词开头,将整个单词检索下来
        #         slow = fast  # 慢指针标记单词左边界
        #         while fast < len(s) and s[fast] != ' ':  # 快指针标记单词右边界+1的位置
        #             fast += 1
        #         sList.append(s[slow: fast])  # 此时,一定可以添加到一个单词
        #     else:
        #         fast += 1
        # # 之前的思路写法
        # # wordLeft, wordRight = 0, 0
        # # while wordRight < len(s):
        # #     while wordRight < len(s) and s[wordRight] == ' ':  # wordRight指示到遍历到的单词的首字母位置
        # #         wordRight += 1
        # #     wordLeft = wordRight  # wordLeft&wordRight同时指示到遍历到的单词的首字母位置
        # #     while wordRight < len(s) and s[wordRight] != ' ':  # wordRight指示到单词的尾字母的下一位置
        # #         wordRight += 1
        # #     if wordLeft < wordRight:  # 确保单词是有效的,wordLeft==wordRight是个空字符
        # #         sList.append(s[wordLeft: wordRight])
        # # 第二步,将字符串数组反转
        # left, right = 0, len(sList) - 1
        # while left < right:
        #     sList[left], sList[right] = sList[right], sList[left]
        #     left += 1
        #     right -= 1
        # return ' '.join(sList)

        # # 思路2、O(1)空间复杂度:C++可以直接实现;Python实际上还是O(N)的,不过可以模拟一下
        # 第一步,按照“27.移除元素”移除所有空格稍加改动,并给单词之间添加一个空格
        # 最终slow标记到了新字符串的末尾+1的位置,表示新字符串的长度
        sList = list(s)
        slow, fast = 0, 0
        while fast < len(sList):
            if sList[fast] != ' ':  # 检测到单词开头
                if slow != 0:  # 此时意味着开始检测到第二个及后续的单词了,对整个单词前移前先添加一个空格
                    sList[slow] = ' '
                    slow += 1
                while fast < len(sList) and sList[fast] != ' ':  # 将整个单词进行前移
                    sList[slow] = sList[fast]
                    slow += 1
                    fast += 1
            else:
                fast += 1
        newStrLen = slow
        # 第二步,将所有元素翻转
        # 定义翻转函数
        def reverseFunc(s: List[str], left: int, right: int):
            while left < right:
                s[left], s[right] = s[right], s[left]
                left += 1
                right -= 1
        reverseFunc(sList, 0, newStrLen - 1)
        # 第三步,将每个单词翻转:发现检测单词的思路 可以继续沿用上面 添加单词、删除空格 的模板
        slow, fast = 0, 0
        while fast < newStrLen:
            if sList[fast] != ' ':  # 检测到单词开头,将整个单词检索下来
                slow = fast
                while fast < newStrLen and sList[fast] != ' ':  # 快指针标记单词右边界+1的位置
                    fast += 1
                reverseFunc(sList, slow, fast - 1)  # 此时,一定可以检测到一个单词,调用翻转函数
            else:
                fast += 1
        return ''.join(sList[0: newStrLen])


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            s = in_line[1].strip()[1: -1]
            print(s)
            print(obj.reverseWords(s))
        except EOFError:
            break

186. 反转字符串中的单词II

“151. 反转字符串中的单词”的简化版:第一步,将所有元素翻转;第二步,将每个单词翻转

from typing import List
'''
186. 反转字符串中的单词II
给你一个字符数组 s ,反转其中 单词 的顺序。
单词 的定义为:单词是一个由非空格字符组成的序列。s 中的单词将会由单个空格分隔。
必须设计并实现 原地 解法来解决此问题,即不分配额外的空间。
注意:输入字符串中不会包含前置或尾随的空格,单词与单词之间永远是以单个空格隔开的。
示例 1:
    输入:s = [“t”,“h”,“e”," “,“s”,“k”,“y”,” “,“i”,“s”,” “,“b”,“l”,“u”,“e”]
    输出:[“b”,“l”,“u”,“e”,” “,“i”,“s”,” “,“s”,“k”,“y”,” ",“t”,“h”,“e”]
示例 2:
    输入:s = [“a”]
    输出:[“a”]
题眼:O(1)空间复杂度
思路、第一步,将所有元素翻转;第二步,将每个单词翻转
'''


class Solution:
    def reverseWords(self, s: List[str]):
        # 定义翻转函数
        def reverseFunc(s: List[str], left: int, right: int):
            while left < right:
                s[left], s[right] = s[right], s[left]
                left += 1
                right -= 1
        # 第一步,将所有元素翻转
        reverseFunc(s, 0, len(s) - 1)
        # 第二步,将每个单词翻转
        slow, fast = 0, 0
        while fast < len(s):
            if s[fast] != ' ':  # 检测到单词开头
                slow = fast  # 标记单词左边界
                while fast < len(s) and s[fast] != ' ':  # 标记单词右边界+1的位置
                    fast += 1
                reverseFunc(s, slow, fast - 1)  # 一定可以检测到完整的一个单词,完成翻转操作
            else:
                fast += 1


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            s = [c[1: -1] for c in in_line[1].strip()[1: -1].split(',')]
            print(s)
            obj.reverseWords(s)
            print(s)
        except EOFError:
            break

557. 反转字符串中的单词 III

“186. 反转字符串中的单词II”的简化版:直接将每个单词翻转

from typing import List
'''
557. 反转字符串中的单词 III
给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。
提示:s 不包含任何开头或结尾空格。s 里 至少 有一个词。s 中的所有单词都用一个空格隔开。
示例 2:
    输入:s = "Let's take LeetCode contest"
    输出:"s'teL ekat edoCteeL tsetnoc"
题眼:
思路、直接将每个单词翻转
'''


class Solution:
    def reverseWords(self, s: str) -> str:
        # 字符串转换为字符串数组
        sList = list(s)
        # 定义翻转函数
        def reverseFunc(s: List[str], left: int, right: int):
            while left < right:
                s[left], s[right] = s[right], s[left]
                left += 1
                right -= 1
        # 将每个单词翻转
        slow, fast = 0, 0
        while fast < len(sList):
            if sList[fast] != ' ':  # 检测到单词开头
                slow = fast  # 标记单词左边界
                while fast < len(sList) and sList[fast] != ' ':  # 标记单词右边界+1的位置
                    fast += 1
                reverseFunc(sList, slow, fast - 1)  # 一定可以检测到完整的一个单词,完成翻转操作
            else:
                fast += 1
        return ''.join(sList)


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            s = in_line[1].strip()[1: -1]
            print(obj.reverseWords(s))
        except EOFError:
            break

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

O(1)空间复杂度的解法(Python只能模拟一下):将字符串一分为二地看待,看成是两个单词(一个长度为k,一个长度为len(s)-k)
最终的效果就相当于是把两个单词翻转;类似于“186. 反转字符串中的单词II”的思路

from typing import List
'''
剑指 Offer 58 - II. 左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,
该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
    输入: s = "abcdefg", k = 2
    输出: "cdefgab"
题眼:旋转
思路:O(1)空间复杂度的解法(Python只能模拟一下):将字符串一分为二地看待,看成是两个单词(一个长度为k,一个长度为len(s)-k),
最终的效果就相当于是把两个单词翻转;类似于“186. 反转字符串中的单词II”的思路
'''


class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        # 字符串转换为字符串数组
        sList = list(s)
        # 定义翻转函数
        def reverseFunc(s: List[str], left: int, right: int):
            while left < right:
                s[left], s[right] = s[right], s[left]
                left += 1
                right -= 1
        # 第一步,将所有元素翻转
        reverseFunc(sList, 0, len(sList) - 1)
        # 第二步,将两个单词分别翻转,第一个单词左右边界[0, len(s)-n-1],第二个单词左右边界[len(s)-n, len(s)-1]
        reverseFunc(sList, 0, len(s) - n - 1)
        reverseFunc(sList, len(s) - n, len(s) - 1)
        return ''.join(sList)


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            s = in_line[1].strip().split(',')[0].strip()[1: -1]
            k = int(in_line[2])
            print(obj.reverseLeftWords(s, k))
        except EOFError:
            break

你可能感兴趣的:(leetcode分类刷题,leetcode,算法)