「这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战」。
给你一个字符串 s ,根据下述规则反转字符串:
- 所有非英文字母保留在原有位置。
- 所有英文字母(小写或大写)位置反转。
返回反转后的 s 。
示例 1:
输入:s = "ab-cd"
输出:"dc-ba"
示例 2:
输入:s = "a-bC-dEf-ghIj"
输出:"j-Ih-gfE-dCba"
示例 3:
输入:s = "Test1ng-Leet=code-Q!"
输出:"Qedo1ct-eeLg=ntse-T!"
提示
1 <= s.length <= 100s仅由 ASCII 值在范围[33, 122]的字符组成s不含'\"'或'\\'
HashMap
由于非字母需要保留在原地,所以我们需要先找到非字母的字符,以及该字符所在的位置,并将其记录下来,然后将所有字母字符入队。
之后,我们需要出队字母字符,并判断当前位置是否应为非字母字符
- 当前位置是非字母字符,取出非字母字符,放入新数组中
- 如果当前位置是字母字符,出队字母字符
- 直至字母队为空,非字母哈希为空结束。
var reverseOnlyLetters = function (s) {
const len = s.length
const map = new Map()
const arr = []
const res = []
for (let i = 0; i < len; i++) {
if ((/^[a-zA-Z]+$/.test(s[i]))) arr.unshift(s[i])
else map.set(i, s[i])
}
while (map.size != 0 || arr.length != 0) {
if (map.has(res.length)) {
res.push(map.get(res.length))
map.delete(res.length - 1)
}
else if (arr.length != 0) res.push(arr.shift())
}
return res.join("");
};
双指针
我们使用 指针从左边开始扫描字符串 s, 指针从右边开始扫描字符串 s。如果两个指针都扫描到字母,且 ,那么交换 和 ,然后继续进行扫描;否则表明反转过程结束,返回处理后的字符串。
var reverseOnlyLetters = function(s) {
const n = s.length;
const arr = [...s];
let left = 0, right = n - 1;
while (true) {
while (left < right && !(/^[a-zA-Z]+$/.test(s[left]))) { // 判断左边是否扫描到字母
left++;
}
while (right > left && !(/^[a-zA-Z]+$/.test(s[right]))) { // 判断右边是否扫描到字母
right--;
}
if (left >= right) {
break;
}
swap(arr, left, right);
left++;
right--;
}
return arr.join('');
};
const swap = (arr, left, right) => {
const temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}