当前位置: 首页 > news >正文

字符串-JS

注意,四、替换数字是Node.js环境,笔试经常是这种环境,而不是leetcode,需要注意。

一、基础知识

JavaScript 字符串基础知识梳理

1. 字符串的定义与创建
  • 字面量创建
    let str1 = 'Hello';
    let str2 = "World";
    let str3 = `模板字符串`; // ES6 支持插值:`Hello ${name}`
  • 构造函数创建​(不推荐):
    let str = new String("Hello"); // 返回对象,非原始值
2. 字符串的特性
  • 不可变性:字符串一旦创建,无法直接修改其中的字符。
    let s = "abc";
    s[0] = "d"; // 无效,s 仍为 "abc"
  • 原始类型:但可以调用方法(JS 引擎自动装箱为临时对象)。
3. 常用方法
3.1 查询与访问
  • length:获取长度。
    "abc".length; // 3
  • charAt(index) / [index]:获取指定位置字符。
    "abc".charAt(1); // "b"
    "abc"[1];         // "b"(更简洁)
  • indexOf(substr) / includes(substr):查找子串。
    "abc".indexOf("b");    // 1
    "abc".includes("bc");  // true
3.2 截取与分割
  • slice(start, end):截取子串(支持负数索引)。
    "abcdef".slice(1, 3); // "bc"
    "abcdef".slice(-2);   // "ef"
  • substring(start, end):类似 slice,但不支持负数。
  • split(separator):按分隔符拆分为数组。
    "a,b,c".split(","); // ["a", "b", "c"]
3.3 修改(返回新字符串)​
  • toLowerCase() / toUpperCase():大小写转换。
    "AbC".toLowerCase(); // "abc"
  • trim():去除两端空格。
    "  abc  ".trim(); // "abc"
  • replace(old, new):替换子串(仅替换第一个匹配)。
    "abcabc".replace("a", "x"); // "xbcabc"
  • repeat(count):重复字符串。
    "a".repeat(3); // "aaa"
3.4 正则相关
  • match(regexp):匹配正则表达式。
    "abc123".match(/\d+/); // ["123"]
  • search(regexp):返回匹配的索引。
    "abc123".search(/\d/); // 3
4. 字符串与数组的转换
  • 字符串 → 数组
    "abc".split("");    // ["a", "b", "c"]
    Array.from("abc");  // ["a", "b", "c"](支持 Unicode 代理对)
  • 数组 → 字符串
    ["a", "b", "c"].join(""); // "abc"
5. Unicode 与特殊字符
  • Unicode 表示
    "\u0041"; // "A"
    "😊".length; // 2(代理对占两个码元)
  • 码点操作
    "A".codePointAt(0); // 65
    String.fromCodePoint(65); // "A"
6. 模板字符串(ES6)​
  • 插值表达式
    let name = "Alice";
    `Hello, ${name}!`; // "Hello, Alice!"
  • 多行字符串
    `Line 1Line 2`;
7. 性能注意事项
  • 避免频繁拼接:使用 += 在循环中拼接字符串性能差,推荐用数组 push + join
    // 低效
    let result = "";
    for (let i = 0; i < 1000; i++) result += i;// 高效
    let arr = [];
    for (let i = 0; i < 1000; i++) arr.push(i);
    let result = arr.join("");
8. 实用技巧
  • 反转字符串
    "abc".split("").reverse().join(""); // "cba"
  • 检查前缀/后缀
    "file.txt".endsWith(".txt");   // true
    "https://".startsWith("http"); // true
9. 常见面试题
  1. 实现字符串反转​(需区分 Unicode 安全方式)。
  2. 判断回文字符串
    function isPalindrome(s) {return s === s.split("").reverse().join("");
    }
  3. 统计字符出现次数
    "abcabc".split("a").length - 1; // 2

总结

  • 核心特性:不可变、原始类型、Unicode 支持。
  • 重点方法slicesplitreplacetrim
  • ES6+:模板字符串、includesrepeat
  • 性能:避免循环内拼接,优先使用数组操作。

二、344.反转字符串

344. 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例 1:

输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]

示例 2:

输入:s = ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]

提示:

  • 1 <= s.length <= 105
  • s[i] 都是 ASCII 码表中的可打印字符

方法1.封装swap函数 并传递数组引用 

直接在原地对字符串进行交换,需要注意,下面这种交换函数是错的。

var swap = (a, b) => {let temp; temp = a;a = b;b = temp;return a, b; 
};
  • 错误原因
    1. JavaScript 的函数参数是 ​按值传递​(对于原始类型如 number/string),函数内的 a 和 b 只是局部变量的副本,修改它们不会影响外部变量。
    2. return a, b; 实际上是返回 b(逗号操作符返回最后一个值),且调用方未接收返回值。

正确代码:

/*** @param {character[]} s* @return {void} Do not return anything, modify s in-place instead.*/
var swap = (arr, i, j) => {[arr[i], arr[j]] = [arr[j], arr[i]]; //  修改原数组
};var reverseString = function(s) {for(let i = 0; i < Math.floor(s.length / 2); i++) { //  只需遍历一半swap(s, i, s.length - 1 - i);}return s;
};

方法 2:直接操作数组(推荐)双指针

var reverseString = function(s) {let left = 0, right = s.length - 1;while (left < right) {// 直接交换数组元素[s[left], s[right]] = [s[right], s[left]]; // ✅ 解构赋值left++;right--;}return s;
};
  • 优点:无需额外函数,直接通过索引修改原数组。

方法3:使用JS库函数

本题直接return s.reverse()即可。但显然不是让用这个。

const arr = ["h", "e", "l", "l", "o"];
arr.reverse(); // 原地反转
console.log(arr); // ["o", "l", "l", "e", "h"]

4.拓展

  • 扩展思考:如果是字符串(而非字符数组),需先转为数组再操作:
  • 字符串转数组 s=s.spilt('');
  • 数组转为字符串s= s.join('');

三、541.反转字符2

541. 反转字符串 II

 

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例 1:

输入:s = "abcdefg", k = 2
输出:"bacdfeg"

示例 2:

输入:s = "abcd", k = 2
输出:"bacd"

提示:

  • 1 <= s.length <= 104
  • s 仅由小写英文组成
  • 1 <= k <= 104

思路

这道题目的关键点就是2k个数据是一组,然后对前k个数据进行操作。

题目要求 ​每 2k 个字符为一组,反转其中的前 k 个字符。因此:

  1. i 的初始值为 0(从字符串开头开始)。
  2. 每次循环后,i 跳转到下一个 2k 的起始位置,即 i += 2 * k
    • 例如 k=2 时,2k=4,所以每次处理 4 个字符中的前 2 个:
      • 第一组:i=0(处理 s[0..3] 的前 2 个)
      • 第二组:i=4(处理 s[4..7] 的前 2 个)
      • 依此类推。

如何保证剩余字符正确处理?

关键在于right 的边界控制:

let right = Math.min(i + k - 1, arr.length - 1);
  • i + k - 1:当前组前 k 个字符的最后一个索引。
  • arr.length - 1:防止越界(剩余字符不足 k 时直接取到末尾)。

方法1:双指针法

/*** @param {string} s* @param {number} k* @return {string}*/var reverseStr = function(s, k) {const arr = s.split('');for (let i = 0; i < arr.length; i += 2 * k) {let left = i;let right = Math.min(i + k - 1, arr.length - 1); // 防止越界// 反转前k个字符while (left < right) {[arr[left], arr[right]] = [arr[right], arr[left]];left++;right--;}}return arr.join('');
};

方法2:直接操作字符串(非原地,但更简洁)​

var reverseStr = function(s, k) {let result = '';for (let i = 0; i < s.length; i += 2 * k) {// 反转前k个字符const segment = s.slice(i, i + k).split('').reverse().join('');// 添加剩余字符(不反转)const remaining = s.slice(i + k, i + 2 * k);result += segment + remaining;}return result;
};

无论选择哪种解法关键点还是要想到拆分为2k步进行操作。

四、替换数字

给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。

例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。

对于输入字符串 "a5b",函数应该将其转换为 "anumberb"

输入:一个字符串 s,s 仅包含小写字母和数字字符。

输出:打印一个新的字符串,其中每个数字字符都被替换为了number

样例输入:a1b2c3

样例输出:anumberbnumbercnumber

数据范围:1 <= s.length < 10000。

解决思路

  1. 遍历字符串:检查每个字符是否为数字。
  2. 替换数字
    • 如果字符是数字(0-9),替换为 "number"
    • 否则,保留原字符。
  3. 拼接结果:将处理后的字符拼接成新字符串。

方法 1:正则表达式(最简洁)​

利用 String.prototype.replace() 结合正则表达式全局匹配数字:

function replaceDigits(s) {return s.replace(/\d/g, 'number');
}

解释

  • /\d/g:正则表达式匹配所有数字(\d 等价于 [0-9]),g 表示全局匹配。
  • 'number':替换所有匹配项。

方法 2:遍历字符串(显式逻辑)​

如果不允许用正则表达式,可以手动遍历:

function replaceDigits(s) {let result = '';for (let char of s) {if (char >= '0' && char <= '9') {result += 'number';} else {result += char;}}return result;
}

优化点

  • 使用 for...of 直接遍历字符,避免索引操作。
  • 通过比较字符的 ASCII 值('0' 到 '9')判断是否为数字。

方法 3:数组映射(函数式风格)​

将字符串转为数组后处理:

function replaceDigits(s) {return s.split('').map(char => char >= '0' && char <= '9' ? 'number' : char).join('');
}

适用场景:适合链式操作,但性能略低于直接遍历。

Node.js 环境(常见于笔试系统)​

const readline = require("readline");const rl = readline.createInterface({input: process.stdin,output: process.stdout
})function replaceDigits(s) {let result = '';for (let char of s) {if (char >= '0' && char <= '9') {result += 'number';} else {result += char;}}return result;
}// 监听输入
rl.on('line', (input) => {console.log(replaceDigits(input)); // 输出结果rl.close(); // 关闭输入流
});

说明

  • readline 是 Node.js 内置模块,用于逐行读取输入。
  • rl.on('line') 监听用户输入的一行数据。
  • 替换逻辑与之前相同(正则表达式或遍历均可)。
  • 适用场景:大多数在线编程笔试系统(如牛客、ACM 模式)。

五、151.反转字符串中的单词

给你一个字符串 s ,请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

示例 1:

输入:s = "the sky is blue"
输出:"blue is sky the"

示例 2:

输入:s = "  hello world  "
输出:"world hello"
解释:反转后的字符串中不能存在前导空格和尾随空格。

示例 3:

输入:s = "a good   example"
输出:"example good a"
解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。

提示:

  • 1 <= s.length <= 104
  • s 包含英文大小写字母、数字和空格 ' '
  • s至少存在一个 单词

    进阶:如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 O(1) 额外空间复杂度的 原地 解法。

    方法1:使用栈

    解题思路

    1. 按空格分割字符串s.split(' ') 更简单,无需逐个字符处理。
    2. 过滤空字符串if (word !== '') 避免多余的空格。
    3. 栈的正确使用:先压入所有单词,再依次弹出实现反转。
    4. 结果拼接:用数组 reversed 存储结果,最后 join(' ') 合并。
    /*** @param {string} s* @return {string}*/
    //  用栈进行处理 把每个单词作为一个字符串存在数组里 以空格为区分
    var reverseWords = function(s) {let arr = s.split(' ');let stack = [];// 将非空单词压入栈for (let word of arr) {if (word !== '') {stack.push(word);}}// 从栈中弹出单词(实现反转)let reversed = [];while (stack.length > 0) {reversed.push(stack.pop());}return reversed.join(' ');
    };

     方法2:优化版本(更简洁)​

    如果不需要显式用栈,可以进一步简化:

    var reverseWords = function(s) {return s.split(' ').filter(word => word !== '')  // 过滤空字符串.reverse()                    // 反转单词顺序.join(' ');                   // 合并为字符串
    };

    为什么可以直接用 split(' ') 分割单词?

    在 JavaScript 中,split(' ') 是处理以空格分隔的单词的最直接方法。它的工作原理和注意事项如下:


    1. split(' ') 的核心机制

    • 功能:按空格字符 ' ' 将字符串拆分成数组。
    • 示例
      "the sky is blue".split(' '); 
      // 结果: ["the", "sky", "is", "blue"]
    • 连续空格的处理
      "a   b".split(' '); 
      // 结果: ["a", "", "", "b"](空字符串需过滤)

    2. 为什么能正确分割单词?

    • 英语文本的规则:单词之间通常用单个空格分隔。
    • JavaScript 的自动拆分
      • split(' ') 会严格按空格拆分,无论连续多少个空格。
      • 后续通过 filter 或遍历可清理空字符串。

    3.split(' ') 和 split('') 的区别

    在 JavaScript 中,split() 方法的参数决定了字符串如何被分割。以下是两者的关键区别:


    1. split(' ') —— 按空格分割
    • 功能:将字符串按 ​空格字符 ' ' 拆分成数组,分割点为每个空格。
    • 示例
      "hello world".split(' '); 
      // 结果: ["hello", "world"]
    • 连续空格的处理
      "a   b".split(' '); 
      // 结果: ["a", "", "", "b"](空字符串来自连续空格)
    • 适用场景:拆分句子中的单词(需配合 filter 清理空字符串)。

    2. split('') —— 按字符分割
    • 功能:将字符串拆分为 ​单个字符的数组,包括空格。
    • 示例
      "hello".split(''); 
      // 结果: ["h", "e", "l", "l", "o"]
      "a b".split(''); 
      // 结果: ["a", " ", "b"](空格也被保留为数组元素)
    • 适用场景:需要操作每个字符(如反转字符串、统计字符频率)。

    对比总结

    方法分割依据结果示例(输入 "a b"典型用途
    split(' ')按空格["a", "b"]拆分单词
    split('')按每个字符["a", " ", "b"]操作字符(如反转、统计)

    常见问题

    Q1:如果想忽略连续空格,如何优化 split(' ')

    用正则表达式合并连续空格:

    "a   b".split(/\s+/); 
    // 结果: ["a", "b"](自动忽略多余空格)
    Q2:split('') 能正确处理 Unicode 字符(如表情符号)吗?

    不能。像 "😊" 这样的字符占 2 个码元,直接 split('') 会拆成乱码:

    "😊".split(''); 
    // 结果: ["\ud83d", "\ude0a"](错误拆分)

    正确方法

    Array.from("😊"); 
    // 结果: ["😊"](支持 Unicode)

    代码示例

    场景 1:反转句子中的单词
    function reverseWords(s) {return s.split(' ')          // 按空格拆分.filter(word => word !== '')  // 去空值.reverse()           // 反转单词顺序.join(' ');          // 合并为字符串
    }console.log(reverseWords("hello world")); // "world hello"
    场景 2:反转字符串中的字符
    function reverseString(s) {return s.split('')           // 拆分为字符数组.reverse()           // 反转字符顺序.join('');           // 合并为字符串
    }console.log(reverseString("abc")); // "cba"

    总结

    • split(' '):用于拆分单词(需处理连续空格)。
    • split(''):用于操作单个字符(注意 Unicode 问题)。
    • 关键区别:空格是否作为分割符或保留为数组元素。

    http://www.mrgr.cn/news/97407.html

    相关文章:

  • 项目总结之常问的一些问题
  • uniapp如何接入星火大模型
  • Java面试34-Kafka的零拷贝原理
  • 国产芯片解析:龙讯USB Type-C/DP Transmitter多场景覆盖,定义高速互联新标杆
  • Java面试32-对Spring Cloud的理解
  • LeetCode 热题 100 堆
  • 从零搭建微服务项目Pro(第7-1章——分布式雪花算法)
  • 1. Qt信号与槽
  • C语言跳表(Skip List)算法(附链表与跳表实现源码)
  • 从奖励到最优决策:动作价值函数与价值学习
  • Opencv之dilib库:表情识别
  • 人大金仓数据库dum文件进行备份数据和恢复数据
  • 使用OpenSceneGraph生成3D数据格式文件
  • 某碰瓷国赛美赛,号称第三赛事的数模竞赛
  • HarmonyOS 基础组件和基础布局的介绍
  • LeetCode Hot100 刷题笔记(3)—— 链表
  • spring boot 整合redis
  • MySQL窗口函数学习
  • AI爬虫?爬!
  • [ctfshow web入门] 零基础版题解 目录(持续更新中)