草庐IT

【LeetCode算法成长之路】Java字符串相关类总结与经典题目分析

小新要变强 2023-04-13 原文

前言

本文小新为大家带来 Java字符串相关类总结与经典题目分析 相关知识,具体内容包括不可变字符序列String介绍(包括:String 的特性String 的构造器String 与其他结构间的转换String 的基本常用方法String 的查找方法String 的字符串截取方法String 的和字符/字符数组相关方法String 的开头与结尾判断方法String 的替换方法),可变字符序列StringBuffer与StringBuilder(包括:StringBuffer 与 StringBuilder 的理解StringBuilder、StringBuffer 的 API),字符串操作经典算法题目(包括:去除字符串两端的空格将字符串进行反转一个字符串在另一个字符串中出现的次数两个字符串中的最大相同子串对字符串中字符进行自然顺序排序)等进行详尽介绍~

不积跬步,无以至千里;不积小流,无以成江海。每天进步一点点,在成为强者的路上,小新与大家共同成长!

📌博主主页:小新要变强 的主页
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
👉Java微服务开源项目可参考:企业级Java微服务开源项目(开源框架,用于学习、毕设、公司项目、私活等,减少开发工作,让您只关注业务!)


目录

Java字符串相关类总结与经典题目分析

在LeetCode算法题目中有许多 关于字符串的题目,对于这些题目,如果我们需要熟练掌握Java中的字符串类,包括其中常用的方法,对于这类题目就可以游刃有余。

下面会先为大家对不可变字符序列String,及可变字符序列StringBuffer与StringBuilder进行介绍,并为大家总结有关的常用方法,最后为大家展示几道与字符串有关的经典算法题目。

一、不可变字符序列String

1️⃣String 的特性

  • java.lang.String 类代表字符串。Java 程序中所有的字符串文字(例如 “hello” )都可以看作是实现此类的实例。
  • 字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
  • 字符串 String 类型本身是 final 声明的,意味着我们不能继承String。
  • String 对象的字符内容是存储在一个字符数组 value[]中的。“abc” 等效于 char[] data={‘h’,‘e’,‘l’,‘l’,‘o’}。

  • Java 语言提供对字符串串联符号(“+”)以及将其他对象转换为字符串的特殊支持(toString()方法)。

2️⃣String 的构造器

  • public String() :初始化新创建的 String 对象,以使其表示空字符序列。
  • String(String original): 初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。
  • public String(char[] value) :通过当前参数中的字符数组来构造新的String。
  • public String(char[] value,int offset, int count) :通过字符数组的 一部分来构造新的String。
  • public String(byte[] bytes) :通过使用平台的默认字符集解码当前参数中的字节数组来构造新的 String。
  • public String(byte[] bytes,String charsetName) :通过使用指定的字符集解码当前参数中的字节数组来构造新的 String。

3️⃣String 与其他结构间的转换

🍀字符串 --> 基本数据类型、包装类

  • Integer 包装类的 public static int parseInt(String s):可以将由“数字”字符组成的字符串转换为整型。
  • 类似地,使用 java.lang 包中的 Byte、Short、Long、Float、Double类调相应的类方法可以将由“数字”字符组成的字符串,转化为相应的基本数据类型。

🍀基本数据类型、包装类 --> 字符串

  • 调用 String 类的 public String valueOf(int n)可将 int 型转换为字符串。
  • 相应的 valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double d)、valueOf(boolean b)可由参数的相应类型到字符串的转换。

🍀字符数组 --> 字符串

  • String 类的构造器:String(char[]) 和 String(char[],int offset,int length)
    分别用字符数组中的全部字符和部分字符创建字符串对象。

🍀字符串 --> 字符数组

  • public char[] toCharArray():将字符串中的全部字符存放在一个字符数组中的方法。
  • public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):提供了将指定索引范围内的字符串存放到数组中的方法。

🍀字符串 --> 字节数组(编码)

  • public byte[] getBytes() :使用平台的默认字符集将此 String 编码为 byte序列,并将结果存储到一个新的 byte 数组中。
  • public byte[] getBytes(String charsetName) :使用指定的字符集将此String编码到byte 序列,并将结果存储到新的 byte 数组。

🍀字节数组 --> 字符串(解码)

  • String(byte[]):通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的String。
  • String(byte[],int offset,int length) :用指定的字节数组的一部分,即从数组起始位置 offset开始取 length 个字节构造一个字符串对象。
  • String(byte[], String charsetName ) 或 new String(byte[], int, int,String charsetName ):解码,按照指定的编码方式进行解码。

4️⃣String 的基本常用方法

String 类包括的方法可用于检查序列的单个字符、比较字符串、搜索字符串、提取子字符串、创建字符串副本并将所有字符全部转换为大写或小写。

  • (1)boolean isEmpty():字符串是否为空
  • (2)int length():返回字符串的长度
  • (3)String concat(xx):拼接
  • (4)boolean equals(Object obj):比较字符串是否相等,区分大小写
  • (5)boolean equalsIgnoreCase(Object obj):比较字符串是否相等,不区分大小写
  • (6)int compareTo(String other):比较字符串大小,区分大小写,按照 Unicode 编码值比较大小
  • (7)int compareToIgnoreCase(String other):比较字符串大小,不区分大小写
  • (8)String toLowerCase():将字符串中大写字母转为小写
  • (9)String toUpperCase():将字符串中小写字母转为大写
  • (10)String trim():去掉字符串前后空白符
  • (11)public String intern():结果在常量池中共享

5️⃣String 的查找方法

  • (1)boolean contains(xx):是否包含 xx
  • (2)int indexOf(xx):从前往后找当前字符串中 xx,即如果有返回第一次出现的下标,要是没有返回-1
  • (3)int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
  • (4)int lastIndexOf(xx):从后往前找当前字符串中 xx,即如果有返回最后一次出现的下标,要是没有返回-1
  • (5)int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。

6️⃣String 的字符串截取方法

  • (1)String substring(int beginIndex) :返回一个新的字符串,它是此字符串的从 beginIndex开始截取到最后的一个子字符串。
  • (2)String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到 endIndex(不包含)的一个子字符串。

7️⃣String 的和字符/字符数组相关方法

  • (1)char charAt(index):返回[index]位置的字符。
  • (2)char[] toCharArray(): 将此字符串转换为一个新的字符数组返回 。
  • (3)static String valueOf(char[] data) :返回指定数组中表示该字符序列的 String 。
  • (4)static String valueOf(char[] data, int offset, int count) :返回指定数组中表示该字符序列的 String 。
  • (5)static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String 。
  • (6)static String copyValueOf(char[] data, int offset, int count):返回指定数组中表示该字符序列的 String。

8️⃣String 的开头与结尾判断方法

  • (1)boolean startsWith(xx):测试此字符串是否以指定的前缀开始 。
  • (2)boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始。
  • (3)boolean endsWith(xx):测试此字符串是否以指定的后缀结束。

9️⃣String 的替换方法

  • (1)String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar替换此字符串中出现的所有 oldChar 得到的。 不支持正则。
  • (2)String replace(CharSequence target, CharSequence replacement): 使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
  • (3)String replaceAll(String regex, String replacement):使用给定的replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
  • (4)String replaceFirst(String regex, String replacement):使用给定的replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。

二、可变字符序列StringBuffer与StringBuilder

因为 String 对象是不可变对象,虽然可以共享常量对象,但是对于频繁字符串的修改和拼接操作,效率极低,空间消耗也比较高。因此,JDK 又在java.lang包提供了可变字符序列 StringBuffer 和 StringBuilder 类型。

1️⃣StringBuffer 与 StringBuilder 的理解

  • java.lang.StringBuffer 代表可变的字符序列,JDK1.0中声明,可以对字符串内容进行增删,此时不会产生新的对象。比如:
//情况 1:
String s = new String("我喜欢学习");
//情况 2:
StringBuffer buffer = new StringBuffer("我喜欢学习");
buffer.append("数学");

  • StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且提供相关功能 的方法也一样。
  • 区分 String、StringBuffer、StringBuilder:
  • String:不可变的字符序列; 底层使用 char[]数组存储(JDK8.0 中)
  • StringBuffer:可变的字符序列;线程安全(方法有 synchronized 修饰),效率低;底层使用 char[]数组存储 (JDK8.0 中)
  • StringBuilder:可变的字符序列; jdk1.5 引入,线程不安全的,效率高;底 层使用 char[]数组存储(JDK8.0中)

2️⃣StringBuilder、StringBuffer 的 API

StringBuilder、StringBuffer 的 API 是完全一致的,并且很多方法与 String 相同。

🍀常用 API

  • (1)StringBuffer append(xx):提供了很多的 append()方法,用于进行字符串追加的方式拼接
  • (2)StringBuffer delete(int start, int end):删除[start,end)之间字符
  • (3)StringBuffer deleteCharAt(int index):删除[index]位置字符
  • (4)StringBuffer replace(int start, int end, String str):替换[start,end)范围的字符序列为 str
  • (5)void setCharAt(int index, char c):替换[index]位置字符
  • (6)char charAt(int index):查找指定 index 位置上的字符
  • (7)StringBuffer insert(int index, xx):在[index]位置插入 xx
  • (8)int length():返回存储的字符数据的长度
  • (9)StringBuffer reverse():反转

🍀与 String相同的方法

  • (1)int indexOf(String str):在当前字符序列中查询 str 的第一次出现下标
  • (2)int indexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str 的第一次出现下标
  • (3)int lastIndexOf(String str):在当前字符序列中查询 str 的最后一次出现下标
  • (4)int lastIndexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询 str 的最后一次出现下标
  • (5)String substring(int start):截取当前字符序列[start,最后]
  • (6)String substring(int start, int end):截取当前字符序列[start,end)
  • (7)String toString():返回此序列中数据的字符串表示形式
  • (8)void setLength(int newLength) :设置当前字符序列长度为newLength

三、字符串操作经典算法题目

1️⃣题目1:去除字符串两端的空格

模拟一个 trim 方法,去除字符串两端的空格。

public String myTrim(String str) {
  if (str != null) {
    int start = 0;// 用于记录从前往后首次索引位置不是空格的位置的索引
    int end = str.length() - 1;// 用于记录从后往前首次索引位置不是空格的位置的索引
    while (start < end && str.charAt(start) == ' ') {
      start++;
    }
    while (start < end && str.charAt(end) == ' ') {
      end--;
    }
    if (str.charAt(start) == ' ') {
      return "";
    }
    return str.substring(start, end + 1);
  }
  return null;
}

@Test
public void testMyTrim() {
  String str = " a ";
  // str = " ";
  String newStr = myTrim(str);
  System.out.println("---" + newStr + "---");
}

2️⃣题目2:将字符串进行反转

将一个字符串进行反转。将字符串中指定部分进行反转。比如“abcdefg”反转为”abfedcg”。

// 方式一:
public String reverse1(String str, int start, int end) {// start:2,end:5
  if (str != null) {
  // 1.
  char[] charArray = str.toCharArray();
  // 2.
  for (int i = start, j = end; i < j; i++, j--) {
    char temp = charArray[i];
    charArray[i] = charArray[j];
    charArray[j] = temp;
  }
  // 3.
  return new String(charArray);
  }
  return null;
}

// 方式二:
public String reverse2(String str, int start, int end) {
  // 1.
  String newStr = str.substring(0, start);// ab
  // 2.
  for (int i = end; i >= start; i--) {
    newStr += str.charAt(i);
  } // abfedc
  // 3.
  newStr += str.substring(end + 1);
  return newStr;
}

// 方式三:推荐 (相较于方式二做的改进)
public String reverse3(String str, int start, int end) {// ArrayLi
  st list = new ArrayList(80);
  // 1.
  StringBuffer s = new StringBuffer(str.length());
  // 2.
  s.append(str.substring(0, start));// ab
  // 3.
  for (int i = end; i >= start; i--) {
    s.append(str.charAt(i));
  }
  // 4.
  s.append(str.substring(end + 1));
  // 5.
  return s.toString();
}

@Test
public void testReverse() {
  String str = "abcdefg";
  String str1 = reverse3(str, 2, 5);
  System.out.println(str1);// abfedcg
}

3️⃣题目3:一个字符串在另一个字符串中出现的次数

获取一个字符串在另一个字符串中出现的次数。 比如:获取“ ab”在“abkkcadkabkebfkabkskab” 中出现的次数。

// 判断 str2 在 str1 中出现的次数
public int getCount(String mainStr, String subStr) {
  if (mainStr.length() >= subStr.length()) {
    int count = 0;
    int index = 0;
    // while((index = mainStr.indexOf(subStr)) != -1){
    //   count++;
    //   mainStr = mainStr.substring(index + subStr.length());
    // }
    // 改进:
    while ((index = mainStr.indexOf(subStr, index)) != -1) {
      index += subStr.length();
      count++;
    }
    return count;
  } else {
    return 0;
  }
}

@Test
public void testGetCount() {
  String str1 = "cdabkkcadkabkebfkabkskab";
  String str2 = "ab";
  int count = getCount(str1, str2);
  System.out.println(count);
}

4️⃣题目4:两个字符串中的最大相同子串

获取两个字符串中最大相同子串。比如: str1 = "abcwerthelloyuiodef“; str2 = “cvhellobnm” 提示:将短的那个串进行长度依次递减的子串与较长的串比较。

// 如果只存在一个最大长度的相同子串
public String getMaxSameSubString(String str1, String str2) {
  if (str1 != null && str2 != null) {
    String maxStr = (str1.length() > str2.length()) ? str1 : str2;
    String minStr = (str1.length() > str2.length()) ? str2 : str1;
    int len = minStr.length();
    for (int i = 0; i < len; i++) {// 0 1 2 3 4 此层循环决定要去几个字符
      for (int x = 0, y = len - i; y <= len; x++, y++) {
        if (maxStr.contains(minStr.substring(x, y))) {
          return minStr.substring(x, y);
        }
      }
    }
  }
  return null;
}

// 如果存在多个长度相同的最大相同子串
// 此时先返回 String[],后面可以用集合中的 ArrayList 替换,较方便
public String[] getMaxSameSubString1(String str1, String str2) {
  if (str1 != null && str2 != null) {
    StringBuffer sBuffer = new StringBuffer();
    String maxString = (str1.length() > str2.length()) ? str1 : str2;
    String minString = (str1.length() > str2.length()) ? str2 : str1;
    int len = minString.length();
    for (int i = 0; i < len; i++) {
      for (int x = 0, y = len - i; y <= len; x++, y++) {
        String subString = minString.substring(x, y);
        if (maxString.contains(subString)) {
          sBuffer.append(subString + ",");
        }
      }
      System.out.println(sBuffer);
      if (sBuffer.length() != 0) {
        break;
      }
    }
    String[] split = sBuffer.toString().replaceAll(",$", "").split("\\,");
    return split;
  }
  return null;
}

// 如果存在多个长度相同的最大相同子串:使用 ArrayList
// public List<String> getMaxSameSubString1(String str1, String str2) {
//   if (str1 != null && str2 != null) {
//     List<String> list = new ArrayList<String>();
//     String maxString = (str1.length() > str2.length()) ? str1 : str2;
//     String minString = (str1.length() > str2.length()) ? str2 : str1;
//
//     int len = minString.length();
//     for (int i = 0; i < len; i++) {
//       for (int x = 0, y = len - i; y <= len; x++, y++) {
//         String subString = minString.substring(x, y);
//         if (maxString.contains(subString)) {
//           list.add(subString);
//         }
//       }
//       if (list.size() != 0) {
//         break;
//       }
//     }
//     return list;
//   }
//   return null;
// }

@Test
public void testGetMaxSameSubString() {
  String str1 = "abcwerthelloyuiodef";
  String str2 = "cvhellobnmiodef";
  String[] strs = getMaxSameSubString1(str1, str2);
  System.out.println(Arrays.toString(strs));
}

5️⃣题目5:对字符串中字符进行自然顺序排序

对字符串中字符进行自然顺序排序。

提示:

  • 1)字符串变成字符数组;
  • 2)对数组排序,选择,冒泡,Arrays.sort();
  • 3)将排序后的数组变成字符串。
@Test
public void testSort() {
  String str = "abcwerthelloyuiodef";
  char[] arr = str.toCharArray();
  Arrays.sort(arr);
  String newStr = new String(arr);
  System.out.println(newStr);
}

后记

👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~

有关【LeetCode算法成长之路】Java字符串相关类总结与经典题目分析的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  3. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  4. ruby-on-rails - unicode 字符串的长度 - 2

    在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)

  5. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  6. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  7. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  8. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  9. ruby - 如何使用文字标量样式在 YAML 中转储字符串? - 2

    我有一大串格式化数据(例如JSON),我想使用Psychinruby​​同时保留格式转储到YAML。基本上,我希望JSON使用literalstyle出现在YAML中:---json:|{"page":1,"results":["item","another"],"total_pages":0}但是,当我使用YAML.dump时,它不使用文字样式。我得到这样的东西:---json:!"{\n\"page\":1,\n\"results\":[\n\"item\",\"another\"\n],\n\"total_pages\":0\n}\n"我如何告诉Psych以想要的样式转储标量?解

  10. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

随机推荐