leetcode刷题日记
2191 字
11 分钟
leetcode刷题日记
2022/11/13 #20 有效的括号
这道题目的核心思想理解栈的数据结构
var isValid = function (s) { const dict = new Map([ ["(", ")"], ["{", "}"], ["[", "]"], ]) const stack = [] const pres = [...dict.keys()] const ends = [...dict.values()] for (let i = 0; i < s.length; i++) { const char = s[i] if (pres.includes(char)) { stack.push(char) } else if (ends.includes(char)) { if (dict.get(stack.pop()) !== char) return false } } return !stack.length};2022/11/14 #1 两数之和
两个数字相亲记~
var twoSum = function (nums, target) { const map = new Map() for (let i = 0; i < nums.length; i++) { const n = nums[i] const theHalf = target - n if (!map.has(theHalf)) { map.set(n, i) } else { return [map.get(theHalf), i] } }};2022/11/15 #9 回文数
其实就是两个指针靠近,直到两人亲上都还能没发生不同,那就是一个回文数
var isPalindrome = function (x) { const n = "" + x; if (n.length === 1) return true; let p1 = 0, p2 = n.length - 1; while (p1++ < p2--) { if (n[p1-1] !== n[p2+1]) return false; } return true;};2022/11/16 #13 罗马数字
这道题我最开始写出来是这样的,能明显感觉到不是很优雅
var romanToInt = function (s) { const dict = new Map([ ['I', 1], ['V', 5], ['X', 10], ['L', 50], ['C', 100], ['D', 500], ['M', 1000], ]); let flag = false const nums = s.split('') return nums.reduce((p, n, i) => { if (dict.get(nums[i + 1]) > dict.get(n)) { flag = true return p + 0 } if (flag) { flag = false return p + dict.get(n) - dict.get(nums[i - 1]) } return p + dict.get(n) }, 0)};通过观察我们可以看出来,当右边不小于左边的时候是正常的的转换逻辑,当右边比左边大的就需要用右边减去左边,那我们可以先减再加,我们可以这样改
var romanToInt = function (s) { const dict = new Map([ ['I', 1], ['V', 5], ['X', 10], ['L', 50], ['C', 100], ['D', 500], ['M', 1000], ]); return s.split('').reduce((p, n, i, ns) => { if (dict.get(ns[i + 1]) > dict.get(n)) { return p - dict.get(n) } else { return p + dict.get(n) } }, 0)};2022/11/17 #14 最长公共前缀
var longestCommonPrefix = function (strs) { let p = 0 while (p > -1) { const uniPicks = [...new Set(strs.map((str) => str[p]))] if (uniPicks.includes(undefined) || uniPicks.length != 1) { return strs[0].substring(0, p) } p++ }};2022/11/18 #26 删除有序数组中的重复项
var removeDuplicates = function (nums) { const uniNums = [...new Set(nums)] nums.length = uniNums.length uniNums.forEach((n, i) => { nums[i] = n }) return nums.length};2022/11/19 #27 移除元素
var removeElement = function (nums, val) { let i = 0; while (i < nums.length) { if (nums[i] === val) { nums.splice(i, 1) } else { i++ } } return nums.length};2022/11/21 #35 搜索插入位置 | #58 最后一个单词的长度
// #35 搜索插入位置var searchInsert = function (nums, target) { for (let i = 0; i < nums.length; i++) { // case1 相等 if (nums[i] === target) return i; // case2 在某个节点大于它之前 if (nums[i] > target) return i; } // case3 插入末尾 return nums.length;};
// #58 最后一个单词的长度var lengthOfLastWord = function (s) { return s.trim().split(" ").at(-1).length;};2022/11/22 #66 加一
var plusOne = function (digits) { let carry = false; digits[digits.length - 1] = digits.at(-1) + 1; for (let i = digits.length - 1; i >= 0; i--) { let n = digits[i] if (carry) { n++; carry = false; } if (n >= 10) { carry = true; digits[i] = n % 10; } else { digits[i] = n; } } if (carry) { digits.unshift(1) } return digits;};想了想,其实所有工作都可以在for循环里完成
var plusOne = function (digits) { digits[digits.length - 1] = digits.at(-1) + 1; for (let i = digits.length - 1; i >= 0; i--) { if (digits[i] >= 10) { digits[i] = digits[i] % 10; // 防止下标越界 if (i === 0) { digits.unshift(1); } else { digits[i - 1] = digits[i - 1] + 1; } } } return digits;};2022/11/23 #67 二进制求和
这道题和昨天的题神似,不过换成二进制的n+n,昨天是十进制的n+1
var addBinary = function (a, b) { const r = []; const sameLen = a.length === b.length; // 长组 const l = sameLen ? a : a.length > b.length ? a : b const lt = l.split(""); const li = lt.length - 1; // 短组 const s = sameLen ? b : a.length < b.length ? a : b const st = s.split(""); let si = st.length - 1; // 长短差 const di = li - si; // 公共进制位 while (si >= 0) { const n = +lt[di + si] + +st[si] // 需要进位 if (n >= 2) { r.unshift(n % 2); // 相同长度下防止下标越界 if (si === 0 && sameLen) { r.unshift(1) } else { lt[si + di - 1] = +lt[si + di - 1] + 1; } } // 无需进位 else { r.unshift(n); } si-- } // 长组余下进制位,其实和上边的逻辑相似,只是不用考虑加法 if (di) { let i = di - 1; while (i >= 0) { const n = lt[i]; if (n >= 2) { r.unshift(n % 2) if (i === 0) { r.unshift(1) } else { lt[i - 1] = +lt[i - 1] + 1; } } else { r.unshift(n) } i-- } } return r.join('');};看到评论区有同学说,长度不一样的情况下可以直接补齐之后再计算,一想的确有道理啊,但是效率应该不会有多大提升,该循环的次数一次没少,不过简洁一些
var addBinary = function (a, b) { const r = []; const sameLen = a.length === b.length; // 长组 const l = sameLen ? a : a.length > b.length ? a : b const lt = l.split(""); let li = lt.length - 1; // 短组 const s = sameLen ? b : a.length < b.length ? a : b const st = s.split(""); const si = st.length - 1; // 长短差 const di = li - si; // 补齐短组 const ft = sameLen ? st : [...new Array(di).fill(0), ...st]; // 公共进制位 while (li >= 0) { const n = +lt[li] + +ft[li] // 需要进位 if (n >= 2) { r.unshift(n % 2); // 相同长度下防止下标越界 if (li === 0) { r.unshift(1) } else { lt[li - 1] = +lt[li - 1] + 1; } } // 无需进位 else { r.unshift(n); } li-- } return r.join('');};确实少了很多代码哈.
2022/11/27 #69 X的平方根 | #70 爬楼梯 | # 83 删除排序链表中的重复元素
// #69var mySqrt = function (x) { if (x == 0 || x == 1) return x; let left = 1, right = x; // 只要左边没超过右边就需要一直去查找 while (left < right) { // 如果只相隔1,直接返回左边 if (right - left == 1) return left; // 向下取整中位数 let mid = left + Math.floor((right - left) / 2); // 除以中位数 let res = x / mid; // 如果刚好结果相等,中位数就是想要的数字 if (res === mid) return mid; // 如果结果小于中位数,说明应该向左缩小范围 if (res < mid) { right = mid; } // 如果结果大于中位数,说明应该向右缩小范围 else { left = mid; } }};
// #70 这是一道经典的动态规划的算法题目,你需要做的最关键的一点是总结出前后节点的规律,或者说是一个公式var climbStairs = function (n) { if (n < 2) return 1; // 用来保存每个台阶的方法数目 const dp = [1, 1]; for (let i = 2; i <= n; i++) { dp[i] = dp[i - 1] + dp[i - 2]; } return dp[n];};
// #83var deleteDuplicates = function (head) { let p = head; while (p && p.next) { // 下个节点 const next = p.next; // 如果重复,将当前节点的next指向下个节点的next if (next.val === p.val) { p.next = next.next; } else { // 将当前指针往后移动 p = p.next; } } return head;};2023/1/19 #88 合并两个有序数组
这个题依然算是简单的指针题,两个指针在自己的合适的情况前进,直到走到目标位置即可
不知道为啥今天leetcode抽疯测试和提交出问题了,但是在本地测试是没问题的,没有测试所有测试用例,可能会有边角料问题,小case~
var merge = function (nums1, m, nums2, n) { const res = []; let i = 0, j = 0; while (i < m || j < n) { const n1 = nums1[i] const n2 = nums2[j] // 是否越界 if (i >= m) { res.push(n2) j++ } // 是否越界 else if (j >= n) { res.push(n1) i++ } // 判断大小 else if (n1 < n2) { res.push(n1) i++ } else if (n1 > n2) { res.push(n2) j++ } // 相等 else { res.push(n1, n2) i++ j++ } } return res};原来leetcode那天并没有抽风,其实是我没注意到题目,是合并到num1数组,不是返回一个新数组 =.=
var merge = function (nums1, m, nums2, n) { // 从后往前遍历,避免覆盖 let i = m - 1, j = n - 1, k = m + n - 1; while (i >= 0 && j >= 0) { if (nums1[i] > nums2[j]) { nums1[k--] = nums1[i--]; } else { nums1[k--] = nums2[j--]; } } // nums2还有剩余 while (j >= 0) { nums1[k--] = nums2[j--]; } return nums1;};2023/1/19 #112 合并两个有序数组
2023/4/11 #104 二叉树的最大深度
var maxDepth = function (root) { if (root === null) return 0; return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;};20230/6/7
189 轮转数组
var rotate = function (nums, k) { for (let i = 0; i < k; i++) { nums.unshift(nums.pop()); }};724 寻找数组的中心下标
这道题目难度是中等?我感觉就很简单啊~
var pivotIndex = function (nums) { let index = -1; for (let i = 0; i < nums.length; i++) { const leftSum = nums.slice(0, i).reduce((a, b) => a + b, 0); const rightSum = nums.slice(i + 1).reduce((a, b) => a + b, 0); if (leftSum === rightSum) { index = i; break; } } return index};文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!














