Carl代码随想录算法训练营-Day 8-344.反转字符串、541. 反转字符串II、卡码网:54.替换数字、151.翻转字符串里的单词、卡码网:55.右旋转字符串

摘要

本文是日常算法学习记录。今天完成了344.反转字符串、541. 反转字符串II、卡码网:54.替换数字、151.翻转字符串里的单词、卡码网:55.右旋转字符串,共五题,并用文字详细描述了算法运行过程。

344、反转字符串

LeetCode题目链接

思路分析

这道题给了一个字符数组,要求反转整个数组,而且需要原地修改,使用O(1)的额外空间。
幸好给的是字符数组,否则给字符串的话,Java就无法使用O(1)的额外空间了。
思路很清晰很明确,那就是使用指针i从数组头部开始,指针j从数组尾部开始,同时向数组中间遍历,每次遍历互换ij位置处的元素即可,直到i=j

代码实现

public void reverseString(char[] s) {
            int i = 0, j = s.length - 1;
            do {
                char tmp = s[i];
                s[i] = s[j];
                s[j] = tmp;
            } while (++i < --j);
        }

541、反转字符串II

LeetCode题目链接

思路分析

这道题与上一题《344.反转字符串》形似,但在反转的规则上有所变化。
因此,先数m*(2k)个字符,分别交换其前k个字符。最后再单独对n-m*(2k)个字符进行反转即可。

代码实现

public String reverseStr(String s, int k) {
            char[] chars = s.toCharArray();
            int i, p, q;
            for (i = 0; chars.length - i >= k << 1; i += k << 1) {
                p = i;
                q = i + k - 1;
                do {
                    char tmp = chars[p];
                    chars[p] = chars[q];
                    chars[q] = tmp;
                } while (++p < --q);
            }
            p = i;
            if (chars.length - i < k) {
                q = chars.length - 1;
            } else {
                q = i + k - 1;
            }
            while (p < q) {
                char tmp = chars[p];
                chars[p++] = chars[q];
                chars[q--] = tmp;
            }
            return new String(chars);
        }

卡码网:54、替换数字

LeetCode题目链接

思路分析

卡码网题目不同于LeetCode题目之处在于其编码方式要使用ACM方式,故而需要处理输入输出,且要写出完整的.java文件。
算法部分,要将数字全部替换为"number"。对于Java来说,要操作字符串,则必须申请额外空间。因此可以直接实例化一个StringBuilder类的对象sb,用于构造新的字符串。随后对输入的字符串逐字符遍历读取,如果当前字符c不是小写英文字母(其ASCII码小于97),就给sb接上字符串"number",否则直接接上c

代码实现

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        while(sc.hasNextLine()){
            String s=sc.nextLine();
            StringBuilder sb=new StringBuilder();
            for(int i=0;i<s.length();i++){
                char c=s.charAt(i);
                sb.append(c<97?"number":c);
            }
            System.out.println(sb);
        }
    }
}

151、翻转字符串里的单词

LeetCode题目链接

思路分析

这是一道很经典的字符串操作算法题。
定义两个指针,iji表示当前读取的字符,j表示当前单词的尾字符。
实例化一个StringBuilder类对象sb,用于构造翻转后的新字符串
i从字符串尾部从后往前遍历,如果i处字符为空格的话,我们就认定i-1的位置是下一个单词的位置,从而把j设为i-1,记录为下一个单词的结尾。
如果i的下一个遍历之处,也就是i-1处的字符为空格,那么我们就认定遍历到了当前单词的首字母,从而从i处开始遍历到j处,将读取到的每一个字符放入到sb中,并在最后加上一个空格。
由于新字符串首尾不允许有空格,因此如果新字符串最后一个字符为空格的话,还要删除。

代码实现

public String reverseWords(String s) {
            StringBuilder sb = new StringBuilder();
            for (int i = s.length() - 1, j = i; i >= 0; i--) {
                if (s.charAt(i) == ' ') {
                    j = i - 1;
                } else if (i == 0 || s.charAt(i - 1) == ' ') {
                    for (int k = i; k <= j; k++) {
                        sb.append(s.charAt(k));
                    }
                    if (i > 0) {
                        sb.append(' ');
                    }
                }
            }
            if (sb.charAt(sb.length() - 1) == ' ') {
                sb.deleteCharAt(sb.length() - 1);
            }
            return sb.toString();

卡码网:55.右旋转字符串

LeetCode题目链接

思路分析

先调试好输入输出。
这道题有多重算法选择。
方法一。对字符串进行切片操作,即前n-k个字符的子串,和后k个字符的子串,然后将前者拼接到后者后面。这种方法由于需要对字符串进行切片操作,所以时间复杂度为O(n),空间复杂度也为O(n)
方法二。将后k个字符逐个向前移动,直到全部移动到开头。每次移动使用类似swap的操作,每个字符移动到开头,时间复杂度为O(n)k个字符需要O(kn)。如果不算Java必须的字符串转字符数组的空间,其空间复杂度为O(1)
方法三。将整个字符串反转(reverse),在分别对前k个字符和后n-k个字符进行反转。三次反转,时间复杂度分别为O(n)O(k)O(n-k),所以整体为O(n)。如果不算Java必须的字符串转字符数组的空间,其空间复杂度为O(1)

代码实现

展示对方法三的实现。

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        while(sc.hasNextLine()){
            int k=Integer.parseInt(sc.nextLine());
            String s=sc.nextLine();
            char[] arr=s.toCharArray();
            for(int i=0,j=arr.length-1;i<j;i++,j--){
                arr[i]^=arr[j];
                arr[j]^=arr[i];
                arr[i]^=arr[j];
            }
            for(int i=k,j=arr.length-1;i<j;i++,j--){
                arr[i]^=arr[j];
                arr[j]^=arr[i];
                arr[i]^=arr[j];
            }
            for(int i=0,j=k-1;i<j;i++,j--){
                arr[i]^=arr[j];
                arr[j]^=arr[i];
                arr[i]^=arr[j];
            }
            System.out.println(new String(arr));
        }
    }
}

总结和思考

以上就是今天的算法学习记录,我们通过分析思路和实现代码的方式,解决了这道题目。希望对大家的算法学习有所帮助,谢谢阅读!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值