代码随想录算法训练营第八天| 344.反转字符串、541. 反转字符串II、替换数字

今日题目

344.反转字符串

题目链接:344. 反转字符串 - 力扣(LeetCode)

思考:将字符串反过来,就是以数组中间位置为轴,水平旋转180度。最简单办法就是新建一个数组,倒序遍历原数组并逐个位置赋值给新数组。

题目要求不要给另外的数组分配额外的空间,必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。因此不能开辟一个新数组。

这道题关键是以数组中间位置为轴,首先需要找到需要互换位置的元素下标关系,仔细思考不难发现,互换位置的下标关系为(index, -index-1)或者(index, len(s)-index-1),len(s)为数组长度。发现这个互换位置下标关系,其实就解决了一半。剩下的一半,就是何时停止互换。

我刚开始写的时候没考虑停止,就觉得这样遍历完整个数组就行了。然而,当index达到数组中间位置后,后面的遍历互换会导致已经被换好的元素被换回去,和原始数组一样。因此,数组中间位置就是停止互换的条件,即len(s)//2。那么应该是index<len(s)//2,还是index<=len(s)//2呢?可以举例思考:

假设数组只有偶数个元素,比如4个,["h","e","l","l"],index只需走过"h","e"就可以了,"e"下标为1,len(s)//2=2,因此需要index<len(s)//2,无需=的情况。

代码:

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        for index, string in enumerate(s):
            if index < len(s) // 2:
                tmp = s[-index-1]
                s[-index-1] = string
                s[index] = tmp
            else:
                return s
        return s

541. 反转字符串II

题目链接:541. 反转字符串 II - 力扣(LeetCode)

思考:本题与上面一题类似,区别在于:1、输入不是列表,而是一整个字符串;2、分段反转字符串。

首先想到的就是先把输入字符串转成类似上面一题的列表形式,然后就是定位区间,每个区间上的思路与上题方法一致。为了完整显示定位区间的思想,我的代码比较冗余,每一段都做了细致的判断和处理。(见解法一)

仔细观察解法一,会发现很多代码存在重复,其实可以封装起来,而且定位区间的判断较多,显得代码更为复杂。

总结一下区间的移动,其实就是每一个长度为2k的区间中,处理前k个字符串,进行反转。(每次反转都是对这一段字符串全部反转,其实不够k个与k个的反转是一样的)。

因此,考虑把反转的功能封装为一个函数,在长度为k的区间上处理字符串。程序整体按照2k为步长去遍历数组。(见解法二)

其实两种解法一个意思,只不过第一种分的太细了,第二种进行了封装简化。(鲜明的对比,高端的程序员往往只用最少的代码)

代码:

# 解法一
class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        l_s = list(s)
        
        n = len(l_s)
        if n < k:
            for i in range(n // 2):
                l_s[i], l_s[-1-i] = l_s[-1-i], l_s[i]
            return ''.join(l_s)

        elif n >= k and n < 2*k:          
            for i in range(k // 2):
                l_s[i], l_s[k-1-i] = l_s[k-1-i], l_s[i]
            return ''.join(l_s)

        else:
            pre_n, pos_n = divmod(n, 2*k)
            for i in range(pre_n):
                start = 2*k*i
                end = 2*k*(i+1)
                cur = l_s[start:end]
                for i in range(k // 2):
                    cur[i], cur[k-1-i] = cur[k-1-i], cur[i]
                l_s[start:end] = cur

            
            last = l_s[-pos_n:]
            if pos_n == 0:
                return ''.join(l_s)

            elif pos_n < k:
                for i in range(pos_n // 2):
                    last[i], last[-1-i] = last[-1-i], last[i]
                l_s[-pos_n:] = last
                return ''.join(l_s)

            else:
                for i in range(k // 2):
                    last[i], last[k-1-i] = last[k-1-i], last[i]
                l_s[end:] = last
                return ''.join(l_s)

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


    def reverse_list(self, l_s):
        l_n = len(l_s)
        for i in range(l_n // 2):
            l_s[i], l_s[-1-i] = l_s[-1-i], l_s[i]
        return l_s
卡码网:54.替换数字

题目链接:54. 替换数字(第八期模拟笔试)

思考:需要把数字出现的位置上数字换为number,由于原本一个长度的变成了6个长度,后面的元素就要向后移动,这样操作很麻烦,因为还需要插入空位置。

所以,首先创建一个足够长度的空字符数组,然后从数组末尾开始填写字符,原数组也是从末尾开始进行遍历,逐个判断,如果是字母就直接写到新数组中,如果是数字,就要把当前下标到前面的6个位置写入number。直到遍历到原数组开头位置为止。

代码:

def main():
    data = input()
    count = sum(1 for char in data if char.isdigit()) 
    expand_len = len(data) + (count * 5) 
    res = [''] * expand_len
        
    new_index = expand_len - 1 
    old_index = len(data) - 1 
        
    while old_index >= 0: 
        if data[old_index].isdigit():
            res[new_index-5:new_index+1] = "number"
            new_index -= 6
        else:
            res[new_index] = data[old_index]
            new_index -= 1
        old_index -= 1
        
    result = "".join(res)
    print(result)


if __name__ == "__main__":
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值