字符串问题,大家记得模板思路即可,一个类型的题目有很多种。
1. 字符串反转的问题
1.1 反转字符串
题目:LeetCode344:
思路
还是我们常见的双指针问题,
- left字符数组头部指针,right字符数组尾部指针。
- 当left < right,交换元素。
- 当left >= right,反转结束,返回字符数组。
代码
/**
* 双指针反转字符串
* @param s
*/
public static void reverseString(char[] s){
if (s == null || s.length == 0){
return;
}
int n = s.length;
for (int left = 0,right = n - 1; left < right; ++left ,--right){
char tmp = s[left];
s[left] = s[right];
s[right] = tmp;
}
}
1.2 k个一组反转
题目:LeetCode541
思路
反转每个下表从2k的倍数开始,长度为k的子字符串,若该字符串长度不为k,则反转整个字符串,注意判断字符串长度不为k的时候。
代码
public String reverseK(String s, int k){
if (s == null || s.length() == 0){
return s;
}
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 tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
++left;
--right;
}
}
1.3 仅仅反转字母
题目:
思路一
分析题目后我们知道,只将字符串反转其他符号位置不变
方法一
第一次遍历将s中的多有字符存入栈中,然后第二次遍历所有字符串,遇到字符串就从栈顶元素弹出元素替换,遇到其他符号直接拼接。
代码一
/**
* 使用栈
* @param s
* @return
*/
public String reverseOnlyLeeters(String s){
Stack<Character> letters = new Stack<>();
for (char c :s.toCharArray()) {
//c是字符串,则压入
if (Character.isLetter(c)){
letters.push(c);
}
}
StringBuilder ans = new StringBuilder();
for (char c : s.toCharArray()) {
//再次遍历,是字符弹栈,不是直接拼接
if (Character.isLetter(c)) {
ans.append(letters.pop());
}else {
ans.append(c);
}
}
return ans.toString();
}
思路二
方法二双指针
- 左指针首部元素,右指针尾部元素
- 左指针遇到元素交换,右指针遇到元素停止,遇到其他符号移动
代码二
/**
* 双指针
*/
public String reverseOnlyletter2(String s){
if (s == null || s.length() == 0){
return s;
}
StringBuilder ans = new StringBuilder();
int j = s.length() -1;
for (int i = 0; i < s.length(); i++) {
//第i位是字符,与j位置字符交换
if (Character.isLetter(s.charAt(i))){
//是字符停止,不是字符移动
while (!Character.isLetter(s.charAt(j)))
j--;
ans.append(j--);
}else {
//前面不是字符,不用反转
ans.append(s.charAt(i));
}
}
return ans.toString();
}
1.4 反转字符串里的单词
题目:LeetCode151
思路一
使用语言提供的方法来解决
- trim(),去掉头部和尾部空格
- split(),按空格分割成数组
- reverse(),将字符串数组反转,每个元素是一个单词
- join(),将字符串数组拼接成一个字符串
代码一
public String reverseWord1(String s){
if (s == null || s.length() == 0){
return s;
}
//除去开头和末尾空格
s = s.trim();
//除去开头和末尾的空白字符作为分割符分割。"s+"匹配多个空白字符
List<String> wordlist = Arrays.asList(s.split("\\s+"));
Collections.reverse(wordlist);
return String.join(" ",wordlist);
}
思路二
自己实现上面的方法
1. tirmSpaces(),去掉多余的空白字符,包括开头和结尾
2. reverse(),将每个字符反转,
3. reverseWord(),根据空格反转每个单词
代码二
/**
* 手动实现上述功能
*/
public String reverseWords(String s){
StringBuilder sb = tirmSpaces(s);
//反转全部字符串
reverse(sb,0,s.length()-1);
//反转每个单词
reverseWord(sb);
return sb.toString();
}
/**
* 去除开头和末尾空格,以及多余的空格
*/
public StringBuilder tirmSpaces(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 reverseWord(StringBuilder sb){
int n = sb.length();
//start判断单词的首字母,end判断末尾字母
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;
//此时两个指针是重合状态
}
}