- 1. 两数之和">1. 两数之和
- 2. 两数相加">2. 两数相加
- 3. 无重复字符的最长子串">3. 无重复字符的最长子串
- 7. 整数反转">7. 整数反转
- 9. 回文数">9. 回文数
- 13. 罗马数字转整数">13. 罗马数字转整数
- 17. 电话号码的字母组合">17. 电话号码的字母组合
- 20.有效的括号">20.有效的括号
- 21. 合并两个有序链表">21. 合并两个有序链表
89. 格雷编码- 164. 最大间距">164. 最大间距
- 258. 各位相加">258. 各位相加
- 349. 两个数组的交">349. 两个数组的交
- 605. 种花问题">605. 种花问题
- 914. 卡牌分组">914. 卡牌分组
- 1047. 删除字符串中的所有相邻重复项">1047. 删除字符串中的所有相邻重复项
- 1209. 删除字符串中的所有相邻重复项 II">1209. 删除字符串中的所有相邻重复项 II
- 1295. 统计位数为偶数的数字">1295. 统计位数为偶数的数字
- 1313. 解压缩编码列表">1313. 解压缩编码列表
- 1317. 将整数转换为两个无零整数的和">1317. 将整数转换为两个无零整数的和
- 剑指 Offer 11. 旋转数组的最小数字">剑指 Offer 11. 旋转数组的最小数字
刷题不在多,需要举一反三
1. 两数之和
// 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。// 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。/*** @param {number[]} nums* @param {number} target* @return {number[]}*/var twoSum = function (nums, target) {for (let i = 0; i < nums.length; i++) {let result = target - nums[i];if (nums.lastIndexOf(result) !== -1 && nums.lastIndexOf(result) !== i) {return [i, nums.lastIndexOf(result)];}}};var twoSum = function (nums, target) {for (let i = 0; i < nums.length; i++) {let result = nums.lastIndexOf(target - nums[i]);if (result > i) {return [i, result];}}};var twoSum = function (nums, target) {for (let i = 0; i < nums.length - 1; i++) {for (let j = i + 1; j < nums.length; j++) {if (nums[i] + nums[j] === target) {return [i, j];}}}};var twoSum = function (nums, target) {let map = new Map();for (let i = 0; i < nums.length; i++) {let k = target - nums[i];if (map.has(k)) {return [map.get(k), i];}map.set(nums[i], i);}return [];};
2. 两数相加
// 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。// 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。// 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。/*** Definition for singly-linked list.* function ListNode(val) {* this.val = val;* this.next = null;* }*//*** @param {ListNode} l1* @param {ListNode} l2* @return {ListNode}*/var addTwoNumbers = function (l1, l2) {let c = 0;let r = new ListNode();let p = r;let p1 = l1;let p2 = l2;while (p1 || p2 || c) {c += (p1 && p1.val) + (p2 && p2.val);p.next = new ListNode(c % 10);c = parseInt(c / 10);p1 && (p1 = p1.next);p2 && (p2 = p2.next);p = p.next;}return r.next;};
3. 无重复字符的最长子串
// 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。/*** @param {string} s* @return {number}*/// var lengthOfLongestSubstring = function (s) {// let arr = [], max = 0;// for (let i = 0; i < s.length; i++) {// let index = arr.indexOf(s[i]);// if (index !== -1) {// arr.splice(0, index + 1);// }// arr.push(s.charAt(i));// max = Math.max(arr.length, max);// }// return max;// };var lengthOfLongestSubstring = function (s) {let index = 0, max = 0;for (let i = 0, j = 0; j < s.length; j++) {index = s.substring(i, j).indexOf(s[j]);if (index === -1) {max = Math.max(max, j - i + 1);} else {i = i + index + 1;}}return max;};
7. 整数反转
// 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。/*** @param {number} x* @return {number}*/var reverse = function (x) {var result = 0;var sign = Math.sign(x);x = Math.abs(x);while (x != 0) {result = result * 10 + (x % 10);x = (x / 10) | 0;}if (result > 2147483647 || result < -2147483648) {return 0;}return sign * result;};
9. 回文数
// 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。/*** @param {number} x* @return {boolean}*/var isPalindrome = function (x) {return x.toString() === x.toString().split("").reverse().join("");};
13. 罗马数字转整数
// 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。// 字符 数值// I 1// V 5// X 10// L 50// C 100// D 500// M 1000// 例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。// 通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:// I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。// X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。// C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。// 给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。/*** @param {string} s* @return {number}*/var romanToInt = function (s) {const map = {I: 1,V: 5,X: 10,L: 50,C: 100,D: 500,M: 1000,};let req = 0;for (let i = 0; i < s.length; i++) {if (i < s.length && map[s[i]] < map[s[i + 1]]) {req -= map[s[i]];} else {req += map[s[i]];}}return req;};
17. 电话号码的字母组合
// 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。// 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。/*** @param {string} digits* @return {string[]}*/var letterCombinations = function (digits) {if (digits.length <= 0) return [];let map = ["", 1, "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"];let num = digits.split("");let code = [];num.forEach((item) => {if (map[item]) {code.push(map[item]);}});let comb = (arr) => {let tmp = [];if (arr.length == 1) {for (let i = 0; i < arr[0].length; i++) {tmp.push(arr[0][i]);}return tmp;} else {for (let i = 0; i < arr[0].length; i++) {for (let j = 0; j < arr[1].length; j++) {tmp.push(`${arr[0][i]}${arr[1][j]}`);}}arr.splice(0, 2, tmp);if (arr.length > 1) {comb(arr);} else {return tmp;}return arr[0];}};return comb(code);};
20.有效的括号
/*** @param {string} s* @return {boolean}*/var isValid = function (s) {let map = {'{': '}','(': ')','[': ']'};let stack = [];for (let i = 0; i < s.length; i++) {if (map[s[i]]) {stack.push(s[i]);} else if (s[i] !== map[stack.pop()]) {return false;}}return stack.length === 0;};/*** @param {string} s* @return {boolean}*/let isValid = function (s) {let sl = s.lengthif (sl % 2 !== 0) return falselet leftToRight = {"{": "}","[": "]","(": ")",}// 建立一个反向的 value -> key 映射表let rightToLeft = createReversedMap(leftToRight)// 用来匹配左右括号的栈let stack = []for (let i = 0; i < s.length; i++) {let bracket = s[i]// 左括号 放进栈中if (leftToRight[bracket]) {stack.push(bracket)} else {let needLeftBracket = rightToLeft[bracket]// 左右括号都不是 直接失败if (!needLeftBracket) {return false}// 栈中取出最后一个括号 如果不是需要的那个左括号 就失败let lastBracket = stack.pop()if (needLeftBracket !== lastBracket) {return false}}}if (stack.length) {return false}return true}function createReversedMap(map) {return Object.keys(map).reduce((prev, key) => {const value = map[key]prev[value] = keyreturn prev}, {})}
21. 合并两个有序链表
// 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。/*** Definition for singly-linked list.* function ListNode(val) {* this.val = val;* this.next = null;* }*//*** @param {ListNode} l1* @param {ListNode} l2* @return {ListNode}*/var mergeTwoLists = function (l1, l2) {if (l1 === null) return l2;let cur = l1;while (l2) {let node = new ListNode();if (cur.val >= l2.val) {node.val = cur.val;node.next = cur.next;cur.val = l2.val;cur.next = node;l2 = l2.next;} else if (cur.next && l2.val <= cur.next.val) {node.val = l2.val;node.next = cur.next;cur.next = node;l2 = l2.next;} else if (!cur.next) {node.val = l2.val;node.next = null;cur.next = node;l2 = l2.next;continue;}cur = cur.next;}return l1;};
89. 格雷编码
// 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。// 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列。即使有多个不同答案,你也只需要返回其中一种。// 格雷编码序列必须以 0 开头。/*** @param {number} n* @return {number[]}*/var grayCode = function (n) {let make = (n) => {if (n === 1) {return ["0", "1"];} else {let prev = make(n - 1);let result = [];let max = Math.pow(2, n) - 1;for (let i = 0; i < prev.length; i++) {result[i] = `0${prev[i]}`;result[max - i] = `1${prev[i]}`;}return result;}};return make(n);};var grayCode = function (n) {let make = (n) => {if (n === 1) return [0, 1];let result = make(n - 1);let highBit = 1 << (n - 1);for (let i = result.length - 1; i >= 0; i--) {result.push(result[i] + highBit);}return result;};if (n === 0) return [0];return make(n);};var grayCode = function (n) {let res = [0];for (let i = 0; i < n; i++) {res = res.concat(res.map((item) => (1 << i) + item).reverse());}return res;};
164. 最大间距
给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。
如果数组元素个数小于 2,则返回 0。
示例 1:
输入: [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。
示例 2:
输入: [10]
输出: 0
解释: 数组元素个数小于 2,因此返回 0。
/*** @param {number[]} nums* @return {number}*/var maximumGap = function (nums) {if (nums.length < 2) return 0;nums.sort((a, b) => a - b);// 保存相邻元素的最大差值let max = 0;let temp = [];for (let i = 0; i < nums.length - 1; i++) {temp = nums[i + 1] - nums[i];if (temp > max) {max = temp;}}return max;};
258. 各位相加
// 给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。/*** @param {number} num* @return {number}*/var addDigits = function (num) {let arr = [];for (let index of num.toString()) {arr.push(index);}if (arr.length === 1) {return parseInt(arr[0]);}let number = 0;for (let i = 0; i < arr.length; i++) {number += parseInt(arr[i]);}if (number > 9) {return addDigits(number);} else {return number;}};
349. 两个数组的交
// 给定两个数组,编写一个函数来计算它们的交集。/*** @param {number[]} nums1* @param {number[]} nums2* @return {number[]}*/var intersection = function (nums1, nums2) {let arr1 = Array.from(new Set(nums1));let arr2 = Array.from(new Set(nums2));let arr3 = new Array();for (let [v, k] of arr1.entries()) {if (arr2.includes(k)) {arr3.push(k);}}return arr3;};var intersection = function (...arrs) {let res = arrs[0];for (let i = 1; i < arrs.length; i++) {res = res.filter((item) => arrs[i].includes(item));}return [...new Set(res)];};
605. 种花问题
// 605. 种花问题// 假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去。// 给定一个花坛(表示为一个数组包含0和1,其中0表示没种植花,1表示种植了花),和一个数 n 。能否在不打破种植规则的情况下种入 n 朵花?能则返回True,不能则返回False。/*** @param {number[]} flowerbed* @param {number} n* @return {boolean}*/var canPlaceFlowers = function (flowerbed, n) {let max = 0;for (let i = 0; i < flowerbed.length - 1; i++) {if (flowerbed[i] === 0) {if (i === 0 && flowerbed[1] === 0) {max++;i++;} else if (flowerbed[i - 1] === 0 && flowerbed[i + 1] === 0) {max++;i++;}}}return max >= n;};// var canPlaceFlowers = function (flowerbed, n) {// let count = 1, sum = 0;// for (val of flowerbed) {// if (val == 1) {// if (count > 1) sum += Math.floor((count - 1) / 2);// count = 0;// } else {// count++;// }// }// if (count > 1) sum += Math.floor(count / 2);// return sum >= n;// };
914. 卡牌分组
// 给定一副牌,每张牌上都写着一个整数。// 此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组:// 每组都有 X 张牌。// 组内所有的牌上都写着相同的整数。// 仅当你可选的 X >= 2 时返回 true。/*** @param {number[]} deck* @return {boolean}*/var hasGroupsSizeX = function (deck) {if (deck.length <= 1) return false;deck.sort((a, b) => {a - b;});let min = Number.MAX_SAFE_INTEGER;let dst = [];let result = true;let tmp = [];for (let i = 0; i < deck.length; i++) {tmp.push(deck[i]);for (let j = i + 1; j < deck.length - 1; j++) {if (deck[i] === deck[j]) {tmp.push(deck[j]);} else {if (min > tmp.length) {min = tmp.length;}dst.push([].concat(tmp));tmp.length = 0;i = j;break;}}}dst.every((item) => {if (item.length % min !== 0) {result = false;return false;}});return result;};var hasGroupsSizeX = function (deck) {// 最大公约数计算公式function gcd(num1, num2) {// 利用辗转相除法来计算最大公约数return num2 === 0 ? num1 : gcd(num2, num1 % num2);}// 相同牌出现次数Maplet timeMap = new Map();// 遍历牌deck.forEach((num) => {// 统计每张牌出现的次数timeMap.set(num, timeMap.has(num) ? timeMap.get(num) + 1 : 1);});// Map.protype.values()返回的是一个新的Iterator对象,所以可以使用扩展运算符(...)来构造成数组let timeAry = [...timeMap.values()];/*最大公约数因为该数组是出现次数数组,最小值至少为1(至少出现1次),所以默认赋值为数组首位对公约数计算无干扰*/let g = timeAry[0];// 遍历出现次数,计算最大公约数timeAry.forEach((time) => {// 因为需要比较所有牌出现次数的最大公约数,故需要一个中间值g = gcd(g, time);});// 判断是否满足题意return g >= 2;};
1047. 删除字符串中的所有相邻重复项
// 给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。// 在 S 上反复执行重复项删除操作,直到无法继续删除。// 在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。/*** @param {string} S* @return {string}*/var removeDuplicates = function (S) {let stack = [];for (const c of S) {let prev = stack.pop();if (prev !== c) {stack.push(prev);stack.push(c);}}return stack.join("");};
1209. 删除字符串中的所有相邻重复项 II
// 给你一个字符串 s,「k 倍重复项删除操作」将会从 s 中选择 k 个相邻且相等的字母,并删除它们,使被删去的字符串的左侧和右侧连在一起。// 你需要对 s 重复进行无限次这样的删除操作,直到无法继续为止。// 在执行完所有删除操作后,返回最终得到的字符串。/*** @param {string} s* @param {number} k* @return {string}*/var removeDuplicates = function (s, k) {let stack = [];for (const c of s) {let prev = stack.pop();if (!prev || prev[0] !== c) {stack.push(prev);stack.push(c);} else if (prev.length < k - 1) {stack.push(prev + c);}}return stack.join("");};
1295. 统计位数为偶数的数字
// 给你一个整数数组 nums,// 请你返回其中位数为 偶数 的数字的个数。// 示例 1:// 输入:nums = [12,345,2,6,7896]// 输出:2// 解释:// 12 是 2 位数字(位数为偶数)// 345 是 3 位数字(位数为奇数)// 2 是 1 位数字(位数为奇数)// 6 是 1 位数字 位数为奇数)// 7896 是 4 位数字(位数为偶数)// 因此只有 12 和 7896 是位数为偶数的数字// 示例 2:// 输入:nums = [555,901,482,1771]// 输出:1// 解释:// 只有 1771 是位数为偶数的数字。// 提示:// 1 <= nums.length <= 500// 1 <= nums[i] <= 10^5/*** @param {number[]} nums* @return {number}*/var findNumbers = function (nums) {let time = 0;for (let i = 0; i < nums.length; i++) {if (String(nums[i]).length % 2 === 0) {time++;}}return time;};const findNumbers = (nums) => nums.reduce((prev, next) => prev + (String(next).length % 2 === 0 ? 1 : 0), 0);
1313. 解压缩编码列表
// 给你一个以行程长度编码压缩的整数列表 nums 。// 考虑每对相邻的两个元素 [freq, val] = [nums[2*i], nums[2*i+1]] (其中 i >= 0 ),每一对都表示解压后子列表中有 freq 个值为 val 的元素,你需要从左到右连接所有子列表以生成解压后的列表。// 请你返回解压后的列表。/*** @param {number[]} nums* @return {number[]}*/var decompressRLElist = function (nums) {const result = [];for (let i = 1; i < nums.length; i++) {if (i % 2 === 1) {result.push(...Array.from(Array(nums[i - 1]), () => nums[i]));}}return result;};
1317. 将整数转换为两个无零整数的和
// 「无零整数」是十进制表示中 不含任何 0 的正整数。// 给你一个整数 n,请你返回一个 由两个整数组成的列表 [A, B],满足:// A 和 B 都是无零整数// A + B = n// 题目数据保证至少有一个有效的解决方案。// 如果存在多个有效解决方案,你可以返回其中任意一个。/*** @param {number} n* @return {number[]}*/var getNoZeroIntegers = function (n) {let time = 1;while (String(time).includes("0") || String(n - time).includes("0")) {time++;}return [time, n - time];};
剑指 Offer 11. 旋转数组的最小数字
// 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。/*** @param {number[]} numbers* @return {number}*/// var minArray = function (numbers) {// for (let i = 0; i < numbers.length; i++) {// if (numbers[i + 1] < numbers[i]) {// return numbers[i + 1];// }// }// return numbers[0];// };var minArray = function (numbers) {let i = 0, j = numbers.length - 1;while (i < j) {const m = Math.floor((i + j) / 2);if (numbers[m] > numbers[j]) {i = m + 1;} else if (numbers[m] < numbers[j]) {j = m;} else {j--;}}return numbers[i];};
