From 1d8c16c31bfc1f8562b8e4b700c6de727e362105 Mon Sep 17 00:00:00 2001 From: LouisFonda Date: Sat, 29 Mar 2025 10:30:38 +0800 Subject: [PATCH] feat: leetcode 6,12,15,58,151 --- .../numbers-and-strings/12整数转罗马数字.js | 31 ++++++ .../numbers-and-strings/14字符串公共前缀.js | 101 ++++++++++++++++++ .../151反转字符串中的单词.js | 76 +++++++++++++ .../58最后一个单词的长度.js | 42 ++++++++ .../numbers-and-strings/6z字形变换.js | 51 +++++++++ 5 files changed, 301 insertions(+) create mode 100644 top-interview-leetcode150/numbers-and-strings/12整数转罗马数字.js create mode 100644 top-interview-leetcode150/numbers-and-strings/14字符串公共前缀.js create mode 100644 top-interview-leetcode150/numbers-and-strings/151反转字符串中的单词.js create mode 100644 top-interview-leetcode150/numbers-and-strings/58最后一个单词的长度.js create mode 100644 top-interview-leetcode150/numbers-and-strings/6z字形变换.js diff --git a/top-interview-leetcode150/numbers-and-strings/12整数转罗马数字.js b/top-interview-leetcode150/numbers-and-strings/12整数转罗马数字.js new file mode 100644 index 0000000..9baf2a8 --- /dev/null +++ b/top-interview-leetcode150/numbers-and-strings/12整数转罗马数字.js @@ -0,0 +1,31 @@ +/** + * https://leetcode.cn/problems/integer-to-roman/?envType=study-plan-v2&envId=top-interview-150 + * @param {number} num + * @return {string} + */ +const intToRoman = function (num) { + f1(num); +}; + +const romanMap = [ + ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'], // 个位 + ['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'], // 十位 + ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'], // 百位 + ['', 'M', 'MM', 'MMM'], // 千位 +]; + +/* +把每一个数位上的数字映射成罗马数字,最后拼接即可 +*/ +function f1(num) { + let result = ''; + let place = 0; + + while (num > 0) { + result = romanMap[place][num % 10] + result; // 处理当前位的罗马数字 + num = Math.floor(num / 10); // 去除当前位 + place++; // 处理下一个更高的位 + } + + return result; +} diff --git a/top-interview-leetcode150/numbers-and-strings/14字符串公共前缀.js b/top-interview-leetcode150/numbers-and-strings/14字符串公共前缀.js new file mode 100644 index 0000000..74d3797 --- /dev/null +++ b/top-interview-leetcode150/numbers-and-strings/14字符串公共前缀.js @@ -0,0 +1,101 @@ +/** + * https://leetcode.cn/problems/longest-common-prefix/?envType=study-plan-v2&envId=top-interview-150 + * @param {string[]} strs + * @return {string} + */ +const longestCommonPrefix = function (strs) { + +}; + +/* +如果字符串数组长度为0直接返回"",如果长度不为0则以字符数组中的第一个字符为公共前缀来比较,遍历整个字符数组,如果当前遍历到的字符 +串包含整个公共前缀(第一个字符串),如果不包含,就去掉当前公共前缀的末尾字符,继续比较,如果在比较的过程中发现公共前缀已经变成了 +空字符就直接返回 +*/ + +function f1(strs) { + if (strs.length === 0) return ''; + let prefix = strs[0]; // 以字符数组中的第一个字符作为公共前缀 + for (let i = 1; i < strs.length; i++) { + while (strs[i].indexOf(prefix) !== 0) { // 如果当前字符不包含公共前缀,说明公共前缀长了,要缩短 + prefix = prefix.substring(0, prefix.length - 1); // 缩短前缀 + if (prefix === '') return ''; // 没有公共前缀直接返回 + } + } + return prefix; +} + +/* +思路和上面的一致,先比较公共前缀的第一个字符,如果字符串数组的所有字符串都满足就比较公共前缀的第二个字符,如果发现比较的字符串 +长度不够,或者当前字符不一致,直接返回公共前缀 +*/ +function f2(strs) { + if (strs.length === 0) return ''; + + for (let i = 0; i < strs[0].length; i++) { + const char = strs[0][i]; // 获取第一个字符串的当前字符 + for (let j = 1; j < strs.length; j++) { + // 如果当前字符与其他字符串的对应位置字符不一致,返回当前公共前缀 + if (i >= strs[j].length || strs[j][i] !== char) { + return strs[0].slice(0, i); + } + } + } + + return strs[0]; // 如果循环结束,没有不匹配的,说明整个第一个字符串都是公共前缀 +} + +function f3(strs) { + if (strs.length === 0) return ''; + + let prefix = strs[0]; // 以第一个字符串作为初始公共前缀 + + for (let i = 1; i < strs.length; i++) { + let j = 0; + // 逐个字符比较当前公共前缀和下一个字符串 + while (j < prefix.length && j < strs[i].length && prefix[j] === strs[i][j]) { + j++; + } + // 更新公共前缀为当前找到的前缀 + prefix = prefix.slice(0, j); + + // 如果公共前缀为空,直接返回 + if (prefix === '') return ''; + } + + return prefix; // 返回最终的公共前缀 +} + +// 二分法代码 +// TODO +function f4(strs) { + if (strs.length === 0) return ''; // 如果数组为空,直接返回空字符串 + + // 定义一个递归函数,用于计算区间 [start, end] 的最长公共前缀 + function lcp(start, end) { + if (start === end) { + return strs[start]; // 如果区间只包含一个字符串,直接返回 + } + + // 计算中点,分成两半 + const mid = Math.floor((start + end) / 2); + + // 递归计算左右两部分的公共前缀 + const lcpLeft = lcp(start, mid); + const lcpRight = lcp(mid + 1, end); + + // 计算公共前缀的长度 + const minLength = Math.min(lcpLeft.length, lcpRight.length); + + // 比较两个公共前缀,找到它们的最长公共前缀 + for (let i = 0; i < minLength; i++) { + if (lcpLeft[i] !== lcpRight[i]) { + return lcpLeft.slice(0, i); // 返回公共前缀 + } + } + + return lcpLeft.slice(0, minLength); // 返回较短的前缀 + } + + return lcp(0, strs.length - 1); // 对整个字符串数组进行递归处理 +} diff --git a/top-interview-leetcode150/numbers-and-strings/151反转字符串中的单词.js b/top-interview-leetcode150/numbers-and-strings/151反转字符串中的单词.js new file mode 100644 index 0000000..a3f132a --- /dev/null +++ b/top-interview-leetcode150/numbers-and-strings/151反转字符串中的单词.js @@ -0,0 +1,76 @@ +/** + * https://leetcode.cn/problems/reverse-words-in-a-string/?envType=study-plan-v2&envId=top-interview-150 + * @param {string} s + * @return {string} + */ +const reverseWords = function (s) { + return f1(s); +}; + +function f1(s) { + // 去除首尾空格并初始化一个空数组来收集单词 + const words = []; + let currentWord = ''; + + // 遍历字符串 + for (let i = 0; i < s.length; i++) { + const char = s[i]; + + if (char !== ' ') { + // 当前字符不是空格,拼接到currentWord + currentWord += char; + } else if (currentWord !== '') { + // 当前字符是空格,且currentWord非空,说明找到一个单词,push到words数组 + words.push(currentWord); + currentWord = ''; // 重置currentWord + } + } + + // 如果最后一个字符不是空格,可能会有一个单词没有被加进去 + if (currentWord !== '') { + words.push(currentWord); + } + + // 反转单词数组并用单空格连接返回 + return words.reverse().join(' '); +} + +/* +技巧项的方式,直接用正则匹配空格字符分割成想的单词字符串数组,之后反转数组再拼 +*/ +function f2(s) { + const reverseWords = function (s) { + // 去除多余的空格并按空格分割为单词 + const words = s.trim().split(/\s+/); // 使用正则去掉多余空格 + + // 反转单词数组并用单空格连接 + return words.reverse().join(' '); + }; +} + +/* +利用栈,首先对字符串s做trim处理,之后遍历整个字符串,如果当前字符不等于" "直接压入栈中,如果当前字符是" "检查栈顶元素是否是 +" ",如果栈顶元素是空就跳过,否则就压入栈中 +*/ +function f3(s) { + const stack = []; // js的数组由栈的特性,直接使用即可 + let isPrevSpace = true; // 标记栈顶元素,js数组没有提供peek方法 + s = s.trim(); + for (let i = 0; i < s.length; i++) { + if (s[i] !== ' ') { + stack.push(s[i]); + isPrevSpace = false; + } else if (!isPrevSpace) { + stack.push(s[i]); + isPrevSpace = true; + } + } + + // 最后通过栈弹出并拼接成结果, + // return stack.reverse().join(''); + let res = ''; + while (stack.length >= 0) { + res += stack.pop(); + } + return res; +} diff --git a/top-interview-leetcode150/numbers-and-strings/58最后一个单词的长度.js b/top-interview-leetcode150/numbers-and-strings/58最后一个单词的长度.js new file mode 100644 index 0000000..830d6d0 --- /dev/null +++ b/top-interview-leetcode150/numbers-and-strings/58最后一个单词的长度.js @@ -0,0 +1,42 @@ +/** + * https://leetcode.cn/problems/length-of-last-word/?envType=study-plan-v2&envId=top-interview-150 + * @param {string} s + * @return {number} + */ +const lengthOfLastWord = function (s) { + return f1(s); +}; + +/* +使用trim对字符做前后空格处理,之后使用split(" ")分割,最后返回split(" ")[s.length = 1].length +*/ +function f1(s) { + // 去除首尾空格,并按空格分割字符串 + const words = s.trim().split(' '); + + // 返回最后一个单词的长度 + return words[words.length - 1].length; +} + +/* +方法2,从后往前遍历,按照题目的要求所给的测试用例至少会包含一个单词,直接从和往前遍历,先去除末尾空格,如果是空格就跳过 +直到遇到不是空格的情况,之后再遍历这个末尾单词,如果不是空格就在统计的长度上加1,直到遇到这个单词前面的空格,结束循环,表示 +单词统计完成 +*/ + +function f2(s) { + let len = 0; // 统计末尾单词长度 + let i = s.length - 1; // 有效字符的位置 + + // 去除末尾空格 + while (i >= 0 && s[i] === ' ') { + i--; + } + + // 统计末尾字符长度 + while (i >= 0 && s[i] !== ' ') { + len++; + i--; + } + return len; +} diff --git a/top-interview-leetcode150/numbers-and-strings/6z字形变换.js b/top-interview-leetcode150/numbers-and-strings/6z字形变换.js new file mode 100644 index 0000000..1e2a0bc --- /dev/null +++ b/top-interview-leetcode150/numbers-and-strings/6z字形变换.js @@ -0,0 +1,51 @@ +/** + * https://leetcode.cn/problems/zigzag-conversion/?envType=study-plan-v2&envId=top-interview-150 + * @param {string} s + * @param {number} numRows + * @return {string} + */ +const convert = function (s, numRows) { + +}; + +/* +思路:2. 设计抽象模型 +建立一个 rows 数组,长度为 numRows,用于存储每一行的字符。 + +使用变量 index 记录当前行号。 + +使用变量 direction 记录移动方向(向下 +1,向上 -1): + +初始 direction = 1(向下) + +到达最后一行时,direction = -1(向上) + +到达第一行时,direction = 1(向下) + +遍历字符串 s,依次将字符添加到 rows[index],并更新 index。 + +最后合并 rows 数组,得到最终的字符串。 +*/ +function f1(s, numRows) { + if (numRows === 1 || numRows >= s.length) return s; + + const rows = Array.from({ length: numRows }, () => []); + let index = 0; let + direction = 1; + + for (const char of s) { + rows[index].push(char); + if (index === 0) direction = 1; + if (index === numRows - 1) direction = -1; + index += direction; + } + + return rows.flat().join(''); +} + +/* +周期的方式编写 +*/ +function f2(s, numRows) { + +}