代码随想录算法训练营第七天 | 字符串 Part01


每日任务

一,leetcode 344 反转字符串
二,leetcode 541 反转字符串II
三,卡码网 54 替换数字

一、leetcode 344 反转字符串

1、原题链接

leetcode 344 反转字符串
在这里插入图片描述
在这里插入图片描述

2、解题思路及代码展示

本题求解依然是使用双指针的方法,只不过对于字符串的反转,要比链表简单一些。因为字符串也是一种数组,所以元素在内存中是连续分布,这就决定了反转链表和反转字符串方式上还是有所差异的。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
PS:本题可能有的同学想到说能不能直接调用已经成熟的库函数呢?那么在现场面试中,我们什么时候使用库函数,什么时候不要用库函数呢?
答:如果题目关键的部分直接用库函数就可以解决,建议不要使用库函数。特别是java,其提供的库函数十分丰富。如果库函数仅仅是 解题过程中的一小部分,并且你已经很清楚这个库函数的内部实现原理的话,可以考虑使用库函数。

具体代码实现:

class Solution {
    public void reverseString(char[] s) {
        // 使用双指针的思路
        // 定义一个左指针指向字符数组第一个元素
        int left = 0;
        // 定义一个右指针指向字符数组第一个元素
        int right = s.length -1;
		// 开始执行动作
        while(left < right){
            char temp = s[left];
            s[left] = s[right];
            s[right] = temp;
            left ++;
            right --;
        }
    }
}

二、leetcode 541(反转字符串II)

1、原题链接

leetcode 541(反转字符串II)
在这里插入图片描述
在这里插入图片描述

2、解题思路及代码展示

每隔2k个字符,翻转前k个字符,就是在遍历字符串的过程中,只要让 i += (2 × k),i 每次移动 2k 就可以了,然后判断是否需要有反转的区间。
解法一:比较抽象,不太好理解

class Solution {
    public String reverseStr(String s, int k) {

        // 解法一
        // 定义一个StringBuffer来存放结果,StringBuffer底层基于动态数组,方便增删元素
        StringBuffer res = new StringBuffer();
        int length = s.length();
        int start = 0;

        while(start < length){
            //找到k处和2k处
            StringBuffer temp = new StringBuffer();
            // 与length进行判断,如果大于length了,那就将其置为length
            int firstK = (start+k >length)? length:start+k;
            int secondKey = (start+(2*k) >length)? length:start+(2*k);
            
            // 无论start在何种位置,肯定会翻转一次
            // 先将要反转的部分裁剪出来
            temp.append(s.substring(start,firstK));
            // 直接调用库函数reverse,注意,只有StringBuffer才有这个reverse函数
            res.append(temp.reverse());

            // 如果firstKey和secondKey之间有元素,按照题目要求,这些保持不变,不用反转
            if(firstK<secondKey){
                res.append(s.substring(firstK,secondKey));
            }

            start += (2*k);

        }
        return res.toString();
    }
}

解法二:较好理解

// 题目的意思其实概括为 每隔2k个反转前k个,尾数不够k个时候全部反转
class Solution {
    public String reverseStr(String s, int k) {
    	// 先利用toCharArray字符串转为字符数组
        char[] ch = s.toCharArray();
        // 开始循环,每次跳2k个
        for(int i = 0; i < ch.length; i += 2 * k){
            int start = i;
            //这里是判断尾数够不够k个来取决end指针的位置,ch.length - 1 与  start + k - 1 娶个最小值,取ch.length - 1就是不足k个,取start + k - 1 就是多于k小于2k个
            int end = Math.min(ch.length - 1, start + k - 1);
            //用异或运算反转 
            while(start < end){
                ch[start] ^= ch[end];
                ch[end] ^= ch[start];
                ch[start] ^= ch[end];
                start++;
                end--;
            }
        }
        return new String(ch); // 将字符数组强制转换为字符串
    }
}

三、卡码网 替换数字

1、原题链接

卡码网 替换数字
在这里插入图片描述

2、解题思路及代码展示

以“a 5 b”为例,想要将其扩充为“a n u m b e r b ”,首先要做的就是将原数组扩充到每个数字字符替换成 “number” 之后的大小。字符串 “a5b” 的长度为3,那么 将 数字字符变成字符串 “number” 之后的字符串为 “anumberb” 长度为 8。
在这里插入图片描述
然后,从后向前替换数字字符,也就是双指针法,过程如下:i指向新长度的末尾,j指向旧长度的末尾。
在这里插入图片描述
PS:为什么要从后向前填充,从前向后填充不行么?

因为从前向后填充就是O(n^2)的算法了,因为每次添加元素都要将添加元素之后的所有元素整体向后移动。很多数组填充类的问题,其做法都是先预先给数组扩容带填充后的大小,然后在从后向前进行操作。

直接上代码:

import java.util.Scanner;

public class Main {
    
    public static String replaceNumber(String s) {
    	
    	// 想知道扩容之后有几个数字会变成number
        int count = 0; // 统计数字的个数
        int sOldSize = s.length();
        for (int i = 0; i < s.length(); i++) {
        	// 遍历数组,利用charAt()和isDigit()两个方法统计数字的个数
            if(Character.isDigit(s.charAt(i))){
                count++;
            }
        }
        
        // 扩充字符串s的大小,也就是每个空格替换成"number"之后的大小
        char[] newS = new char[s.length() + count * 5]; // 从1个变成6个
        int sNewSize = newS.length;
        // 将旧字符串的内容填入新数组
        System.arraycopy(s.toCharArray(), 0, newS, 0, sOldSize);
        
        // 从后往前将空格替换为"number",i指针代表最后一个元素,j指针代表原来
        for (int i = sNewSize - 1, j = sOldSize - 1; j < i; j--, i--) {
            if (!Character.isDigit(newS[j])) {
                newS[i] = newS[j];
            } else {
                newS[i] = 'r';
                newS[i - 1] = 'e';
                newS[i - 2] = 'b';
                newS[i - 3] = 'm';
                newS[i - 4] = 'u';
                newS[i - 5] = 'n';
                i -= 5;
            }
        }
        return new String(newS);
    };
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String s = scanner.next();
        System.out.println(replaceNumber(s));
        scanner.close();
    }
}

提示:这里对文章进行总结:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值