java算法day7

字符串篇

  • java该学的字符串基础
  • 反转字符串
  • 反转字符串Ⅱ
  • 替换数字

java该学的字符串基础。

在Java中,String 类是用来操作字符序列的。Java中的字符串是不可变的,这意味着一旦一个字符串被创建,其内容就不能改变。下面是一些关于Java字符串及其在算法题中常用技巧的详细介绍:

Java中的String类基础
创建字符串:
直接使用双引号:String s = “Hello”;
使用构造函数:String s = new String(“Hello”);

字符串常用方法:
.length() - 返回字符串的长度。
.charAt(index) - 返回指定位置的字符。
.substring(beginIndex, endIndex) - 返回子字符串。
.contains(CharSequence s) - 检查字符串是否包含序列s。
.equals(Object another) - 比较两个字符串的内容是否相等。
.equalsIgnoreCase(String another) - 同上,但忽略大小写。
.split(String regex) - 根据匹配给定的正则表达式来拆分字符串。
.indexOf(String str) - 返回指定子字符串在此字符串中第一次出现处的索引。
.toLowerCase() 和 .toUpperCase() - 转换字符串的大小写。
.trim() - 返回去除前导和尾随空格的字符串副本。

字符串比较:
使用 equals() 方法比较字符串内容,而不是使用 ==,后者比较的是引用。

一个习惯性操作:
想像c++一样,如果String能够按下标访问,修改,那很多题做起来就方便的多。但是上面String由于不可变性。所以它的任何操作并不能够修改字符串的本身。

接下来将解决这个难题。

方法1:转换为字符数组,完成操作后再转为字符串。
看一个例子就懂了。

String s = "Hello";
char[] charArray = s.toCharArray();  //通过toCharArray()方法转换
charArray[1] = 'a';  // 修改第二个字符。变成数组了就可以修改了
String newString = new String(charArray); //创建字符串可以将字符数组传入作为参数。
System.out.println(newString);  // 输出 "Hallo"

方法2:使用StringBuffer或者StringBuilder。

StringBuilder

StringBuilder 是一个可变的字符序列。与不可变的 String 类不同,StringBuilder 允许你在原地修改字符串而不需要每次修改都生成新的字符串对象,这样可以大大提高效率。

StringBuilder是一个非线程安全的可变字符序列,它通常比StringBuffer更快,因为它不进行同步。

创建 StringBuilder 对象
你可以通过多种方式创建 StringBuilder 对象:

StringBuilder sb1 = new StringBuilder();  // 创建一个空的StringBuilder
StringBuilder sb2 = new StringBuilder(10);  // 指定初始容量
StringBuilder sb3 = new StringBuilder("Hello");  // 从一个字符串开始

常用方法

append() - 添加文本到当前StringBuilder对象的末尾。

StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb.toString());  // 输出 "Hello World"

insert() - 在指定位置插入文本

StringBuilder sb = new StringBuilder("Hello World");
sb.insert(6, "Java ");
System.out.println(sb.toString());  // 输出 "Hello Java World"

replace() - 替换StringBuilder中的一部分内容。

StringBuilder sb = new StringBuilder("Hello World");
sb.replace(6, 11, "Java");
System.out.println(sb.toString());  // 输出 "Hello Java"

delete() 和 deleteCharAt() - 删除StringBuilder中的一部分内容或特定位置的字符。

StringBuilder sb = new StringBuilder("Hello World");
sb.delete(5, 11);
System.out.println(sb.toString());  // 输出 "Hello"
sb.deleteCharAt(4);
System.out.println(sb.toString());  // 输出 "Hell"

reverse() - 将StringBuilder中的内容反转。

StringBuilder sb = new StringBuilder("Hello");
sb.reverse();
System.out.println(sb.toString());  // 输出 "olleH"

setCharAt() - 设置指定位置的字符。

StringBuilder sb = new StringBuilder("Hello");
sb.setCharAt(1, 'a');
System.out.println(sb.toString());  // 输出 "Hallo"

length(), capacity() - 获取长度和容量。

StringBuilder sb = new StringBuilder("Hello");
System.out.println("Length: " + sb.length());  // 输出 "Length: 5"
System.out.println("Capacity: " + sb.capacity());  // 输出 "Capacity: 21" (初始容量是16加上字符串长度)

最重要的就是这个sb.toString()转String类型。

使用 StringBuilder 的一个主要优点是它可以避免创建多个临时不可变字符串对象,这在循环或频繁操作字符串内容的场景中非常有用。例如,拼接字符串时,使用 StringBuilder 要比使用 String 直接拼接(使用 + 操作符)效率高得多。

StringBuffer

这两个方法都是类似的,主要区别就在于线程安全性。StringBuffer是线程安全的,而StringBuilder不是线程安全的。这意味着StringBuffer适用于多线程环境中,而StringBuilder则适用于单线程或不需要考虑线程安全的情况。

StringBuffer是一个线程安全的可变字符序列。它通过内部同步来确保多个线程可以安全地同时修改字符串缓冲区。

StringBuffer:在你需要确保字符串操作的线程安全时使用StringBuffer。例如,在web应用服务器或任何多线程应用程序中处理字符串时。
StringBuilder:在单线程环境中或不关心线程安全的情况下使用StringBuilder,因为它没有同步开销,通常会比StringBuffer更快。

总的来说,选择StringBuffer还是StringBuilder主要取决于是否需要线程安全。在性能敏感的应用中,通常推荐使用StringBuilder,除非你需要在多线程环境中操作字符串。

二者都会自动扩容

StringBuffer和StringBuilder都会在需要时自动扩容。这是通过内部机制实现的,以便这两种类型的对象可以在运行时根据需要增加存储容量,以容纳更多的字符。

扩容机制
当你向StringBuffer或StringBuilder添加内容,而当前容量不足以容纳新增的内容时,它们会自动进行扩容。扩容的过程通常涉及以下步骤:

计算新容量:新的容量通常是当前容量的两倍加上2,但这可能因JVM的实现而异。如果这个新计算的容量还不足以容纳新增的数据,那么容量会增加到必要的大小以适应新增的数据。

分配新数组:一旦计算出新的容量,就会创建一个新的字符数组,其大小等于新的容量。

复制数据:原有数组中的数据会被复制到新的数组中。

替换数组:旧的字符数组被新的字符数组替换,旧的数组将被垃圾回收。


反转字符串

这题无论是双指针往中间靠,还是凭借下标的关系都可以完成这个题。

class Solution {
    public void reverseString(char[] s) {
        for(int i = 0;i<s.length/2;i++){ //只到中间
            char temp; //相对的元素进行两两交换。
            temp = s[s.length-i-1];
            s[s.length-i-1] = s[i];
            s[i] = temp;
        }
    }
}

翻转字符串Ⅱ

也很简单,主要就是想清楚2k个元素之中的下标位置。在处理好区间的基础上。对每个区间完成翻转字符串即可。

class Solution {
    public String reverseStr(String s, int k) {
        char[] str = s.toCharArray(); //先转为字符数组
        for(int i = 0;i<str.length;){ //这里就没必要对i进行操作了。处理完一个区间后。i直接跳转到下一个区间的起点就可以了。一旦跳转到下一个区间起点不符合i的限制,循环会自动停止的。
            if(i+2*k-1<=str.length-1){ //当第2k个元素还在字符数组的有效范围。由于下标从0开始,所以第2k个字符的位置在i+2*k-1这个位置。接下来进行翻转数组的操作。
                //翻转前k个字符
                int start=i;
                int end = i+k-1;
                int goNext = i+2*k; //设置i下一个区间的跳转点。
                while(start<=end){ //纯纯双指针交换首尾
                    char temp =str[end];
                    str[end] = str[start];
                    str[start] = temp;
                    start++;
                    end--;
                }
                i = goNext; //i进行跳转
            }else{ 
                //这个时候第2k个元素的下标已经超了,检查里面的字符是在1k以上还是1k以下
                if(i+k-1>=str.length-1){ //检查1k这个地方还在有效范围没有,如果1k这个地方也超了,说明剩余不足1k,全部翻转
                    int start = i;
                    int end = str.length-1;
                    while(start<=end){
                        char temp = str[end];
                        str[end] = str[start];
                        str[start] = temp;
                        start++;
                        end--;
                    }
                    break; //翻转完就可以结束了。因为这种情况只在尾部。
                }else{
                    //1k这个地方如果还在有效区间,那就翻转前k。
                    int start = i;
                    int end = i+k-1;
                    while(start<=end){
                        char temp = str[start];
                        str[start] = str[end];
                        str[end] = temp;
                        start++;
                        end--;
                    }
                    break;//翻转完就可以结束了。因为这种情况只在尾部。
                }
            }
        }
        

        return new String(str); //转为字符串返回
    }
}

替换数字

题目的意思就每遇到一个数字就改为把这个数字去掉,然后插一个字符串"number"进去。java做这个我感觉最好用的办法就是空间换时间了。用StringBuilder。

思路:遍历字符串,是数字就把number字符串插入,不是数字就把遍历的字符给插入。
我的写法:看着就是有点长了。

import java.util.Scanner;

class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();
        String result = replaceNum(s);
        System.out.println(result);
        
    }
    
    
    
    public static String replaceNum(String s){
        int count = 0;
        char[] str = s.toCharArray();
        for(char c : str){
            if(c>='0' && c <='9'){
                count++;
            }
        }
        String insertStr = "number";
        int numLength = 6;
        int sum = s.length() - count + numLength*count;
        StringBuilder sb = new StringBuilder(sum);
        for(char c:str){
            if(c>='0'&& c<='9'){
                sb.append(insertStr);
            }else{
                sb.append(c);
            }
        }
        
        return sb.toString();
        
    }
    
}

代码随想录解法:
这个解法简短就在于直接用s.charAt()访问字符串。而我是转字符数组多此一举。

所以以后如果是这种遍历插入构造新字符串的。不涉及修改元素组来进行操作,最好还是用charAt(),如果是原数组进行处理,那么转为字符数组要好做的多。

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String s = in.nextLine();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            if (Character.isDigit(s.charAt(i))) {
                sb.append("number");
            }else sb.append(s.charAt(i));
        }
        System.out.println(sb);
    }
}
  • 28
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值