今日题目:
- 344. 反转字符串
- 541. 反转字符串Ⅱ
- 剑指offer 05. 替换空格
- 151. 翻转字符串里的单词
- 剑指offerⅡ. 左旋转字符串
解题思想:
- 双指针反转字符串
344题反转字符串并不难,要求原地反转,只需要头指针和尾指针元素两两交换,指针向内收缩就好了。
541题最难的点可能是读懂题。。。说人话就是每隔k个元素反转一次字符串。在写for
循环的时候,会下意识的i++
来控制变量,但是这样会发现进来逻辑处理起来非常麻烦,最优雅的方式是,遍历过程中每趟i += (2*k)
,然后判断是否有需要反转的区间。
所以当需要固定规律一段一段去处理字符串的时候,要想想在for循环的表达式上做文章。
这道题还需要注意的一个地方是,需要先把字符串通过split("")
分割成字符串数组,才能正常的进行反转,最后通过join("")
将字符串数组变为字符串。
- 从后往前的双指针
05替换空格这道题,要求原地改,代码随想录提供的解题思路是先进行一遍字符串遍历,计算出数组空格个数,扩充数组。然后从后往前的双指针,L在数组原始长度末尾,R在数组扩充长度的末尾,L往前探索,如果不为空则把L所在的值赋给R,如果为空则R倒序赋值%20。
- 反转单词
第151题,思路就是1、移除多余空格,2、反转整个字符串,3、反转每个单词。移除多余空格就利用快慢指针遍历数组,移除多余空格
- 左旋转字符串
这道题要想原地修改的话还是有点难度的(我靠调用库函数做出来了kkk)。跟上一题思路也有点类似:1. 反转区间为签n的子串 2. 反转区间为n到末尾的子串 3.反转整个字符串。思路很妙,没接触过确实比较难想
代码:
- 344 . 反转字符串
var reverseString = function(s) {
let L = 0
let R = s.length-1
while(L<=R) {
let temp = s[L]
s[L] = s[R]
s[R] = temp
L++
R--
}
return s
};
- 541 . 反转字符串Ⅱ
var reverseStr = function(s, k) {
const len = s.length
let resArr = s.split("")
for(let i = 0; i<len; i+= (2*k) ) {
k = i+k>len ? len-i : k
reverseFns(resArr, i, i+k-1)
}
function reverseFns(arr, start, end) {
let L = start
let R = end
while(L <= R) {
let temp = arr[R]
arr[R] = arr[L]
arr[L] = temp
L++
R--
}
}
return resArr.join("")
};
- 剑指offer 05. 替换空格
//自己第一次实现用的是数组的splice方法
var replaceSpace = function(s) {
s=s.split("")
for(let i =0; i<s.length; i++) {
if(s[i] == ' ') {
s.splice(i,1,'%20')
}
}
return s.join("")
};
//代码随想录提供的方法
var replaceSpace = function(s) {
s=s.split("") //字符串转数组
let counter = 0
s.forEach(item => {
if(item === ' ') counter++
})
let L = s.length-1
let R = s.length + counter*2 -1
while(L >= 0) {
if(s[L] === ' ') {
s[R--] = '0'
s[R--] = '2'
s[R--] = '%'
L--
} else {
s[R--] = s[L--]
}
}
return s.join('')
};
- 151 . 翻转字符串里的单词
/**
* @param {string} s
* @return {string}
*/
var reverseWords = function(s) {
s = s.split("")
let L = R = 0
//首先去除所有多余空格
while(R<s.length) {
if(s[R] == ' ' && (L == 0 || s[R-1] == ' ')){
R++
} else {
s[L++] = s[R++]
}
}
// if(s[L-1]== ' ') s = s.slice(0, L-1) 这种做法是错的!因为不管后面的是不是空格,字符串长度都需要重新调整
s.length = s[L-1] === ' '? L-1: L //去除末尾空格
//整体翻转
reverse(0, s.length-1)
//局部单词翻转
let start = 0
for(let i = 0; i<=s.length; i++) {
if(s[i] == ' ' || i == s.length) { //注意这里,还要考虑i探索到队尾的情况,不然最后一个单词会漏转
reverse(start, i-1)
start = i+1
}
}
//通用reverse函数
function reverse(start, end) {
let L = start
let R = end
while(L<=R){
let temp = s[L]
s[L] = s[R]
s[R] = temp
L++
R--
}
}
return s.join("")
};
- 剑指offerⅡ. 左旋转字符串
//我的做法
var reverseLeftWords = function(s, n) {
s=s.split('')
let count = 0
while(count<n) {
let temp = s.shift()
s.push(temp)
count++
}
return s.join('')
};
//代码随想录给的思路
var reverseLeftWords = function(s, n) {
s=s.split('')
reverse(0,n-1)
reverse(n, s.length-1)
reverse(0, s.length-1)
function reverse(start, end) {
let L = start
let R = end
while(L<=R) {
let temp = s[L]
s[L] = s[R]
s[R] = temp
L++
R--
}
}
return s.join('')
};
总结:
今天美团实习一面结束,可以开始追进度啦 不过这周还要把开题报告给解决了…先占个坑等明天补叭
在处理字符串的时候,一般先通过str = str.split('')
把它转为数组形式,再最后return的时候通过str.join('')
转回字符串形式。
这几道题收获还蛮大的,有些思想确实自己做题的话很难想到:对for循环的i变量处理、先局部反转再整体反转的思想…都是值得自己多次熟练练习并掌握的。并且有时候自己太过于依赖库函数的调用,导致时间复杂度上不是很好。practice makes perfect,继续加油吧