344.反转字符串
建议: 本题是字符串基础题目,就是考察 reverse 函数的实现,同时也明确一下 平时刷题什么时候用 库函数,什么时候 不用库函数
题目
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]
答案
/**
* @param {character[]} s
* @return {void} Do not return anything, modify s in-place instead.
*/
var reverseString = function(s) {
let l = 0, r = s.length -1;
while(l < r) {
const temp = s[l];
s[l] = s[r];
s[r] = temp;
l++; r--;
}
return s;
};
541. 反转字符串II
建议:本题又进阶了,自己先去独立做一做,然后在看题解,对代码技巧会有很深的体会。
题目
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
输入:s = "abcdefg", k = 2
输出:"bacdfeg"
思路
一开始想复杂了,绞尽脑汁地想怎么把长字符串划分成2k,看了讲解才想到只要遍历字符串,每次 + 2k
就可以了。
答案
很麻烦的解法
/**
* @param {string} s
* @param {number} k
* @return {string}
*/
var reverseStr = function(s, k) {
const reverse = function(l, r) {
while(l < r) {
const temp = arr[l];
arr[l] = arr[r], arr[r] = temp;
l++; r--;
}
}
let count = Math.floor(s.length / (2 * k)), i = 0;
const arr = Array.from(s);
if(s.length <= k) {
reverse(0, s.length - 1);
return arr.join('');
}
while(count--) {
// 反转
let l = 2*k*i, r = 2*k*i + k - 1;
reverse(l, r);
i++;
}
const left = s.length % (2 * k);
console.log(left, 2*k*i, s.length)
if(left <= k) reverse(2*k*i, s.length - 1)
if(k < left && left < 2 * k) reverse(2*k*i, 2*k*i + k - 1);
return arr.join('');
};
简洁的写法
/**
* @param {string} s
* @param {number} k
* @return {string}
*/
var reverseStr = function(s, k) {
const arr = s.split('');
const len = arr.length;
for(let i = 0; i < len; i+=2*k) {
let l = i-1, r = i+k > len ?len : i+k;
while(++l < --r) [arr[l], arr[r]] = [arr[r], arr[l]];
}
return arr.join('');
};
剑指Offer 05.替换空格
建议:对于线性数据结构,填充或者删除,后序处理会高效的多。好好体会一下。
题目链接
题目
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1: 输入:s = "We are happy."
输出:"We%20are%20happy."
思路
用双指针,左边的指针指向字符串的最后一个位置,右边的指针指向扩充后的数组的最后一个位置,从后往前进行遍历。
答案
/**
* @param {string} s
* @return {string}
*/
var replaceSpace = function(s) {
const res = s.split('');
let count = 0;
// 找到有多少个空格
for(item of res) {
if (item === ' ') count++;
}
let l = res.length -1, r = l + count * 2;
while(l >= 0) {
if(res[l] === ' ') {
res[r--] = '0';
res[r--] = '2';
res[r--] = '%';
l--;
} else {
res[r--] = res[l--];
}
}
return res.join('');
}
151.翻转字符串里的单词
建议:这道题目基本把 刚刚做过的字符串操作 都覆盖了,不过就算知道解题思路,本题代码并不容易写,要多练一练。
题目
给你一个字符串 s ,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
输入:s = "the sky is blue"
输出:"blue is sky the"
思路
自己的解题思路是先将单词放到数组中,然后将单词进行反转。
如果要求空间复杂度是 n(1),就要先将整个字符串反转,再将单词反转。
需要实现两个函数,①去除字符串中多余的空格 @将字符串进行翻转。
答案
/**
* @param {string} s
* @return {string}
*/
var reverseWords = function(s) {
const reverse = function(arr) {
let l = -1, r = arr.length;
while(++l < --r) {
[arr[l], arr[r]] = [arr[r], arr[l]]
}
return arr;
}
// 先放到数组中
let str = '', arr = s.split(''), res = [];
for(let i = 0; i < arr.length; i++) {
if (arr[i] == ' ' && str == ' ') continue;
else if (arr[i] == ' ' && !!str) {res.push(str); str = '';}
else if(arr[i] !== ' ')str += arr[i];
}
if(!!str) res.push(str);
// 反转
res = reverse(res);
return res.join(' ');
};
剑指Offer58-II.左旋转字符串
建议:题解中的解法如果没接触过的话,应该会想不到
题目
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
输入: s = "abcdefg", k = 2
输出: "cdefgab"
知识点-字符串分割
- 用“string.split(分割符)”;
- 用“String.substring(开始位置,结束位置)”;
- 用“String.substr(开始位置,截取长度)”;
- 用“String.slice(开始位置,结束位置)”。
答案
简单粗暴,直接遍历把要转移的字符串放到后面,然后再用字符串分割的函数进行分割。
var reverseLeftWords = function(s, n) {
let i = 0, len = s.length;
while(i < n) {
s += s[i];
i++;
}
return s.substr(n, len);
}
只允许在原字符串上操作的。
先整体反转,再局部反转。
var reverseLeftWords2 = function(s, n) {
const reverse = function(arr, start, end) {
while(start < end) {
[arr[start], arr[end]] = [arr[end], arr[start]];
start++;
end--;
}
}
const arr = s.split(''), len = s.length;
reverse(arr, 0, len - 1);
reverse(arr, 0, len - n -1);
reverse(arr, len - n , len - 1)
return arr.join('');
}