344.反转字符串
题目链接:344. 反转字符串 - 力扣(LeetCode)
第一想法
直接再来一个数组然后遍历赋值,但是题目说了,不要给另外的数组分配额外的空间
所以,这里用双指针法比较合适
思路
双指针法对其进行交换
var reverseString = function(s) {
let len = parseInt(s.length/2);
for(let i = 0,j = s.length - 1;i < len; i++,j--){
let temp = s[i];
s[i] = s[j];
s[j] = temp;
}
return s;
};
总结
JS中有直接反转数组元素的方法:
.reverse()
不过平时做题目多练练基本功,还是少用
541. 反转字符串II
题目链接:541. 反转字符串 II - 力扣(LeetCode)
第一想法
把字符串按k个进行分组,奇数组反转,偶数组不变
对最后一组的数量做一个判断,分情况对其进行反转
思路
当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章。
在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间
JS代码如下:
var reverseStr = function(s, k) {
let len = s.length;
let arr = s.split('');
for(let i = 0; i < len; i += 2*k){
if((i+k) < len){
let l = i-1, r = i + k ;
while(++l < --r){
[arr[l],arr[r]] = [arr[r],arr[l]];
}
}else{
let l = i-1, r = len ;
while(++l< --r){
[arr[l],arr[r]] = [arr[r],arr[l]];
}
}
}
return arr.join('');
};
-
注意自增自减!
一开始写的是:
let l = i, r = i ; while(l++ < r--){ [arr[l],arr[r]] = [arr[r],arr[l]]; }因为是l++,下面arr[l]中,l已经出现一次了,此时,l变成i+1
被改变的值不是想改变的值
总结
这个思路很重要,一开始想的是分割成一段一段再单独处理,但是
可以想想直接在for循环的表达式上做做文章
这样就可以简单很多
另外,代码的if 和 else 的主体代码比较相似,因此可以合并到一起
代码如下:
for(let i = 0; i < len; i += 2 * k) { // 每隔 2k 个字符的前 k 个字符进行反转 let l = i - 1, r = i + k > len ? len : i + k; while(++l < --r) [resArr[l], resArr[r]] = [resArr[r], resArr[l]]; }对r做一个逻辑判断即可
剑指Offer 05.替换空格
题目链接:剑指 Offer 05. 替换空格 - 力扣(LeetCode)
第一想法
遍历字符串,遇到空格,就将空格替换成'%'
问题:
没办法判断当前元素是否等于空格
思路
双指针法
先补上需要的空间,一个指针指向原本的数组的尾部,一个指针指向扩充空间后的数组的尾部
从后向前移动指针,碰到空格则添加20%
为什么是从后向前移动指针:
因为添加的空间在数组的后面,如果是从前往后,则添加20%时需要移动剩下的全部元素,复杂度比较高
JS代码如下:
var replaceSpace = function(s) {
if(s == ''){
return s;
}
const strArr = Array.from(s);
let count = 0;
// 计算空格数量
for(let i = 0; i < strArr.length; i++) {
if (strArr[i] === ' ') {
count++;
}
}
let left = strArr.length - 1;
let right = strArr.length + count * 2 - 1;
while(left >= 0) {
if (strArr[left] === ' ') {
strArr[right--] = '0';
strArr[right--] = '2';
strArr[right--] = '%';
left--;
} else {
strArr[right--] = strArr[left--];
}
}
// 数组转字符串
return strArr.join('');
};
- 转化为数组可以直接用Array.from
- 用count计算空格数量
- 可以不用考虑数组的扩充,因为可以制造空洞,比如:添加
arr[0],然后添加arr[1000],这样数组的大小变成了1000,不过他们中间什么也没有
总结
字符串的双指针解法需要好好的记一下
另外,这一题也可以用JS自带的API
var replaceSpace = function(s) {
return s.replaceAll(' ', '%20');
};
151.翻转字符串里的单词
题目链接:151. 反转字符串中的单词 - 力扣(LeetCode)
第一想法
字符串转换为数组然后用双指针
具体细节没有想到
思路
主要可以分为3步:
-
将整个字符串翻转过来
-
移除多余空格
- 移除前面的空格
- 移除之间的空格
- 移除最后面的空格
-
将单个单词翻转
JS代码如下:
var reverseWords = function(s) {
let arr = s.split('');
arr = arr.reverse();
// 移除空格
removespaces(arr);
// 反转单词
let start = 0;
for(let i = 0; i <= arr.length; i++){
if(arr[i] == ' ' || i == arr.length){
reverse(arr, start, i-1);
start = i + 1;
}
}
return arr.join('');
};
function removespaces(arr){
// 移除前面的空格
let slow = 0, fast = 0;
while(fast < arr.length){
if(arr[fast] == ' ' && (fast == 0 || arr[fast - 1] == ' ')){
fast++;
}else{
arr[slow++] = arr[fast++];
}
}
arr.length = arr[slow - 1] == ' ' ? slow - 1 : slow;
}
function reverse(arr, a, b){
let l = a, r = b;
while(l < r){
[arr[l],arr[r]] = [arr[r],arr[l]];
l++;
r--;
}
}
移除空格和单个单词的翻转可以写成函数形式
总结
这一题感觉掌握的不是很好,最后写的时候还是需要一边看答案一边写才行
需要自己再去写一遍!
剑指Offer58-II.左旋转字符串
题目链接:剑指 Offer 58 - II. 左旋转字符串 - 力扣(LeetCode)
第一想法
暴力解法,把前k个放在一个新数组,把原数组删掉前k个,再把新数组拼接上去,这样复杂度太高了
或者建立一个新数组,然后双指针法,代码如下:
var reverseLeftWords = function(s, n) {
let arr = s.split('');
let len = arr.length;
let arr1 = new Array(len).fill(0);
let i = n, j = 0,k = 0;
while(i < len){
arr1[j++] = arr[i++]
}
while(j < len){
arr1[j++] = arr[k++]
}
s = arr1.join('');
return s;
};
思路
这一题提升一下难度,不使用额外空间,直接在本字符串上进行操作
这样就比较难了
方法步骤如下:
- 反转前n个区间的子串
- 反转剩下的子串
- 把整个字符串反转
JS代码如下:
var reverseLeftWords = function(s, n) {
let arr = s.split('');
reverse(arr,0,n-1);
reverse(arr,n,arr.length-1);
reverse(arr,0,arr.length-1);
s = arr.join('');
return s;
};
function reverse(arr,start,end){
let l = start, r = end;
while(l < r){
[arr[l],arr[r]] = [arr[r],arr[l]];
l++;
r--;
}
}
总结
对一个数组指定区间进行反转这个是固定的操作
可以总结出自己的一个函数来
function reverse(arr,start,end){
let l = start, r = end;
while(l < r){
[arr[l],arr[r]] = [arr[r],arr[l]];
l++;
r--;
}