leetcode刷题——字符串

一、反转

(一)反转字符串

数组反转就用首尾指针,字符串是一种特殊的数组结构

344. 反转字符串

  • 反转问题】字符串也是一种数组结构,不同于链表,链表交换是从开始到最后两两交换,相当于调换一下指针的方向;但是字符串的交换则是分别从头尾出发,两两交换头尾元素。
class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        #s.reverse()

        left,right=0,len(s)-1
        while left<right:   # 知道首尾指针相撞才结束循环
            s[left],s[right]=s[right],s[left]
            left+=1
            right-=1
        return s

(二)间隔反转字符串

541. 反转字符串 II
在反转字符串的基础上每隔两个字母做反转

class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        a = list(s)
        for i in range(0, len(a), 2*k):   #间隔2k,变的只有前k个
            a[i:i+k] = reversed(a[i:i+k])    #list[a:b]b越界了就取不到呗
        return "".join(a)

(三)反转字符串中的单词

151. 翻转字符串里的单词

【法一】利用python已有的函数API

  • python中翻转列表的三种方式:

     1.list_b=reversed(list_b)
     2.list_a.reverse()
     3.list_b=list_a[::-1]
    
# 法一:直接反转
class Solution:
    def reverseWords(self, s: str) -> str:
        return ' '.join([i for i in s.split(' ')[::-1] if i != ''])   # 用生成器对列表中的元素做筛选


class Solution:
    def reverseWords(self, s: str) -> str:
        return ' '.join([i for i in reversed(s.split(' ')) if i != ''])   # 用生成器对列表中的元素做筛选

【法二】自己定义函数

这里的代码有很多注意点:

  1. 多个连续的空格,只保留第一个:遍历,cur空格且上一个不是,则记录,否则continue
  2. 翻转字符串中的每个字符:先定义一个翻转函数,遍历一直到有空格,将遍历的序列进行翻转。更新start和end指针继续搜索从非空到非空的序列。
class Solution:
    # 1.去除多余的空格
    def trim_spaces(self,s):     
        n=len(s)
        left=0
        right=n-1
    
        while left<=right and s[left]==' ':       # 去除开头的空格
            left+=1
        while left<=right and s[right]==' ':        # 去除结尾的空格
            right-=1
        tmp=[]
        while left<=right:                   # 去除单词中间多余的空格
            if s[left]!=' ':
                tmp.append(s[left])
            elif tmp[-1]!=' ':     # 只保留第一个空格
                tmp.append(s[left])
            left+=1
        return tmp

    # 2.翻转字符数组
    def reverse_string(self,nums,left,right):
        while left<=right:
            nums[left], nums[right]=nums[right],nums[left]
            left+=1
            right-=1
        return None    # 返回的变量和作用的参数是同一个,所以只用None记录变化情况就可以了,当然也可以return l记录新变量,但是没有必要哦

    # 3.翻转字符串中的每个单词
    def reverse_each_word(self, nums):
        start=0
        end=0
        n=len(nums)-1
        while start<=n:
            while end<=n and nums[end]!=' ':
                end+=1
            self.reverse_string(nums,start,end-1)   
            start=end+1
            end+=1
        return None

    # 4.实例化
    def reverseWords(self, s): #测试用例:"the sky is blue"
        l = self.trim_spaces(s)                     
        self.reverse_string( l,  0, len(l) - 1)   
        self.reverse_each_word(l)               
        return ''.join(l)

(四)部分反转字符串中的单词

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

# 方法一:可以使用切片方法
class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        return s[n:] + s[0:n]

# 方法二:reverse()
class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        s = list(s)
        s[0:n] = list(reversed(s[0:n]))
        s[n:] = list(reversed(s[n:]))
        s.reverse()
        
        return "".join(s)

# 方法三:如果连reversed也不让使用,那么自己手写一个
class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        def reverse_sub(lst, left, right):
            while left < right:
                lst[left], lst[right] = lst[right], lst[left]
                left += 1
                right -= 1
        
        res = list(s)
        end = len(res) - 1
        reverse_sub(res, 0, n - 1)
        reverse_sub(res, n, end)
        reverse_sub(res, 0, end)
        return ''.join(res)

# 同方法二
# 时间复杂度:O(n)
# 空间复杂度:O(n),python的string为不可变,需要开辟同样大小的list空间来修改

二、替换

  • 代码技巧:append & + & extend

     1.append命令可以添加单个元素,也可以添加可迭代对象;而extend命令只能添加可迭代对象,也就是一个个添加。
     2.extend不占用新内存,而+会占用新内存
    
  • 替换问题】(1)replace(2)从前向后遍历,但是占用空间复杂度高(3)先填充再从后向前填充,占用的空间少。

  • 填充问题】:很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。

     这么做有两个好处:
     1.不用申请新数组。
     2.从后向前填充元素,避免了从前先后填充元素要来的 每次添加元素都要将添加元素之后的所有元素向后移动。
    

剑指 Offer 05. 替换空格

# s.replace(' ','%20)
class Solution:
    def replaceSpace(self, s: str) -> str:
        # 填充空格
        counter = s.count(' ')
        res = list(s)
        res.extend([' '] * counter * 2)   # 每碰到一个空格就多拓展两个格子,1 + 2 = 3个位置存’%20‘
        
        # 双指针从后往前替换
        left, right = len(s) - 1, len(res) - 1
        for i in range(left,-1,-1):   # 倒叙循环,左闭右开,两个-1很容易写错
            if res[i] != ' ':
                res[right] = res[i]
                right -= 1
            else:
                res[right - 2],res[right-1],res[right]= '%','2','0'   # res[right - 2: right + 1] = '%20'
                right -= 3
            left-=1
        return ''.join(res)

三、字符串匹配——KMP

  • 主要思想:当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。

  • 具体理解:

      1、概念
      (1)next数组就是一个前缀表(prefix table):前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。具体实现,next数组即可以就是前缀表,也可以是前缀表统一减一(右移一位,初始位置为-1)
      (2)前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串。
      (3)后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
     	
     2、思路:
      (1)前缀表要求的就是相同前后缀的长度。因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的前缀的后面从新匹配就可以了。
      (2)前缀表的计算
      找到的不匹配的位置, 那么此时我们要看它的前一个字符的前缀表的数值是多少,也就是前面字符串的最长相同的前缀和后缀。把下标移动到对应的索引位置继续比配。
    
     3、时间复杂度:
     O(n+m)
     
     4、操作步骤:
     (1)构造next数组:1️⃣初始化定义两个指针i和j,j指向前缀起始位置,i指向后缀起始位置。j=-1,next[0]=j。
    

28. 实现 strStr()
字符串a是否是字符串b的子串
459. 重复的子字符串

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值