文章目录
一、不能有长度大于2的包含公共元素的子串重复
getString(a,0,3)
private static boolean getString(String str,int l,int r){
if(r>=str.length()){
return false;
}
if(str.substring(r).contains(str.substring(l,r))){
return true;
}else{
return getString(str,l+1,r+1);
}
}
二、字符串的排序
对字母排序,可以使用Arrays类的sort方法。下面是一个示例代码,将字符串中的字母按字典序排序:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String str = "hello world";
char[] arr = str.toCharArray();
// 使用 Arrays.sort 方法对字符数组进行排序,实现字典序排序
Arrays.sort(arr);
System.out.println(new String(arr));
}
}
运行以上代码,输出结果为: dehllloorw。
另外,如果要忽略大小写排序,可以使用String类的toLowerCase()或toUpperCase()方法将字符串转换为全小写或全大写,再按照上面的方法排序。
如果您需要对字符串中单词按字典序排序,可以使用Arrays类的sort方法和String类的split方法将字符串分割为单词,再排序。以下是一个示例代码:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String str = "hello world java program";
String[] arr = str.split(" ");
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
运行以上代码,输出结果为:[hello, java, program, world],单词按字典序排序。
三、String和StringBuilder
java中的String类型所表达的字符串是无法改变的,也就是说,只能对字符串进行读操作。如果对字符串进行写操作,那么修改的内容在返回值的字符串中,原来的字符串保持不变。
由于每次对String实例进行修改将创建一个新的String实例,因此如果连续多次对String实例进行修改将连续创建多个新的String实例,不必要的开销较大。所以可以创建一个StringBuilder实例,因为他能容纳修改后的结果。
StringBuilder sb = new StringBuilder(); // 创建一个空的 StringBuilder 对象
sb.append("hello"); // 在末尾添加字符串
sb.append(" world");
System.out.println(sb.toString()); // 输出 "hello world"
sb.insert(5, ","); // 在指定位置插入字符
System.out.println(sb.toString()); // 输出 "hello, world"
sb.delete(5, 6); // 删除指定范围内的字符
System.out.println(sb.toString()); // 输出 "hello world"
sb.replace(0, 5, "hi"); // 替换指定范围内的字符
System.out.println(sb.toString()); // 输出 "hi world"
sb.reverse(); // 反转字符序列
System.out.println(sb.toString()); // 输出 "dlrow ih"
四、String和Char转换
在Java中将String转换为char是非常简单的。
- 使用String.charAt(index)(返回值为char)可以得到String中某一指定位置的char。
- 使用String.toCharArray()(返回值为char[])可以得到将包含整个String的char数组。这样我们就能够使用从0开始的位置索引来访问string中的任意位置的元素。
将char转为String
复制代码
1. String s = String.valueOf('c'); //效率最高的方法
2. String s = String.valueOf(new char[]{'c'}); //将一个char数组转换成String
3. String s = Character.toString('c');
// Character.toString(char)方法实际上直接返回String.valueOf(char)
4. String s = new Character('c').toString();
5. String s = "" + 'c';
// 虽然这个方法很简单,但这是效率最低的方法
// Java中的String Object的值实际上是不可变的,是一个final的变量。
// 所以我们每次对String做出任何改变,都是初始化了一个全新的String Object并将原来的变量指向了这个新String。
// 而Java对使用+运算符处理String相加进行了方法重载。
// 字符串直接相加连接实际上调用了如下方法:
// new StringBuilder().append("").append('c').toString();
6. String s = new String(new char[]{'c'});
五、打印输出List<>
要打印List中的所有字符串,可以使用Java中的增强型for循环或者使用迭代器(Iterator)遍历并打印每个元素。以下是两个例子:
使用增强型for循环:
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
for (String str : list) {
System.out.println(str);
}
使用迭代器:
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
六、翻转字符串里的单词
给定一个字符串,逐个翻转字符串中的每个单词。
示例 1:
输入: “the sky is blue”
输出: “blue is sky the”
示例 2:
输入: " hello world! "
输出: “world! hello”
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入: “a good example”
输出: “example good a”
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
思路:1.用快慢指针去除多余的空格
2.两次翻转
/*
* 解法四:时间复杂度 O(n)
* 参考卡哥 c++ 代码的三步骤:先移除多余空格,再将整个字符串反转,最后把单词逐个反转
* 有别于解法一 :没有用 StringBuilder 实现,而是对 String 的 char[] 数组操作来实现以上三个步骤
*/
class Solution {
//用 char[] 来实现 String 的 removeExtraSpaces,reverse 操作
public String reverseWords(String s) {
char[] chars = s.toCharArray();
//1.去除首尾以及中间多余空格
chars = removeExtraSpaces(chars);
//2.整个字符串反转
reverse(chars, 0, chars.length - 1);
//3.单词反转
reverseEachWord(chars);
return new String(chars);
}
//1.用 快慢指针 去除首尾以及中间多余空格,可参考数组元素移除的题解
public char[] removeExtraSpaces(char[] chars) {
int slow = 0;
for (int fast = 0; fast < chars.length; fast++) {
//先用 fast 移除所有空格
if (chars[fast] != ' ') {
//在用 slow 加空格。 除第一个单词外,单词末尾要加空格
if (slow != 0)
chars[slow++] = ' ';
//fast 遇到空格或遍历到字符串末尾,就证明遍历完一个单词了
while (fast < chars.length && chars[fast] != ' ')
chars[slow++] = chars[fast++];
}
}
//相当于 c++ 里的 resize()
char[] newChars = new char[slow];
System.arraycopy(chars, 0, newChars, 0, slow);
return newChars;
}
//双指针实现指定范围内字符串反转,可参考字符串反转题解
public void reverse(char[] chars, int left, int right) {
if (right >= chars.length) {
System.out.println("set a wrong right");
return;
}
while (left < right) {
chars[left] ^= chars[right];
chars[right] ^= chars[left];
chars[left] ^= chars[right];
left++;
right--;
}
}
//3.单词反转
public void reverseEachWord(char[] chars) {
int start = 0;
//end <= s.length() 这里的 = ,是为了让 end 永远指向单词末尾后一个位置,这样 reverse 的实参更好设置
for (int end = 0; end <= chars.length; end++) {
// end 每次到单词末尾后的空格或串尾,开始反转单词
if (end == chars.length || chars[end] == ' ') {
reverse(chars, start, end - 1);
start = end + 1;
}
}
}
}
七、左旋字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
示例 2:
输入: s = “lrloseumgh”, k = 6
输出: “umghlrlose”
限制:
1 <= k < s.length <= 10000
思路:
代码:
class Solution{
public String reverseLeftWordss(String s,int n){
int len=s.length();
StringBuilder sb=new StringBuilder(s);
resverseString(sb,0,n-1);
resverseString(sb,n,len-1);
return sb.resverse().toString();
}
public void reverseString(StringBuilder sb,int start,int end){
while(start<end){
char temp=sb.charAt(start);
sb.setCharAt(start,sb.charAt(end));
sb.setCharAt(end,temp);
start++;
end--;
}
}
}
八、KMP算法
kmp算法解决字符匹配的问题,经典例子:
文本串:aabaabaaf
模式串:aabaaf
问文本串中有没有出现过模式串
利用前缀表来找到之前匹配过的内容。
前缀:aabaaf的前缀是:a、aa、aab、aaba、aabaa
后缀:aabaaf的后缀是: f、af、aaf、baaf、abaaf
最长相等前后缀
kmp算法代码:1.初始化 2.前后缀不同的情况 3.前后缀相同的情况 4.更新next数组的值
指针i指向后缀末尾位置,指针j指向前缀末尾的位置(j同时记录了i之前包括i子串的最长相等前后缀长度)
具体代码
private void getNext(int[] next,String s){
int j=0;
next[0]=0;
for(int i=1;i<s.length();i++){
while(j>0&&s.charAt(j)!=s.charAt(i)){
j=next[j-1];
}
if(s.charAt(j)==s.charAt(i)){
j++;
next[i]=j;
}
}
}
九、重复的子字符串
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
示例 1:
输入: “abab”
输出: True
解释: 可由子字符串 “ab” 重复两次构成。
示例 2:
输入: “aba”
输出: False
示例 3:
输入: “abcabcabcabc”
输出: True
解释: 可由子字符串 “abc” 重复四次构成。 (或者子字符串 “abcabc” 重复两次构成。)
思路:用kmp算法,重复子串就是最长相等前后缀不包含的子串就是最小重复子串
代码:
class Solution{
public boolean repeatedSubstringPattern(String s){
if(s.equals("")) return false;
int len=s.length();
//原串加个空格(哨兵),使下标从1开始,这样j从0开始,也不用初始化了
s=" "+s;
char[] chars=s.toCharArray();
int[] next=new int[len+1];
//构造next数组过程,j从0开始(空格),i从2开始
for(int i=2,j=0;i<=len;i++){
//匹配不成功,j回到前一位置next数组所对应的值
while(j>0 && chars[i]!=chars[j+1])j=next[j];
//匹配成功,j往后移
if(chars[i]==chars[j+1])j++;
//更新next数组的值
next[i]=j;
}
//最后判断是否是重复的子字符串,这里next[len]即代表next数组末尾的值
if(next[len]>0&&len%(len-next[len]==0)){
return true;
}
}
return false;
}