344.反转字符串
因为字符串也是一种数组,所以元素在内存中是连续分布
题目链接:https://leetcode.cn/problems/reverse-string/
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:输入:["h","e","l","l","o"]输出:["o","l","l","e","h"]
示例 2:输入:["H","a","n","n","a","h"]输出:["h","a","n","n","a","H"]
头尾双指针法
相当于交换数组元素操作
class Solution {
public void reverseString(char[] s) {
int i = 0;
int j = s.length - 1;
while(i < j){
char temp = s[i];//注意是用字符接收
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
}
}
541. 反转字符串II
这个反转要仔细读题
题目链接:https://leetcode.cn/problems/reverse-string-ii/
给定一个字符串 s 和一个整数 k,从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例:
输入: s = "abcdefg", k = 2输出: "bacdfeg"
class Solution {
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
for(int i = 0; i < ch.length; i += 2 * k){
int start = i;
int end = Math.min(ch.length - 1, start + k - 1);//这步的ch.length-1将条件1考虑到了,start+k-1考虑到了第二个条件,相当的巧妙
while(start < end){
char temp = ch[start];
ch[start] = ch[end];
ch[end] = temp;
start++;
end--;
}
}
return new String(ch);
}
}
思路:
首先将字符串转化为字符数组
解题关键:定义首尾指针,这里尾指针很关键
int end = Math.min(ch.length - 1, start + k - 1);//这步的ch.length-1将条件1考虑到了,start+k-1考虑到了第二个条件,相当的巧妙
剑指Offer 05.替换空格
题目链接:https://leetcode.cn/problems/ti-huan-kong-ge-lcof/
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1: 输入:s = "We are happy."输出:"We%20are%20happy."
StringBuilder方法
思路:使用一个新的对象,复制 str,复制的过程对其判断,是空格则替换,否则直接复制,类似于数组复制
class Solution {
public String replaceSpace(String s) {
if(s == null){//不需要判断因为下面循环已经判断了,不满足条件直接就输出了
return null;
}
StringBuilder sb = new StringBuilder();//可变对象
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) == ' '){
sb.append("%20");
}else{
sb.append(s.charAt(i));
}
}
return sb.toString();
}
}
注意:charAt()获取到的是字符,不是字符串
思考:为什么不用这个思路呢:先把字符串根据空格拆分形成字符串数组,之后再遍历字符串数组,遇到空格进行append;
上述步骤出问题在charAt这,因为charAt这取不到字符串数组中的单个字符串,所以上面方法不能成立。
![](https://img-blog.csdnimg.cn/img_convert/1373aebaeffb1e4685297f5be7d732e1.png)
class Solution {
public String replaceSpace(String s) {
if(s == null || s.length() == 0){//要判断s的长度,因为用到了双指针
return s;
}
StringBuilder str = new StringBuilder();
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) == ' '){
str.append(" ");//
}
}
if(str.length() == 0){
return s;
}
//有空格的情况
int left = s.length() - 1;
s += str.toString();
int right = s.length() - 1;
char[] c = s.toCharArray();
while(left >= 0){
if(c[left] != ' '){
c[right] = c[left];
}else{
c[right--] = '0';
c[right--] = '2';
c[right] = '%';
}
left--;
right--;
}
return new String(c);
}
}
官方解答
思路:很好,巧妙运用了new String(array,起始,结束)
class Solution {
public String replaceSpace(String s) {
int len = s.length();
char[] ch = new char[3 * len];
int size = 0;
for(int i = 0; i < len; i++){
if(s.charAt(i) == ' '){
ch[size++] = '%';
ch[size++] = '2';
ch[size++] = '0';
}else{
ch[size++] = s.charAt(i);
}
}
return new String(ch,0,size);
}
}
String newStr = new String(array, 0, size);//其作用是将array函数从0到size由数组变成字符串,左闭右开
151.翻转字符串里的单词
全面考察字符串的操作,重点看 方法二 对之后的代码书写细节会有一个提高
部分细节说明
StringBuilder 中有reverse()方法,并且包含了首位位置,但StringBuilder s = s1.reverse();只能将整体反转,不能指定起始位置
split() 可以引入正则表达式
public void reverse(StringBuilder sb, int left, int right) {
while (left < right) {
char tmp = sb.charAt(left);
//主要是用来替换的,方法里面有两个参数 setCharAt(int index,Char ch)
//第一个参数是取代的位置 索引从0开始 第二个参数是你要替换为的字符串
sb.setCharAt(left++, sb.charAt(right));
sb.setCharAt(right--, tmp);
}
}
题目链接:https://leetcode.cn/problems/reverse-words-in-a-string/
给定一个字符串,逐个翻转字符串中的每个单词。
示例 1:输入: "the sky is blue"输出: "blue is sky the"
示例 2:输入: " hello world! "输出: "world! hello"解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:输入: "a good example"输出: "example good a"解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
用API
class Solution {
public String reverseWords(String s) {
//去除字符串的首位字符
String s1 = s.trim();
//将字符串中的一个或多个空格进行拆分
String[] s2 = s1.split(" +");
StringBuilder s3 = new StringBuilder();
for(int i = s2.length - 1; i >= 0; i--){
s3.append(s2[i] + ' ');
}
return s3.toString().trim();
}
}
方法二
不使用Java内置方法实现
* 1.去除首尾以及中间多余空格
* 2.反转整个字符串
* 3.反转各个单词
官方答案,已经注释的很清晰了
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);
}
//如果为空格 但是sb中最后一个不是空格也加入进去 (这样就将多个空格变成了一个空格)
else if (sb.charAt(sb.length() - 1) != ' ') {
sb.append(c);
}
++left;
}
return sb;
}
//将字符串进行反转 a good example就反转成 elpmaxe doog a
public void reverse(StringBuilder sb, int left, int right) {
while (left < right) {
char tmp = sb.charAt(left);
//主要是用来替换的,方法里面有两个参数 setCharAt(int index,Char ch)
//第一个参数是取代的位置 索引从0开始 第二个参数是你要替换为的字符串
sb.setCharAt(left++, sb.charAt(right));
sb.setCharAt(right--, tmp);
}
}
//这个主要是将elpmaxe doog a 变成 example good a
public void reverseEachWord(StringBuilder sb) {
int n = sb.length();
int start = 0, end = 0;
while (start < n) {
// 循环至单词的末尾
while (end < n && sb.charAt(end) != ' ') {//注意end < n 一定放在前面判断
++end;
}
// 翻转单词
reverse(sb, start, end - 1);//这里调用的是自己的reverse方法,注意是end - 1
// 更新start,去找下一个单词
start = end + 1;
++end;
}
}
}
剑指Offer58-II.左旋转字符串
String 的API substring截取之后,原字符串本身并没有变
题目链接:https://leetcode.cn/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:输入: s = "abcdefg", k = 2输出: "cdefgab"
示例 2:输入: s = "lrloseumgh", k = 6输出: "umghlrlose"
限制:1 <= k < s.length <= 10000
常规拼接方法
方法一
class Solution {
public String reverseLeftWords(String s, int n) {
StringBuilder str = new StringBuilder();
for(int i = n ; i < s.length(); i++){
str.append(s.charAt(i));
}
for(int i = 0; i < n; i++){
str.append(s.charAt(i));
}
return str.toString();
}
}
方法二
class Solution {
public String reverseLeftWords(String s, int n) {
String s1 = s.substring(0,n);
String s2 = s.substring(n);
return s2 + s1;
}
}
先局部反转再 整体反转
先把左面字符串反转,在反转右面,在整体反转,注意:反转的次序不要错
方法一:利用数组进行交换
class Solution {
public String reverseLeftWords(String s, int n) {
char[] c = s.toCharArray();
reverse(c, 0, n - 1);
reverse(c, n, c.length - 1);
reverse(c, 0,c.length - 1);
return new String(c);
}
public void reverse(char[] c, int left, int right){
while(left < right){
char temp = c[left];
c[left] = c[right];
c[right] = temp;
left++;
right--;
}
}
}
方法二
利用字符串进行交换
class Solution {
public String reverseLeftWords(String s, int n) {
StringBuilder str = new StringBuilder(s);
int len = s.length();
reverse(str, 0, n - 1);
reverse(str, n, len - 1);
reverse(str, 0, len - 1);
return str.toString();
}
public void reverse(StringBuilder str, int left, int right){
while(left < right){
char temp = str.charAt(left);
str.setCharAt(left++, str.charAt(right));
str.setCharAt(right--, temp);
}
}
}