【leetcode】字符串
String常用方法
int length() - 返回字符串长度
举个意想不到的例子:String s = "😓", s.length() = ?。
char charAt(int) - 返回字符串中指定索引的字符,索引从0开始
boolean equals(Object) - 判断是否与指定字符串相等
boolean equalsIgnoreCase(String) - 同上,忽略大小写
boolean contentEquals(StringBuffer) - 判断是否与指定StringBuffer相等
int compareTo(String) - 与指定字符串比较,返回Unicode编码的差值,相等时为0
int compareToIgnoreCase(String) - 同上,忽略大小写
boolean startsWith(String, int) - 该串从指定偏移开始,是否以指定字符串为前缀
例如:String s = "abcd", s.startsWith("cd", 2)为true。
boolean startsWith(String) - 是否以指定字符串为前缀
boolean endsWith(String) - 是否以指定字符串为后缀
int indexOf(int) - 返回字符首次出现的索引
int lastIndexOf(int) - 返回字符的最后出现的索引
String substring(int) - 返回当前串从指定位置开始的子串,包括指定位置
s.substring(0) == s为true
String substring(int, int) - 返回当前串从指定位置开始和结束的字串
s.substring(0, s.length()) == s为true, 左闭右开区间[start, end)
String concat(String) - 在当前串后面添加指定串
String replace(char, char) - 将串中的所有指定字符替换为另一个指定字符
String replace(CharSequence, CharSequence) - 将当前串中所有的指定字符序列替换为另一个字符序列
String replaceAll(String, String) - 将当前串中所有的指定字符串替换为另一个字符串
String replaceFirst(String, String) - 将当前串中的首次出现的指定字符串替换为另一个字符串
boolean matches(String) - 判断当前串是否满足给定的正则表达式
boolean contains(CharSequence) - 判断当前串是否包含指定字符序列
String[] split(String) - 以给定正则表达式将当前串分割并返回字符串数组
"axbyc".split("[xy]"), 结果为[a, b, c]
String[] split(String, int) - 以给定正则表达式将当前串分割为指定个字符串,0表示不限制个数
"axbyc".split("[xy]", 2), 结果为[a, byc]
static String join(CharSequence, CharSequence...) - 将给定的字符序列数组用给定的字符序列连接起来,并返回结果
String.join("-", "abc", "def", "xyz"), 结果为"abc-def-xyz"
static String join(CharSequence, Iterable) - 同上,字符序列数组可以换为可迭代类型如List/Set等
String toLowerCase() - 将当前字符串转为全小写
String toUpperCase() - 将当前字符串转为全大写
String trim() - 去掉当前串首尾的空白符
char[] toCharArray() - 将当前字符串转为字符数组,该字符数组是字符串内部的字符数组的一个拷贝
String s = "abc"; char[] arr = s.toCharArray(); arr[0] = 'x';修改字符数组不影响原来的字符串
static String copyValueOf(char[]) - 将字符数组转为字符串
static String copyValueOf(char[], int, int) - 将字符串数组从指定偏移开始的指定长度转为字符串
static String valueOf(int/char/char[]/long/float/double/boolean) - 将基本类型值转为字符串
double d = 0.3f; String.valueOf(d);结果为0.30000001192092896
最长公共前缀
题目 取第一个字符串,从其前缀[0,1)开始到整串,判断其它串是否以此为前缀。
class Solution {
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length == 0) {
return "";
}
if (strs.length == 1) {
return strs[0];
}
for (int j = 1; j < strs[0].length() + 1; j++) { // 遍历第一个字符串的前缀
for (int i = 1; i < strs.length; i++) { // 遍历每个字符串
if (!strs[i].startsWith(strs[0].substring(0, j))) { // 判断每个串是否以[0, j)为前缀
return j == 1 ? "" : strs[0].substring(0, j - 1);
}
}
}
return strs[0];
}
}
最长回文子串
题目 中心扩散法。遍历字符串,判断每个位置上的最长回文子串。
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return "";
}
char[] arr = s.toCharArray();
int start = 0, end = 0; // [start, end]
for (int i = 0; i < s.length() - 1; i++) {
int l1 = longestPalindrome(arr, i, i); // ABA型,奇数
int l2 = longestPalindrome(arr, i, i + 1); // AA型,偶数
int l = Math.max(l1, l2);
if (l > end - start + 1) { // 更新最大值
start = i - (l - 1) / 2;
end = i + l / 2;
}
}
return s.substring(start, end + 1);
}
// 返回最长回文子串的长度
public int longestPalindrome(char[] arr, int left, int right) {
while (left >= 0 && right < arr.length && arr[left] == arr[right]) {
left--;
right++;
}
return right - left - 1;
}
}
翻转字符串里的单词
- api,先分割为数组,数组反转,再组合为字符串。
class Solution {
public String reverseWords(String s) {
if (s == null || s.isEmpty()) {
return "";
}
String[] arr = s.trim().split("\\s+");
int left = 0, right = arr.length - 1;
while (left < right) {
String temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
return String.join(" ", arr);
}
}
- toCharArray之后原地操作。第一步trim;第二步去掉单词之间的多余空格;第三步翻转整个数组;第四步翻转每个单词。
class Solution {
public String reverseWords(String s) {
if (s == null || s.isEmpty()) {
return "";
}
char[] arr = s.toCharArray();
int length = trim(arr);
if (length < 1) {
return "";
}
length = removeRedundantBlank(arr, length);
reverseArray(arr, 0, length - 1);
reverseWord(arr, length);
return String.valueOf(arr, 0, length);
}
// 去掉数组两边的空格
public int trim(char[] arr) {
int preBlank = 0;
for (int i = 0; i < arr.length && arr[i] == ' '; i++) {
preBlank++;
}
int postBlank = 0;
for (int i = arr.length - 1; i >= 0 && arr[i] == ' '; i--) {
postBlank++;
}
for (int i = 0; i < arr.length - postBlank && i + preBlank < arr.length; i++) {
arr[i] = arr[i + preBlank];
}
return arr.length - preBlank - postBlank;
}
// 去除单词之间多余的空格
public int removeRedundantBlank(char[] arr, int length) {
int i = 1;
while (i < length) {
int count = 0;
while (i < length && arr[i - 1] == ' ' && arr[i] == ' ') {
count++;
i++;
}
if (count > 0) {
int j = i;
while (j < length) {
arr[j - count] = arr[j];
arr[j] = ' ';
j++;
}
length -= count;
i--;
}
i++;
}
return length;
}
// 翻转字符数组
public void reverseArray(char[] arr, int left, int right) {
while (left < right) {
char temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}
// 翻转单词 eulb -> blue
public void reverseWord(char[] arr, int length) {
int i = 0;
while (i < length) {
int start = i;
int end = i - 1;
while (i < length && arr[i] != ' ') {
end++;
i++;
}
reverseArray(arr, start, end);
i++;
}
}
}
字符串匹配算法:KMP算法
class Solution {
public int strStr(String haystack, String needle) {
if (haystack == null || needle == null || haystack.length() < needle.length() ) {
return -1;
}
if (needle.length() == 0) {
return 0;
}
return kmp(haystack, needle);
}
public int kmp(String txt, String pat) {
char[] patArr = pat.toCharArray();
int[] next = getNext(patArr);
int i = 0;
int j = 0;
while (i < txt.length() && j < pat.length()) {
if (txt.charAt(i) == patArr[j]) {
i++;
j++;
} else if (next[j] == -1) {
i++;
} else {
j = next[j];
}
}
return j == patArr.length ? i - j : -1;
}
public int[] getNext(char[] pat) {
if (pat.length == 1) {
return new int[]{-1};
}
int[] next = new int[pat.length];
next[0] = -1;
next[1] = 0;
int pos = 2;
int cn = 0;
while (pos < next.length) {
if (pat[pos - 1] == pat[cn]) {
next[pos++] = ++cn;
} else if (cn > 0) {
cn = next[cn];
} else {
next[pos++] = 0;
}
}
return next;
}
}