Day08 算法| 字符串01

题目 344. Reverse String

题目链接

题目描述:

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

示例 1:
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]

示例 2:
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]

解题思路:

举个列子,这道题就用双指针两两交换做,就比如 [1,2,3,4,5]-->[5,2,3,4,1]-->[5,4,3,2,1],就得到了一个倒序数组。

代码:

注意while的限制,当list为奇数时,刚好两两交换,反之最中间那个数不做处理。

class Solution:
    def reverseString(self, s: List[str]) -> None:
        #利用双指针从外向内交换
        i=0
        j=len(s)-1
        while i< len(s)//2:
            s[i],s[j]=s[j],s[i]
            i+=1
            j-=1
        

        

复杂度:

  1. 时间复杂度:这个函数的时间复杂度是 O(n),其中 n 是字符数组 s 的长度。这是因为我们只遍历了一次字符数组,而遍历的次数是与数组的长度线性相关的。

  2. 空间复杂度:这个函数的空间复杂度是 O(1),这表示我们在函数执行过程中使用的额外空间是常数。这是因为我们只使用了两个变量 left 和 right 来进行计算,而不管输入的数组有多大,这两个变量的空间需求都是固定的。

题目 541. 反转字符串II

题目链接

题目描述:

给定一个字符串 s 和一个整数 k,从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。

如果剩余字符少于 k 个,则将剩余字符全部反转。

如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例:

输入: s = "abcdefg", k = 2
输出: "bacdfeg"

解题思路:

  1. 将输入字符串 s 转换为一个字符列表 res,这样我们可以对其中的字符进行修改。

  2. 定义了一个嵌套函数 reverse(s),该函数接受一个字符列表 s 作为参数。这个函数使用双指针法,从字符列表的两端同时向中间移动,交换字符的位置,从而实现字符反转的操作。

  3. 使用一个 for 循环,从字符串开头开始,以步长为 2 * k 迭代字符串。循环变量 cur 表示每个子串的起始索引。

  4. 在循环中,根据剩余字符数的情况,对当前子串进行反转操作:

    • 如果剩余字符数少于 k,即剩余字符数不足一个长度为 k 的子串,我们直接对剩余字符进行反转操作。
    • 如果剩余字符数大于等于 k,但小于 2k,即剩余字符数大于等于一个长度为 k 的子串,但不足一个长度为 2k 的子串,我们只对前 k 个字符进行反转操作,其余字符保持原样。
  5. 最后,将修改后的字符列表 res 使用 join() 方法转换为字符串,并返回结果

代码:

class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        #define a reverse function
        def reverse_word(words):
            left, right = 0, len(words)-1
            while left < right:
                words[left], words[right] = words[right], words[left]
                left += 1
                right -= 1
            return words
        
        res = list(s)

        for cur in range(0, len(s), 2 * k):
            if cur + k <= len(s):
                res[cur: cur + k] = reverse_word(res[cur: cur + k])
            else:
                res[cur:] = reverse_word(res[cur:])
        
        return ''.join(res)
        





复杂度:

时间复杂度为 O(n),空间复杂度为 O(n),其中 n 是输入字符串的长度。这是因为代码需要遍历整个字符串,对字符列表进行修改,以及将字符列表转换为字符串。

题目  剑指Offer 05.替换空格

题目描述:

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

示例 1: 输入:s = "We are happy."
输出:"We%20are%20happy."

题目链接

解题思路:

  1. 首先,通过 s.count(' ') 统计字符串 s 中空格的个数,以确定扩展后的字符串长度。
  2. 创建一个新的列表 res,将字符串 s 转换为列表形式。同时,根据空格的个数,扩展列表长度,每个空格需要额外扩展两个单位来存储 "%20"。
  3. 设置两个指针 leftright,分别指向原始字符串末尾和扩展后字符串的末尾。
  4. 从原始字符串的末尾开始遍历,如果当前字符不是空格,则将其复制到扩展后字符串的对应位置,并更新 right 指针的位置。
  5. 如果当前字符是空格,则将 %20 替换到扩展后字符串的对应位置,并更新 right 指针的位置。
  6. 继续向前移动 left 指针,直到遍历完整个原始字符串。
  7. 最后,将列表 res 转换为字符串,并将结果返回

代码:

class Solution:
    def replaceSpace(self, s: str) -> str:
        num_tab = s.count(' ')

        res = list(s)
        # 一个空格就扩展两个单位储存“20%”
        res.extend([' ']*num_tab*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)

复杂度:

时间复杂度:

  • 字符串转换为列表的操作需要 O(n) 的时间,其中 n 是字符串的长度。
  • 统计空格数量需要遍历一次字符串,需要 O(n) 的时间。
  • 扩展列表长度的操作需要 O(k) 的时间,其中 k 是空格的数量。
  • 在遍历原始字符串时,需要进行 n 次循环。
  • 在每次循环中,根据字符是否为空格,进行相应的复制或替换操作,这些操作都是 O(1) 的时间。
  • 最后将列表转换为字符串的操作需要 O(n) 的时间。 综上,总的时间复杂度为 O(n + k)。

空间复杂度:

  • 创建了一个列表 res 来存储转换后的字符串,需要额外的 O(n + 2k) 的空间,其中 n 是字符串的长度,2k 是空格的数量。
  • 创建了一个变量 num_tab 来存储空格的数量,需要额外的 O(1) 的空间。
  • 最后将列表转换为字符串时,不需要额外的空间。 综上,总的空间复杂度为 O(n + 2k)。

题目 剑指Offer58-II.左旋转字符串

题目链接

题目描述:

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

示例 1:
输入: s = "abcdefg", k = 2
输出: "cdefgab"

示例 2:
输入: s = "lrloseumgh", k = 6
输出: "umghlrlose"

限制:
1 <= k < s.length <= 10000

解题思路:

  1. 创建一个新的列表 s_,将字符串 s 转换为列表形式,这样可以方便地进行字符的移动操作。
  2. 创建一个与 s 长度相同的列表 res,用于存储移动后的字符串。
  3. 使用循环遍历 s 中的每个字符,根据移动规则进行字符的移动操作。
  4. 如果当前索引 i 小于 len(s) - k,说明字符应该被移动到新字符串的后面,所以将 s_[i+k] 赋值给 res[i]
  5. 如果当前索引 i 大于等于 len(s) - k,说明字符应该被移动到新字符串的前面,所以将 s_[i - len(s) + k] 赋值给 res[i]
  6. 最后,使用 ''.join(res) 将列表 res 转换为字符串,并将结果返回。

代码:

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        s_=list(s)
        res=[1]*len(s)
        for i in range(len(s)):
            if i < len(s)-k:
                res[i] = s[i+k]
            else:
                res[i] = s[i - len(s) + k]
        #res[len(s)-k:len(s)] = res[len(s)-k:len(s)][::-1]
        return ''.join(res)


s = "abcdefg"
k = 2
solution = Solution()
result = solution.reverseLeftWords(s, k)
print(result)  # 输出 "cdefgab"

            

复杂度:

时间复杂度:

  • 字符串转换为列表的操作需要 O(n) 的时间,其中 n 是字符串的长度。
  • 循环遍历字符串的每个字符,共需要执行 n 次循环。
  • 在每次循环中,字符的移动操作需要 O(1) 的时间。
  • 最后将列表转换为字符串的操作需要 O(n) 的时间。 综上,总的时间复杂度为 O(n)。

空间复杂度:

  • 创建了一个列表 s_ 来存储转换后的字符串,需要额外的 O(n) 的空间。
  • 创建了一个列表 res 来存储移动后的字符串,需要额外的 O(n) 的空间。
  • 最后将列表转换为字符串时,不需要额外的空间。 综上,总的空间复杂度为 O(n)。

题目 151.翻转字符串里的单词 

题目链接

题目描述:

给定一个字符串,逐个翻转字符串中的每个单词。

示例 1:
输入: "the sky is blue"
输出: "blue is sky the"

示例 2:
输入: "  hello world!  "
输出: "world! hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。

示例 3:
输入: "a good   example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

#

解题思路:

先整体反转,再反转单词内部

  1. 定义了 reverseWords 方法,接受一个字符串 s 作为输入,并返回反转后的结果。

  2. 使用切片操作 reversed_s = s[::-1] 将整个字符串反转,将反转后的字符串赋值给 reversed_s

  3. 使用 split() 方法将 reversed_s 按空格分割为一个单词列表 reversed_words。这里我们不需要使用循环和索引来逐个反转每个单词,而是利用列表推导式和切片操作一次性完成。

  4. 使用 ' '.join(reversed_words) 构建新的字符串 new_s,将每个单词用空格连接起来。

  5. 返回最终的反转结果 new_s

代码:

class Solution:
    def reverseWords(self, s: str) -> str:
        # 整个字符串反转
        reversed_s = s[::-1]
        
        # 内部单词反转
        reversed_words = [word[::-1] for word in reversed_s.split()]
        
        # 构建新字符串
        new_s = ' '.join(reversed_words)
        
        return new_s

复杂度:

时间复杂度为 O(n + m * k),其中 n 是字符串的长度,m 是单词的数量,k 是单词的平均长度。

空间复杂度为 O(n + m * k),其中 n 是字符串的长度,m 是单词的数量,k 是单词的平均长度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值