字符串基础
344.反转字符串
题意:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O ( 1 ) O(1) O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
思路:
- 双指针法
- 记得指针移动
package com.yzu.lee.string;
import org.junit.Test;
/**
* @ClassName: ReverseString
* @Description:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
* 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 $O(1)$ 的额外空间解决这一问题。
* 你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
* @author: Leekuangyew
* @date: 2022/5/19 11:46
*/
public class ReverseString {
public static void reverseString(char[] s) {
//定义双指针
int left = 0;
int right = s.length - 1;
//循环停止条件
while (left < right) {
char temp = s[left];
s[left] = s[right];
s[right] = temp;
left++;
right--;
}
}
public static void main(String[] args) {
char[] chars = {'h', 'e', 'l', 'l', 'o'};
reverseString(chars);
}
}
541. 反转字符串II
题意:给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例:
输入: s = “abcdefg”, k = 2
输出: “bacdfeg”
思路:
- 定义左右两个指针
- 当右指针小于等于s的长度时,对前K个字符串进行反转 而后移动左右指针
- 当右指针大于s的长度时,判断剩余字符与K的关系
package com.yzu.lee.string;
import java.util.logging.Level;
/**
* @ClassName: ReverseStr
* @Description:给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。
* 如果剩余字符少于 k 个,则将剩余字符全部反转。
* 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
* 示例:
* 输入: s = "abcdefg", k = 2
* 输出: "bacdfeg"
* @author: Leekuangyew
* @date: 2022/5/19 11:56
*/
public class ReverseStr {
public static String reverseStr(String s, int k) {
//定义左右两个指针
int left = 0;
int right = 2 * k;
char[] chars = s.toCharArray();
//当右指针小于等于s的长度时,对前K个字符串进行反转 而后移动左右指针
while (right <= s.length()) {
reverseString(chars, left, left + k - 1);
left = right;
right = left + 2 * k;
}
int mid = left + k;
if (mid <= s.length() - 1) {
reverseString(chars, left, mid - 1);
return String.valueOf(chars);
} else {
reverseString(chars, left, s.length() - 1);
return String.valueOf(chars);
}
}
public static void reverseString(char[] s, int left, int right) {
while (left < right) {
char temp = s[left];
s[left] = s[right];
s[right] = temp;
left++;
right--;
}
}
public static void main(String[] args) {
String s = "abcd";
String s1 = reverseStr(s, 3);
System.out.println(s1);
}
}
题目:剑指Offer 05.替换空格
题意:请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1: 输入:s = “We are happy.”
输出:“We%20are%20happy.”
思路:
- 遍历字符串,如果该字符为空格,则替换,否则直接拼接
package com.yzu.lee.string;
import com.sun.crypto.provider.PBEWithMD5AndDESCipher;
/**
* @ClassName: ReplaceSpace
* @Description:请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
* 示例 1: 输入:s = "We are happy."
* 输出:"We%20are%20happy."
* @author: Leekuangyew
* @date: 2022/5/19 12:58
*/
public class ReplaceSpace {
public String replaceSpace(String s) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ' ') {
result.append("%20");
}else {
result.append(s.charAt(i));
}
}
return result.toString();
}
}
151.翻转字符串里的单词
题意:给定一个字符串,逐个翻转字符串中的每个单词。
示例 1:
输入: “the sky is blue”
输出: “blue is sky the”
思路:
-
去除字符串前后和中间的多余空格
- 利用头尾双指针去除前后空格
- 删除中间空格
创建一个新字符串sb,循环遍历字符串,如果该字符不为空格,或者sb的结尾不为空格,则直接拼接遍历的字符串
-
反转字符串
利用split进行分割,然后交换
package com.yzu.lee.string;
import org.junit.Test;
/**
* @ClassName: ReverseWords
* @Description:给定一个字符串,逐个翻转字符串中的每个单词。 示例 1:
* 输入: "the sky is blue"
* 输出: "blue is sky the"
* @author: Leekuangyew
* @date: 2022/5/19 13:30
*/
public class ReverseWords {
public String reverseWords(String s) {
//去除多余空格
StringBuilder sb = removeSpace(s);
//反转字符串
String s1 = reverseString(sb);
return s1;
}
private String reverseString(StringBuilder sb) {
String s = sb.toString();
String[] s1 = s.split(" ");
//
int left = 0;
int right = s1.length - 1;
while (left < right) {
String temp = s1[right];
s1[right] = s1[left];
s1[left] = temp;
left++;
right--;
}
//
StringBuilder result = new StringBuilder();
for (int i = 0; i < s1.length - 1; i++) {
result.append(s1[i] + " ");
}
result.append(s1[s1.length - 1]);
return result.toString();
}
private StringBuilder removeSpace(String s) {
int start = 0;
int end = s.length() - 1;
//删除前后空格
while (s.charAt(start) == ' ') start++;
while (s.charAt(end) == ' ') end--;
//删除中间空格
StringBuilder sb = new StringBuilder();
while (start <= end) {
if (s.charAt(start) != ' ' || sb.charAt(sb.length() - 1) != ' ') {
sb.append(s.charAt(start));
}
start++;
}
return sb;
}
@Test
public void test() {
String s = "the sky is blue";
String s1 = reverseWords(s);
System.out.println(s1);
}
}
题目:剑指Offer58-II.左旋转字符串
题意:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
思路:
- 使用substring进行分割
- 0到n反转,n到最后反转,然后整个反转
package com.yzu.lee.string;
/**
* @ClassName: ReverseLeftWords
* @Description:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。 请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,
* 该函数将返回左旋转两位得到的结果"cdefgab"。
* 示例 1:
* 输入: s = "abcdefg", k = 2
* 输出: "cdefgab"
* @author: Leekuangyew
* @date: 2022/5/19 14:36
*/
public class ReverseLeftWords {
public static String reverseLeftWords(String s, int n) {
int left = 0;
int right = n;
StringBuilder sb = new StringBuilder();
String s1 = s.substring(right, s.length() );
String s2 = s.substring(left, right );
return s1 + s2;
}
public static void main(String[] args) {
String abcdefg = reverseLeftWords("abcdefg", 2);
System.out.println(abcdefg);
}
}
28. 实现 strStr()
题目:实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1: 输入: haystack = “hello”, needle = “ll” 输出: 2
示例 2: 输入: haystack = “aaaaa”, needle = “bba” 输出: -1
说明: 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。
思路:
- KMP算法
- 获得needle字符串的next数组
- 对next数组进行初始化
- 给next数组赋值
如果 s[i] 与 s[j]不相同,也就是遇到 前后缀末尾不相同的情况,就要向前回退。
如果 s[i] 与 s[j ] 相同,那么就同时向后移动i 和j 说明找到了相同的前后缀,同时还要将j(前缀的长度)赋给next[i], 因为next[i]要记录相同前后缀的长度。
- 使用next数组做匹配
- 定义两个下标j 指向模式串起始位置,i指向文本串起始位置。
- 如果 s[i] 与 t[j ] 不相同,j就要从next数组里寻找下一个匹配的位置。
- 如果 s[i] 与 t[j + 1] 相同,那么i 和 j 同时向后移动
- 返回当前在文本串匹配模式串的位置i 减去 模式串的长度+1,就是文本串字符串中出现模式串的第一个位置
package com.yzu.lee.string;
import org.junit.Test;
/**
* @ClassName: StrStr
* @Description:实现 strStr() 函数。
* 给定一个 haystack 字符串和一个 needle 字符串,
* 在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
* 示例 1: 输入: haystack = "hello", needle = "ll" 输出: 2
* 示例 2: 输入: haystack = "aaaaa", needle = "bba" 输出: -1
* @author: Leekuangyew
* @date: 2022/5/19 14:45
*/
public class StrStr {
public int strStr(String haystack, String needle) {
if (needle.length() == 0) return 0;
int[] next = new int[needle.length()];
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.length(); i++) {
while (j > 0 && haystack.charAt(i) != needle.charAt(j)) j = next[j - 1];
if (haystack.charAt(i) == needle.charAt(j)) j++;
if (j == needle.length()) return i - needle.length() + 1;
}
return -1;
}
private void getNext(int[] next, String s) {
//对next数组进行初始化
next[0] = 0;
int j = 0;
//给next数组赋值
for (int i = 1; i < s.length(); i++) {
while (j > 0 && s.charAt(i) != s.charAt(j)) {
j = next[j - 1];
}
if (s.charAt(i) == s.charAt(j)) {
j++;
}
next[i] = j;
}
}
@Test
public void test() {
int i = strStr("mississippi", "issip");
System.out.println(i);
}
}
459.重复的子字符串
题意:给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
示例 1:
输入: “abab”
输出: True
解释: 可由子字符串 “ab” 重复两次构成。
思路:
- KMP算法
- 数组长度减去最长相同前后缀的长度相当于是第一个周期的长度,也就是一个周期的长度,如果这个周期可以被整除,就说明整个数组就是这个周期的循环。
- 如果s.length() % (s.length() - next[next.length - 1]) == 0 并且**next[next.length - 1] > 0**,则说明 (数组长度-最长相等前后缀的长度) 正好可以被 数组的长度整除,说明有该字符串有重复的子字符串。
- next[next.length - 1] > 0这个条件不加,例如“abac”这样的就为true
package com.yzu.lee.string;
/**
* @ClassName: RepeatedSubstringPattern
* @Description:给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。 给定的字符串只含有小写英文字母,并且长度不超过10000。
* 示例 1:
* 输入: "abab"
* 输出: True
* 解释: 可由子字符串 "ab" 重复两次构成。
* @author: Leekuangyew
* @date: 2022/5/19 18:28
*/
public class RepeatedSubstringPattern {
public boolean repeatedSubstringPattern(String s) {
int[] next = new int[s.length()];
int j = 0;
for (int i = 1; i < s.length(); i++) {
while (j > 0 && s.charAt(i) != s.charAt(j)) j = next[j - 1];
if (s.charAt(i) == s.charAt(j)) j++;
next[i] = j;
}
if (s.length() % (s.length() - next[next.length - 1]) == 0 && next[next.length - 1] > 0) {
return true;
} else {
return false;
}
}
}