字符串
1.导论
- 1.求字符串的长度记得length()后面的括号。
- 2.Strigbuilder和StringBuffer常用方法要掌握。
- 3.字符串到字符数组的转换
- 4.字符的大小写判断
- 5.KMP算法:详解
求前缀表(本身就是一个字符串匹配过程,记录的是前后缀相同的个数)
不相等回退
相等下标加一
- 26个英文的Ascll码
大写字母【65,90】
小写字符【97,122】
两则相差32
2.编程题
2.1 344.反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
//双指针
class Solution {
public void reverseString(char[] s) {
int left = 0;
int right = s.length-1;
while(left<right){
char t = s[left];
s[left] = s[right];
s[right] = t;
left++;
right--;
}
}
}
2.2 541.反转字符串II
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
1 <= s.length <= 104
s 仅由小写英文组成
1 <= k <= 104
class Solution {
public String reverseStr(String s, int k) {
int n = s.length();
char[] arr = s.toCharArray();
for (int i = 0; i < n; i += 2 * k) {
reverse(arr, i, Math.min(i + k, n) - 1);
}
return new String(arr);
}
//字符串反转
public void reverse(char[] arr, int left, int right) {
while (left < right) {
char temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}
}
//利用StringBuffer的reverse()方法
class Solution {
public String reverseStr(String s, int k) {
StringBuffer res = new StringBuffer();
int length = s.length();
int start = 0;
while (start < length) {
// 找到k处和2k处
StringBuffer temp = new StringBuffer();
// 与length进行判断,如果大于length了,那就将其置为length
int firstK = (start + k > length) ? length : start + k;
int secondK = (start + (2 * k) > length) ? length : start + (2 * k);
//无论start所处位置,至少会反转一次
temp.append(s.substring(start, firstK));
res.append(temp.reverse());
// 如果firstK到secondK之间有元素,这些元素直接放入res里即可。
if (firstK < secondK) { //此时剩余长度一定大于k。
res.append(s.substring(firstK, secondK));
}
start += (2 * k);
}
return res.toString();
}
}
2.3 剑指offer05.替换空格
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
0 <= s 的长度 <= 10000
//使用API
class Solution {
public String replaceSpace(String s) {
return s.replaceAll(" ","%20");
}
}
//不使用API
class Solution {
public String replaceSpace(String s) {
int n = s.length();
char[] array = new char[n*3];
int size = 0;
for(int i=0;i<n;++i){
if(s.charAt(i) == ' '){
array[size++] = '%';
array[size++] = '2';
array[size++] = '0';
}else{
array[size++] = s.charAt(i);
}
}
return new String(array,0,size);
}
}
//进一步优化空间
class Solution {
public String replaceSpace(String s) {
int n = s.length();
int count = 0;
for(int i=0;i<n;++i){
if(s.charAt(i)==' '){
++count;
}
}
char[] array = new char[n+3*count];
int size = 0;
for(int i=0;i<n;++i){
if(s.charAt(i) == ' '){
array[size++] = '%';
array[size++] = '2';
array[size++] = '0';
}else{
array[size++] = s.charAt(i);
}
}
return new String(array,0,size);
}
}
2.4 151.反转字符串里的单词
给你一个字符串 s ,逐个翻转字符串中的所有 单词 。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。
说明:
输入字符串 s 可以在前面、后面或者单词间包含多余的空格。
翻转后单词间应当仅用一个空格分隔。
翻转后的字符串中不应包含额外的空格。
1 <= s.length <= 104
s 包含英文大小写字母、数字和空格 ’ ’
s 中 至少存在一个 单词
//使用API
class Solution {
public String reverseWords(String s) {
String[] str = s.trim().split(" +");
Collections.reverse(Arrays.asList(str));
return String.join(" ",str);
}
}
//不使用API
class Solution {
public String reverseWords(String s) {
StringBuilder sb = trimSpaces(s);
// 翻转字符串
reverse(sb, 0, sb.length() - 1);
// 翻转每个单词
reverseEachWord(sb);
return sb.toString();
}
public StringBuilder trimSpaces(String s) {
int left = 0, right = s.length() - 1;
// 去掉字符串开头的空白字符
while (left <= right && s.charAt(left) == ' ') {
++left;
}
// 去掉字符串末尾的空白字符
while (left <= right && s.charAt(right) == ' ') {
--right;
}
// 将字符串间多余的空白字符去除
StringBuilder sb = new StringBuilder();
while (left <= right) {
char c = s.charAt(left);
if (c != ' ') {
sb.append(c);
} else if (sb.charAt(sb.length() - 1) != ' ') {
sb.append(c);
}
++left;
}
return sb;
}
public void reverse(StringBuilder sb, int left, int right) {
while (left < right) {
char tmp = sb.charAt(left);
sb.setCharAt(left++, sb.charAt(right));
sb.setCharAt(right--, tmp);
}
}
public void reverseEachWord(StringBuilder sb) {
int n = sb.length();
int start = 0, end = 0;
while (start < n) {
// 循环至单词的末尾
while (end < n && sb.charAt(end) != ' ') {
++end;
}
// 翻转单词
reverse(sb, start, end - 1);
// 更新start,去找下一个单词
start = end + 1;
++end;
}
}
}
2.5 58-Ⅰ.翻转单词顺序
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。
无空格字符构成一个单词。
输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
class Solution {
public String reverseWords(String s) {
String[] str = s.trim().split(" ");
StringBuilder sb = new StringBuilder();
for(int i=str.length-1;i>=0;--i){
if(str[i].equals("")){
continue;
}
sb.append(str[i]).append(" ");
}
return sb.toString().trim();
}
}
2.6 58-II.左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
1 <= k < s.length <= 10000
class Solution {
public String reverseLeftWords(String s, int n) {
return s.substring(n)+s.substring(0,n);
}
}
2.7 28.实现strStr()
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。
0 <= haystack.length, needle.length <= 5 * 104
haystack 和 needle 仅由小写英文字符组成
//KMP算法
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length(), m = needle.length();
if (m == 0) {
return 0;
}
int[] pi = new int[m];//前缀表
for (int i = 1, j = 0; i < m; i++) {
while (j > 0 && needle.charAt(i) != needle.charAt(j)) {//前后缀不相同
j = pi[j - 1];//向前回退
}
if (needle.charAt(i) == needle.charAt(j)) {//找到相同前后缀
j++;
}
pi[i] = j;
}
for (int i = 0, j = 0; i < n; i++) {
while (j > 0 && haystack.charAt(i) != needle.charAt(j)) {
j = pi[j - 1];
}
if (haystack.charAt(i) == needle.charAt(j)) {
j++;
}
if (j == m) {
return i - m + 1;
}
}
return -1;
}
}
2.8 709. 转换成小写字母
给你一个字符串 s ,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。
1 <= s.length <= 100
s 由 ASCII 字符集中的可打印字符组成
//使用API
class Solution {
public String toLowerCase(String s) {
return s.toLowerCase();
}
}
//实现API
class Solution {
public String toLowerCase(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (c >= 65 && c <= 90) {
c |= 32;
}
sb.append(c);
}
return sb.toString();
}
}
2.9 5.最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串
1 <= s.length <= 1000
s 仅由数字和英文字母组成
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
// 用来记录最长回文字符串的起始和末尾
int start = 0, end = 0;
for (int i = 0; i < s.length(); ++i) {
// 以i为中心的字符串长度可能为奇数或偶数
int len1 = centerExpansionMethod(s, i, i);
int len2 = centerExpansionMethod(s, i, i + 1);
int maxLen = Math.max(len1, len2);
if (maxLen > end - start) {
start = i - (maxLen - 1) / 2;
end = i + maxLen / 2;
}
}
// substring()方法中是左闭右开,所以end要加1
return s.substring(start, end + 1);
}
// 中心扩展法 返回回文字符串的长度
private int centerExpansionMethod(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
--left;
++right;
}
return (right - left - 2) + 1;
}
}