344.反转字符串
思路: 不使用reverse()函数的话其实就是自己实现一下,不使用另外的数组,直接更改数组反转相当于把位置 i和位置 len -i-1的元素互换
/**
* @param {character[]} s
* @return {void} Do not return anything, modify s in-place instead.
*/
var reverseString = function(s) {
const n = s.length
for(let i= 0;i<n / 2;i++){
[s[i] , s[n -1 -i]] = [ s[n -1 -i], s[i]]
}
return s
};
541. 反转字符串II
思路:把字符串按照2k长度分隔,作为数组元素放入数组,对每个元素进行前k个字符的反转,再拼接
const reverse = (s) => {
const arr = s.split('')
const len = arr.length
for (let i = 0; i < len / 2; i++) {
[arr[i], arr[len - 1 - i]] = [arr[len - 1 - i], arr[i]]
}
return arr.join('')
}
var reverseStr = function (s, k) {
let sArr = []
let i = 0
while (s.length > 2 * i * k) {
sArr.push(s.slice(2 * i * k, 2 * i * k + 2 * k))
i++
}
sArr = sArr.map(item => {
let s1 = reverse(item.slice(0, k))
const s2 = item.slice(k, item.length)
return `${s1}${s2}`
})
return sArr.join('')
};
另一种方法:将整个字符串split成数组,对数组元素的值进行交换
/**
* @param {string} s
* @param {number} k
* @return {string}
*/
var reverseStr = function(s, k) {
const len = s.length;
let resArr = s.split("");
for(let i = 0; i < len; i += 2 * k) { // 每隔 2k 个字符的前 k 个字符进行反转
let l = i - 1
let r = i + k > len ? len : i + k;
while(++l < --r) [resArr[l], resArr[r]] = [resArr[r], resArr[l]];
}
return resArr.join("");
};
卡码网:54.替换数字
思路:使用额外空间的话,创建新数组,遍历原数组(字符串转数组),遇到数字则向新数组push'number',否则push对应的字母,没有难度。
不使用额外空间的话,遍历原数组,获得数字的个数count,改变原数组的大小为size + 5*count,然后通过双指针分别指向原数组的末尾和扩充大小之后的末尾位置
例:
数组
a1b2c3 , arr.length = 6+5*3 = 21 , 设两个指针为p1, p2 ,p1指向 3的位置,也就是index 为5,p2指向index为20,p1,p2向数组头方向移动, 当p1的位置为数字时,p2向前赋值'number', p1位置为字母时,p2位置赋值对应字母
其实很多数组填充类的问题,其做法都是先预先给数组扩容带填充后的大小,然后在从后向前进行操作。 这么做有两个好处:
- 不用申请新数组。
- 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。
151.翻转字符串里的单词
第一反应:split然后reverse
/**
* @param {string} s
* @return {string}
*/
var reverseWords = function(s) {
// 后面的filter是为了去除单纯的空格产生的空数组项
let sArr = s.split(' ').filter(item=>item)
return sArr.reverse().join(' ')
};
不使用额外空间:
- 去掉重复的空格(双指针法, 头尾空格单独判断)
- 翻转整个字符串
- 翻转字符串中的单词(遇到空格了前面的就是单词,或者最后走到了字符串结尾)
/**
* @param {string} s
* @return {string}
*/
var reverseWords = function(s) {
// 字符串转数组
const strArr = Array.from(s);
// 移除多余空格
removeExtraSpaces(strArr);
// 翻转
reverse(strArr, 0, strArr.length - 1);
let start = 0;
for(let i = 0; i <= strArr.length; i++) {
if (strArr[i] === ' ' || i === strArr.length) {
// 翻转单词
reverse(strArr, start, i - 1);
start = i + 1;
}
}
return strArr.join('');
};
// 删除多余空格
function removeExtraSpaces(strArr) {
let slowIndex = 0;
let fastIndex = 0;
while(fastIndex < strArr.length) {
// 移除开始位置和重复的空格
if (strArr[fastIndex] === ' ' && (fastIndex === 0 || strArr[fastIndex - 1] === ' ')) {
fastIndex++;
} else {
strArr[slowIndex++] = strArr[fastIndex++];
}
}
// 移除末尾空格
strArr.length = strArr[slowIndex - 1] === ' ' ? slowIndex - 1 : slowIndex;
}
// 翻转从 start 到 end 的字符
function reverse(strArr, start, end) {
let left = start;
let right = end;
while(left < right) {
// 交换
[strArr[left], strArr[right]] = [strArr[right], strArr[left]];
left++;
right--;
}
}
卡码网:55.右旋转字符串
思路:不使用额外空间的话,整体思路类似于替换上一题
- 整体翻转
- 单独翻转
abcdef ---> fedcba fedcba ---- (fe->ef,dcba->abcd)-->efabcd
单独总结:
替换数字和翻转字符串里的单词两道题,都用到了双指针法,这里双指针法用来在不创建额外空间的情况下,对原数组进行删除元素或替换元素的操作。