✅✅代码随想录算法训练营Day8 | | 344.反转字符串 ,541. 反转字符串II , 剑指Offer 05.替换空格 ,151.翻转字符串里的单词 ,剑指Offer58-II 左旋转字符串
我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第11篇文章 点击查看文章详情 🚀🚀
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情🚀🚀
前言
今天一下子安排了五道题,不仅我吃不消了,文章的标题也吃不消了,这些字都打不上去了。 希望明天卡哥可以手下留情~😨😨😨
344. 反转字符串 - 力扣(LeetCode)
难度:🔥🔥
双指针
var reverseString = function(s) {
let len = s.length;
let l = 0;
let r = len-1;
while(l < r){
[s[l],s[r]] = [s[r],s[l]];
l++;
r--;
}
return s;
};
这里我们要尝试用底层一点的东西去实现,如果仅仅是用reverse这个api的话,直接就完事了,这样做的话百分之百达不到面试官的要求的。
另外一点就是这里用双指针去实现也挺简单的~
541. 反转字符串 II - 力扣(LeetCode)
难度:🔥🔥🔥
双指针
var reverseStr = function(s, k) {
let len = s.length;
let res= s.split('');
for(let i = 0;i < len;i += 2*k){
let l = i-1;
let r = i+k;
r = i+k > len ? len : i+k;
while(++l<--r){
[res[l],res[r]] = [res[r],res[l]];
}
}
return res.join('')
};
难点
前k的处理逻辑
肯定有不少人为了处理逻辑:每隔2k个字符的前k的字符,写了一堆逻辑代码或者再搞一个计数器,来统计2k,再统计前k个字符。
其实在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。
for(let i = 0;i < len;i += 2*k){
}
split和join方法的理解
刚刷的这里的时候,对split和join很懵!!!
-
split: 使用指定的分隔符字符串将一个字符对象分割成子字符串数组,以一个指定的分割字串来决定每个拆分的位置。这是字符串的api
下面是容易弄混的split的结果
let q = 'wearehappy' let arr = q.split(''); let brr = q.split(' ') let crr = q.split() console.log(arr,'arr'); console.log(brr,'brr'); console.log(crr,'crr'); console.log(q,'q');所以我们一般用
split('')将每个字符进行分隔成数组并且
split不会改变原来的字符串 -
join:用于把数组中的所有元素放入一个字符串。
join易混淆的结果
let s = ['a','p','p','l','e']
let res = s.join();
let arr = s.join('')
let brr = s.join(' ')
console.log(res,'res');
console.log(arr,'arr');
console.log(brr,'brr');
console.log(s,'s');
// join('')将数组元素无缝拼接
// join(' ') 将数组元素以空格分割
// join()将数组每个元素都转为字符串,用法等同于toString() 默认以逗号分隔
根据结果,所以我们一般用join('')去实现数组转字符串
并且join()不会改变原来的数组
最后的判断
当遍历到最后一组时,也要符合题目的要求:
- 如果剩余字符少于
k个,则将剩余字符全部反转。 - 如果剩余字符小于
2k但大于或等于k个,则反转前k个字符,其余字符保持原样。
在这里,三目运算符可以很好的进行体现:
let l = i-1;
let r = i+k;
r = i+k > len ? len : i+k;
剑指 Offer 05. 替换空格 - 力扣(LeetCode)
难度:🔥🔥🔥
api解法
let res = s.split(' ');
let newS = res.join('%20');
return newS
正则解法
return s.replace(/ /g, "%20");
双指针
let len = s.length;
let res = s.split('');
let count = 0;
for(let i = 0; i < len;i++){
if(res[i] == ' ')
count++;
}
let l = len - 1;
let r = len - 1 + count*2;
while(l >= 0){
if(res[l] !== ' '){
res[r--] = res[l--];
}
else{
res[r--] = '0';
res[r--] = '2';
res[r--] = '%';
l--
}
}
return res.join('')
难点
数组不会存在操作空指针的情况
let l = len - 1;
let r = len - 1 + count*2;
这里r已经大于了数组的长度了,但依旧可以继续操作。
151. 反转字符串中的单词 - 力扣(LeetCode)
难度:🔥🔥🔥🔥
api
return s.trim().split(/\s+/).reverse().join(' ');
快慢指针
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--;
}
}
};
这个题,就感觉很难受,只用api嫌弃它太简单了,不用api纯手写出来这些功能,又比较难~😡😡😡
剑指 Offer 58 - II. 左旋转字符串 - 力扣(LeetCode)
难度:🔥🔥🔥
固定搭配
var reverseLeftWords = function(s, n) {
const fn = (res,l,r) => {
while(l < r){
[res[l],res[r]] = [res[r],res[l]];
l++;
r--;
}
}
let len = s.length;
let res = s.split('');
fn(res,0,n-1);
fn(res,n,len-1);
fn(res,0,len-1)
return res.join('')
};
害,这个题的思路也奇奇怪怪,第一次刷一般想不到
难点
实现思路
- 反转区间为前n的子串
- 反转区间为n到末尾的子串
- 反转整个字符串
总结下来就是:
先转左半边
再右半边
最后再一起转
小结
今天刷题的体验不太好,一个是字符串这边固定的题型不多,api也多,就比较乱。然后今天的任务量也比较多,脑子要烧掉了~
- 反转字符串:(今天的主线)
while(l < r){
[s[l],s[r]] = [s[r],s[l]];
l++;
r--;
}
经常利用双指针
l,r进行交换
- 加深了对
split和join的理解
希望明天不要再来五道算法题了 😨😨😨