【力扣一刷】代码随想录day8(344、 541、卡码网54、151、卡码网55)

【字符串基础】

1、字符串的创建方式

常用的构造器:

2、字符串的常用方法

【344.反转字符串】- 简单题

方法  双指针

class Solution {
    public void reverseString(char[] s) {
        int left = 0;
        int right = s.length - 1;
        while (left < right){
            char c = s[left];
            s[left] = s[right];
            s[right] = c;

            left++;
            right--;
        }
    }
}

时间复杂度: O(n)

空间复杂度: O(1)

【541. 反转字符串II】- 简单题

思路:以2k的步长遍历字符串,再利用左右指针反转前k个字符串

关键:当剩余字符串足够k个和不足k个时,右指针right的取值不同

注意:由于Java中String类为不可变类型,因此需要将其转换成字符数组 char[] 或者StringBuffer对象(线程安全)。

方法一  利用双指针和【StringBuffer】实现

StringBuffers的相关方法:

1、创建对象:StringBuffer sb = new StringBuffer(String s);

2、获取字符串的长度:sb.length();

3、获取指定索引的字符:sb.charAt(int idx);

4、设置指定索引的字符:sb.setCharAt(int idx, char c);

5、转化为字符串:sb.toString();

class Solution {
    public String reverseStr(String s, int k) {
        StringBuffer sb = new StringBuffer(s);
        int left;
        int right;

        for (int start = 0; start < sb.length(); start += 2 * k){
            left = start;
            // 剩余字符串不足k个时对右指针的特殊处理
            right = start + k - 1 < sb.length() ? start + k - 1 : sb.length() - 1; 

            while (left < right){
                // 交换左右指针的字符
                char c = sb.charAt(left);
                sb.setCharAt(left, sb.charAt(right));
                sb.setCharAt(right, c);
                // 更新左右指针
                left++;
                right--;
            }
            
        }

        return sb.toString();
    }
}

时间复杂度: O(n),遍历次数n/2k,在每次遍历最多反转k个字符,O(k * n/2k)=O(n)

空间复杂度: O(n),利用StringBuffer对象存储长度为n的字符串

方法二  利用双指针和【字符数组】实现

字符数组的相关方法:

1、字符串 -> 字符数组:char[] sc = s.toCharArray();

2、获取字符数组的长度:sc.length;   // 注意:数组获取长度都是没括号

3、获取指定索引的字符:sc[idx];

4、设置指定索引的字符:sc[idx] = c;

5、字符数组 -> 字符串:sb.toString();

class Solution {
    public String reverseStr(String s, int k) {
        char[] sc = s.toCharArray();
        int left;
        int right;

        for (int start = 0; start < sc.length; start += 2 * k){
            left = start;
            // 剩余字符串不足k个时对右指针的特殊处理
            right = start + k - 1 < sc.length ? start + k - 1 : sc.length - 1; 

            while (left < right){
                // 交换左右指针的字符
                char c = sc[left];
                sc[left] = sc[right];
                sc[right] = c;
                // 更新左右指针
                left++;
                right--;
            }
            
        }

        return new String(sc);
    }
}

时间复杂度: O(n),遍历次数n/2k,在每次遍历最多反转k个字符,O(k * n/2k)=O(n)

空间复杂度: O(n),利用字符数组存储长度为n的字符串

【总结】

1、可变类型和不可变类型

由于Java中的String类为不可变类型,因此不能按指定索引修改字符,需要将字符串转换成

可变类型的变量(如:StringBuffer对象,字符数组等)。

2、获取不同类型的长度的方法汇总:

字符串:s.length()

数组:s.length

集合/映射:s.size()

【卡码网:54.替换数字】- 简单题

注意:

1、卡码网需要自己编写main函数,需要先定义Main类,再定义main函数

2、卡码网需要自己编写输入和输出,要熟悉不同类型的数据的输入方式

import java.util.*;

public class Main{
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length(); i++){
            // 当前遍历的字符是数字('0' = 48, 'a' = 97)
            if (s.charAt(i) < 'a'){
                sb.append("number");
            }
            // 当前遍历的是小写字母
            else{
                sb.append(s.charAt(i));
            }
        }
        System.out.println(sb.toString());
    }
}

时间复杂度: O(n)

空间复杂度: O(n)

【151.翻转字符串里的单词】- 中等题

方法一  利用String类的trim和split函数水题

思路:

1、利用trim()去除两端的空格,并利用split函数获取String数组

2、倒序遍历String数组,组装单词

class Solution {
    public String reverseWords(String s) {
        // System.out.println(words);

        // 利用split函数获取单词数组(注意:一个空格是" ",多个空格是" +")
        String[] words = s.trim().split(" +");
        System.out.println(Arrays.toString(words));

        // 遍历单词数组,组装所有单词,组合成要求的字符串
        StringBuffer res = new StringBuffer();
        for (int i = words.length - 1; i >= 0; i--){
            res.append(words[i]);
            if (i != 0){
                res.append(" ");
            }
        }

        return res.toString();
    }
}

时间复杂度: O(n)

空间复杂度: O(n),创建了额外的List对象存储所有单词

方法二  不需要额外的List对象存储单词

思路:假设原来的字符串为 "the         sky is   blue  "

1、移除首尾和中间多余的空格 : "the sky is blue" (利用创建的函数removeSpace实现)

2、反转整个字符串:"eulb si yks eht" (利用创建的函数reverseString实现)

3、反转各个单词:"blue is sky the" (利用创建的函数reverseWord实现)

注意:

removeSpace函数和reverseWord函数的条件判断十分巧妙,要仔细分析和理解。

class Solution {
    // 1、去除首位及多余的空格
    private StringBuffer removeSpace(String s){
        int start = 0;
        int end = s.length() - 1;
        
        // 去除首尾多余的空格
        while (s.charAt(start) == ' ') start++;
        while (s.charAt(end) == ' ') end--;

        // 2、去除中间多余空格的同时获取返回的字符串
        StringBuffer sb = new StringBuffer();
        for(int i = start; i <= end; i++){
            // 只有两种情况符合拼接要求:a.当前字符不是空格  b.当前字符是空格,但上一个字符不是空格
            if (s.charAt(i) != ' ' || s.charAt(i - 1) != ' '){
                sb.append(s.charAt(i));
            }
        }
        return sb;
    }

    // 2、反转指定范围的字符串
    private StringBuffer reverseString(StringBuffer sb, int start, int end){
        while(start < end){
            char c = sb.charAt(start);
            sb.setCharAt(start, sb.charAt(end));
            sb.setCharAt(end, c);

            start++;
            end--;
        }
        return sb;
    }

    // 3、反转所有单词
    private StringBuffer reverseWord(StringBuffer sb){
        int start = 0;
        int end = -1; // 注意end初始值应该从-1开始
        for (int i = 0; i <= sb.length(); i++){  // 注意:此处能取=,是要判断是否已经遍历完字符串
            if (i < sb.length() && sb.charAt(i) != ' '){
                end++;
            }
            // 如果遇到空格或已经遍历完字符串(i = sb.length()),就要反转字符串
            else{
                reverseString(sb, start, end);
                start = i + 1;
                end = i;
            }
        }
        return sb;
    }

    // 总的操作
    public String reverseWords(String s) {
        StringBuffer sb =  removeSpace(s);
        sb = reverseString(sb, 0, sb.length() - 1);
        sb = reverseWord(sb);
        return sb.toString();
    }
}

时间复杂度: O(n),reverseWord函数中,找单词遍历整个字符串为O(n),所有单词反转了一次,也是O(n),所以加起来还是O(n)。

空间复杂度: O(n)

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

方法一  利用StringBuffer+简单拼接

注意:sc.next();替换为sc.nextLine(); 会导致读取完数字后再读取字符串失败

原因:

  • 由于 nextLine() 方法会读取并返回输入中的下一行内容,包括换行符。输入了一个整数后按下了回车键,此时换行符被作为下一行的内容被 nextLine()读取了。
  • 在使用 next() 方法时,它会读取并返回下一个以空白符分隔的字符串,但不会读取换行符。
import java.util.*;

public class Main{
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        int k = sc.nextInt();
        String s = sc.next();
        
        StringBuffer sb = new StringBuffer();
        
        // 先拼接后k个字符
        int start = s.length() - k;
        while (start < s.length()){
            sb.append(s.charAt(start));
            start++;
        }
        
        // 再拼接剩余的字符
        int i = 0;
        while (i < s.length() - k){
            sb.append(s.charAt(i));
            i++;
        }
        System.out.println(sb.toString());
    }
}

时间复杂度: O(n)

空间复杂度: O(n)

方法二  利用字符数组,整体反转+分段反转

思路:

1、整体反转:如果输入的k=2,s="abcdefg",整体反转后为"gfedcba"

2、分段反转:反转前k个字符和反转剩余的字符,得到"fgabcde",就是想要的结果

3、写一个反转指定范围字符串的函数,再调用三次即可

注意:

main函数为静态方法,自定义的方法也需要是静态方法才能被main函数使用

import java.util.*;

public class Main{
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        int k = sc.nextInt();
        String s = sc.next();
        
        char[] res = s.toCharArray();
        res = reverseString(res, 0, res.length - 1); // 整体反转
        res = reverseString(res, 0, k - 1); // 反转前k个
        res = reverseString(res, k, res.length - 1); // 反转剩余的
        System.out.println(res);;
    }
    
    // 反转指定范围字符串
    public static char[] reverseString(char[] cc, int start, int end){
        while(start < end){
            char c = cc[start];
            cc[start] = cc[end];
            cc[end] = c;
            
            start++;
            end--;
        }
        return cc;
    }
}

时间复杂度: O(n)

空间复杂度: O(n)

  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值