java算法day7

2024-04-28 00:04
文章标签 java 算法 day7

本文主要是介绍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);}
}

这篇关于java算法day7的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/941846

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第