【力扣刷题】917. 仅仅反转字母

406 阅读1分钟

「这是我参与11月更文挑战的第 11 天,活动详情查看:2021最后一次更文挑战

原题链接

917. 仅仅反转字母 - 力扣(LeetCode) (leetcode-cn.com)

题目描述

给定一个字符串 S,返回 “反转后的” 字符串,其中不是字母的字符都保留在原地,而所有字母的位置发生反转。

测试用例

示例 1:

输入:"ab-cd"
输出:"dc-ba"

示例 2:

输入:"a-bC-dEf-ghIj"
输出:"j-Ih-gfE-dCba"

示例 3:

输入:"Test1ng-Leet=code-Q!"
输出:"Qedo1ct-eeLg=ntse-T!"

参数限制

  1. S.length <= 100
  2. 33 <= S[i].ASCIIcode <= 122 
  3. S 中不包含 `` or "

分析

对于这种在原数组上直接做替换的操作,直接双指针安排

pl 从 0 开始往右移,找到字母后停止;pr 往左移,找到字母后停止;然后交换 pl, pr 指针对应的字母,然后重复上述步骤,直到 pl>pr 终止循环操作。这个时候返回的字符串就是答案

至于如何判断当前指向的元素是否为字符,直接使用正则表达式 /[a-zA-Z]/ 来匹配即可

代码

var reverseOnlyLetters = function(s) {
  s = s.split('')
  let l = 0,
    r = s.length - 1;
  let reg = /[a-zA-Z]/
  for (;;) {
    while (!reg.test(s[l])) {
      l++;
    }
    while (!reg.test(s[r])) {
      r--;
    }
    if (l >= r) break;
    let c = s[l];
    s[l++] = s[r];
    s[r--] = c;
  }
  return s.join('')
};

虽然是 for 嵌套 while 的风格,但实际上也只是遍历了一次数组,仅仅是阅读起来会有点吃力

image.png

优化

由于字符串的比较是使用的正则,担心这里面会有一些性能的损耗,我们直接替换为 ascll码 的比较

控制台查阅资料可以知道 [a, z] = [97, 122], [A, Z] = [65, 90]

同时优化一下 for 中嵌套 while 的风格

var reverseOnlyLetters = function(s) {
    s = s.split('')
    let l = 0,
        r = s.length - 1;
    for (; l < r;) {
        if (!check(s[l])) {
            l++;
            continue;
        }
        if (!check(s[r])) {
            r--;
            continue;
        }
        let c = s[l];
        s[l++] = s[r];
        s[r--] = c;
    }
    return s.join('');

    function check(s) {
        let c = s.charCodeAt();
        return (c >= 65 && c <= 90) || (c >= 97 && c <= 122);
    }
};

image.png


今天的力扣刷题就分享到这里,感谢大家的阅读~