代码随想录训练营 Day8打卡 字符串part01 344.反转字符串 541. 反转字符串II 卡码网:54.替换数字

代码随想录训练营 Day8打卡 字符串part01

一、 力扣344. 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
示例 1:
输入:s = [“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
示例 2:
输入:s = [“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]

对于字符串,我们定义两个指针(也可以说是索引下标),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。

以字符串hello为例,过程如下:
在这里插入图片描述

版本一:双指针法
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

版本二:使用栈
class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        利用栈后进先出的特性来反转字符串。
        先将所有字符压入栈中,然后依次弹出栈顶元素重新赋值给原列表。
        """
        stack = []
        for char in s:
            stack.append(char)
        for i in range(len(s)):
            s[i] = stack.pop()

版本三:使用 range 函数
class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        使用 range 函数进行循环,只遍历列表的一半长度,然后进行首尾元素的互换。
        这样可以减少不必要的操作,提高效率。
        """
        n = len(s)
        for i in range(n // 2):
            s[i], s[n - i - 1] = s[n - i - 1], s[i]

版本四:使用 reversed 函数
class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        利用 Python 的内置函数 reversed() 来获取反向迭代器,然后用切片操作完成原地修改。
        """
        s[:] = reversed(s)

版本五:使用切片
class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        使用 Python 的切片功能,简洁明了地反转整个列表。
        通过 s[::-1] 获取列表的反向副本并赋值。
        """
        s[:] = s[::-1]

版本六:使用列表推导
class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        使用列表推导式和 range 函数,从列表末尾开始向前遍历,并创建一个新的列表赋值给原列表。
        """
        s[:] = [s[i] for i in range(len(s) - 1, -1, -1)]

版本七:使用 reverse() 方法
class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        直接使用列表的 reverse() 方法进行原地反转。
        这是最直接也是最简单的方法,直接调用列表自带的函数完成操作。
        """
        s.reverse()

力扣题目链接
题目文章讲解
题目视频讲解

二、 力扣541. 反转字符串II

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例 1:
输入:s = “abcdefg”, k = 2
输出:“bacdfeg”
示例 2:
输入:s = “abcd”, k = 2
输出:“bacd”

这道题目本质上是关于模拟题目中所设定的特定反转逻辑。一些解题者可能会采用复杂的方法,比如编写冗长的逻辑代码或引入额外的计数器来追踪每2k个字符,并进一步识别出需要反转的前k个字符。

然而,一个更为高效的解决方案是,在遍历字符串时,直接让指针i跳跃2 * k个位置。这意味着每次迭代,i都将前进2 * k的距离,从而直接定位到下一个反转区间的起始点。随后,只需简单判断当前区间是否满足反转条件即可。

采用这种方式,代码不仅更加精炼,同时也显著提升了执行效率,因为无需在每个字符上逐一判断或维护额外的计数状态。通过恰当的循环控制,可以简化问题处理流程,实现对字符串的高效局部反转。

版本一:使用辅助函数来反转子字符串
class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        """
        反转字符串中每隔2k个字符的前k个字符。
        1. 使用range(start, end, step)来确定需要调换的起始位置。
        2. 利用 Python 切片操作,可以简单处理字符串的部分反转。
        3. 切片s[start:end]如果end超过字符串长度,Python会自动处理,不会出错。
        """

        # 辅助函数,用于反转列表的一部分
        def reverse_substring(text):
            left, right = 0, len(text) - 1
            while left < right:
                text[left], text[right] = text[right], text[left]
                left += 1
                right -= 1
            return text

        # 将字符串转换为列表,以便可以修改
        res = list(s)

        # 每隔2k个字符处理一次
        for cur in range(0, len(s), 2 * k):
            # 反转当前段的前k个字符
            res[cur: cur + k] = reverse_substring(res[cur: cur + k])
        
        # 将列表转换回字符串并返回
        return ''.join(res)

版本二:使用切片操作直接反转
class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        """
        反转字符串中每隔2k个字符的前k个字符。
        1. 遍历字符串,步长为2k,保证每次跳过2k字符,处理前k字符的反转。
        2. 使用Python的切片功能 [::-1] 直接反转子字符串。
        3. 利用切片的容错性,自动处理边界条件,简化代码。
        """
        # 初始化指针
        p = 0
        # 转换为列表以便修改
        s = list(s)

        # 遍历字符串
        while p < len(s):
            # 找到当前片段的结束位置,确保不超过字符串长度
            p2 = min(p + k, len(s))
            # 直接使用切片操作反转前k个字符
            s[p:p2] = s[p:p2][::-1]
            # 移动指针到下一个2k区间
            p += 2 * k

        # 将列表转换回字符串并返回
        return ''.join(s)

以上两种方法都采用了切片和局部修改的方式来处理字符串,第一种方法通过辅助函数手动反转,而第二种方法直接利用 Python 的切片反转功能,两者都有效地利用了 Python 的特性来简化代码和增加执行效率。

力扣题目链接
题目文章讲解
题目视频讲解

三、 卡码网. 54.替换数字

给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。 例如,对于输入字符串 “a1b2c3”,函数应该将其转换为 “anumberbnumbercnumber”。
输入描述:
输入一个字符串 s,s 仅包含小写字母和数字字符。
输出描述:
打印一个新的字符串,其中每个数字字符都被替换为了number
输入示例:
a1b2c3
输出示例:
anumberbnumbercnumber
提示信息:
数据范围:1 <= s.length < 10000。

代码实现:

这段代码目的是将输入字符串中的所有数字字符替换为 “number”。这通过转换字符串为列表,修改列表元素,然后重新组合成字符串来实现。这种方法直接在列表上操作,避免了字符串不可变的限制,但需要额外的空间来存储列表。

class Solution:
    def change(self, s):
        # 将字符串 s 转换成列表 lst,因为 Python 中的字符串是不可变的,转换成列表后可以修改。
        lst = list(s)  # Python 的字符串是不可改变的,因此需要转换成列表来进行修改。空间复杂度为 O(n)。
        
        # 遍历列表中的每个元素,索引为 i
        for i in range(len(lst)):
            # 检查当前元素是否是数字
            if lst[i].isdigit():
                # 如果是数字,将该位置的元素替换为 "number"
                lst[i] = "number"
        
        # 使用 ''.join(lst) 将列表转换回字符串,并返回这个修改后的字符串
        return ''.join(lst)

卡码网题目链接
题目文章讲解

四、拓展

在Python中,字符串和数组的概念和行为有明显的区别,尽管在某些方面它们表现出一定的相似性。这里,我们可以探讨一下Python字符串的特点和行为,以及它与数组(通常通过列表或元组表示)的对比。

字符串的特性

不可变性(Immutability):

  • 在Python中,字符串是不可变的。这意味着一旦一个字符串被创建,它的内容不能被改变。任何看似修改字符串的操作实际上是创建了一个新的字符串。
  • 例如,当你执行如 str = str.replace(‘a’, ‘b’)
    的操作时,你并没有改变原始字符串,而是创建了一个修改后的新字符串赋值给了 str 变量。

索引和切片:

  • 字符串支持索引和切片操作,这使得访问字符串的一部分非常方便。
  • 例如,str[1:5] 会返回从索引 1 开始到索引 5(不包含)的子字符串。

内置方法:

  • Python为字符串提供了丰富的内置方法,这些方法使得执行常见的字符串操作(如分割、合并、查找、转换大小写等)变得非常简单。
  • 例如,str.upper()、str.lower()、str.split()、str.find() 等。

遍历:

  • 字符串可以被迭代,这意味着你可以在for循环中直接遍历字符串中的每个字符。
  • 例如:
for char in "hello":
    print(char)

字符串与数组的比较

相似点:

  • 两者都支持索引和切片操作。
  • 两者都可以通过循环进行遍历。

差异点:

  • 可变性:与字符串不同,列表(数组的一种形式)是可变的。你可以修改列表中的元素,添加新元素,或者删除元素。
  • 存储类型:字符串只用于存储字符序列。而列表可以存储任何类型的对象,包括数字、字符串、其他列表或任何可哈希的对象。
  • 方法和操作:虽然字符串和列表都有许多专用的方法,但列表的方法更侧重于添加、删除元素和其他列表操作,如 append(), pop(),
    extend() 等。
  • 性能:由于字符串的不可变性,频繁的字符串操作(尤其是连接操作)可能会导致效率低下,因为每次操作都可能生成一个新的字符串。在这种情况下,使用如列表的可变类型可能会更有效,特别是当涉及到大量的数据修改时。

什么是可哈希对象

可哈希(Hashable)的对象是指那些可以被用作字典的键或集合(如set或frozenset)中的元素的对象。在Python中,一个对象被称为可哈希的,必须满足以下两个条件

  • 不可变性(Immutability):对象的状态在其生命周期中不能改变。这是因为哈希值是基于对象的内容计算出来的,如果对象的内容改变了,而它的哈希值却没有更新,这将导致错误的关联和检索。例如,字符串、整数、浮点数、元组(如果元组内的元素也是不可变的)都是不可变的,因此它们是可哈希的。

  • 一致性(Consistency):相同对象的哈希值必须始终相同。这意味着只要对象的内部状态不变,无论何时调用其__hash__()方法,返回的哈希值都应该是相同的。

哈希在Python中是如何工作的呢?当你将一个对象用作字典的键时,Python会调用该对象的 hash() 方法来计算其哈希值。这个哈希值是一个整数,用于在内部数据结构中快速定位对象。如果两个对象相等(通过__eq__()方法比较),那么它们的哈希值也应该相同,这是哈希一致性的要求。

举例来说,字符串是可哈希的,因为它们是不可变的,且具有稳定的哈希值。这意味着你可以将字符串用作字典的键:

my_dict = {'apple': 1, 'banana': 2}

但是,列表和字典本身是不可哈希的,因为它们是可变的。你不能将它们直接用作字典的键或集合的元素,这样做会抛出TypeError。例如:

# 下面的代码会抛出 TypeError
my_set = {[1, 2, 3]}  # TypeError: unhashable type: 'list'
my_dict = {[1, 2, 3]: 'some value'}  # TypeError: unhashable type: 'list'

为了避免这个问题,你可以使用不可变的容器,如元组或frozenset,来包装可变的元素,从而创建可哈希的对象:

my_set = {(1, 2, 3)}  # 元组是可哈希的
my_dict = {frozenset([1, 2, 3]): 'some value'}  # frozenset是可哈希的

总结来说,可哈希的对象是那些不可变且在哈希过程中表现出一致性的对象,它们可以作为字典的键或集合的成员,用于高效的数据检索和存储。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值