From d51e795d488bf3bde48d4358bd41cabc7c7251c0 Mon Sep 17 00:00:00 2001 From: alwyn Date: Sun, 24 Jan 2021 22:19:42 +0800 Subject: [PATCH 001/210] add .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..e43b0f98 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store From bccdbdf28b3d3e3bde4078f19059c6c5d2beb464 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 27 Jan 2021 23:42:52 +0800 Subject: [PATCH 002/210] =?UTF-8?q?=E6=AF=8F=E6=97=A5=E4=B8=80=E9=A2=98?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_01/001.js | 17 +++++++++++++++++ Week_01/070.js | 15 +++++++++++++++ Week_01/66.js | 19 +++++++++++++++++++ Week_01/README.md | 46 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 Week_01/001.js create mode 100644 Week_01/070.js create mode 100644 Week_01/66.js diff --git a/Week_01/001.js b/Week_01/001.js new file mode 100644 index 00000000..969dd25a --- /dev/null +++ b/Week_01/001.js @@ -0,0 +1,17 @@ +/** + * 思路:类似去婚姻登记所找另一半,如果没找到匹配对象,就利用哈希表登记下;找到了就ok。 + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function(nums, target) { + var hashMap = {} + for(var i = 0; i < nums.length; ++i) { + if (hashMap[nums[i]] === undefined) { + hashMap[target - nums[i]] = i + } else { + return [hashMap[nums[i]], i] + } + } + return [] +}; diff --git a/Week_01/070.js b/Week_01/070.js new file mode 100644 index 00000000..e3294dbe --- /dev/null +++ b/Week_01/070.js @@ -0,0 +1,15 @@ +/** + * 思路:fibnacci数列 + * @param {number} n + * @return {number} + */ +var climbStairs = function(n) { + if (n < 3) return n + var p1 = 1, p2 = 2, p3 = 3 + while(n-- > 3) { + p1 = p2 + p2 = p3 + p3 = p1 + p2 + } + return p3 +}; diff --git a/Week_01/66.js b/Week_01/66.js new file mode 100644 index 00000000..3599db89 --- /dev/null +++ b/Week_01/66.js @@ -0,0 +1,19 @@ +/** + * 思路:从右往左遍历,遇9进位 + * @param {number[]} digits + * @return {number[]} + */ +var plusOne = function(digits) { + for(var i = digits.length - 1; i >= 0; --i) { + if (digits[i] < 9){ + digits[i]++ + break + } else { + digits[i] = 0 + if(i === 0) { + digits.unshift(1) + } + } + } + return digits +}; diff --git a/Week_01/README.md b/Week_01/README.md index 50de3041..6c2a430a 100644 --- a/Week_01/README.md +++ b/Week_01/README.md @@ -1 +1,45 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +入学考试 +## 零、每日刷题 + +## 一、课堂题目 + +11 盛更多水的容器 https://leetcode-cn.com/problems/container-with-most-water/ +283 移动零 https://leetcode-cn.com/problems/move-zeroes/ +70 爬楼梯 https://leetcode.com/problems/climbing-stairs/ +15 三数之和 https://leetcode-cn.com/problems/3sum/ (高频老题) +206 反转链表 https://leetcode.com/problems/reverse-linked-list/ +24 两两交换链表中的节点 https://leetcode-cn.com/problems/swap-nodes-in-pairs/ +141 环形链表 https://leetcode.com/problems/linked-list-cycle +142 环形链表II https://leetcode-cn.com/problems/linked-list-cycle-ii/ +25 K 个一组翻转链表 https://leetcode.com/problems/reverse-nodes-in-k-group/ +20 有效的括号 https://leetcode-cn.com/problems/valid-parentheses/ +155 最小栈 https://leetcode-cn.com/problems/min-stack/ +84 柱状图中最大的矩形 https://leetcode-cn.com/problems/largest-rectangle-in-histogram +239 滑动窗口最大值 https://leetcode-cn.com/problems/sliding-window-maximum + +## 二、作业 + +**easy** + ++ 用 add first 或 add last 这套新的 API 改写 Deque 的代码 ++ 分析 Queue 和 Priority Queue 的源码 ++ 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) ++ 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) ++ 合并两个有序链表(亚马逊、字节跳动在半年内面试常考) ++ 合并两个有序数组(Facebook 在半年内面试常考) ++ 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) ++ 移动零(Facebook、亚马逊、苹果在半年内面试中考过) ++ 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) + +**medium** + ++ 设计循环双端队列(Facebook 在 1 年内面试中考过) + +**hard** + ++ 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) + +## 三、训练场 + From aaa1bf8b4c78360e88c6a0f54068c1174e2bfbf4 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 27 Jan 2021 23:44:52 +0800 Subject: [PATCH 003/210] rename --- Week_01/{66.js => 066.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Week_01/{66.js => 066.js} (100%) diff --git a/Week_01/66.js b/Week_01/066.js similarity index 100% rename from Week_01/66.js rename to Week_01/066.js From fa06ddde15d55da155a23fe86d427e221cb54810 Mon Sep 17 00:00:00 2001 From: alwynzhou Date: Sat, 30 Jan 2021 14:56:01 +0800 Subject: [PATCH 004/210] add week1 homework --- Week_01/homework.js | 113 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 Week_01/homework.js diff --git a/Week_01/homework.js b/Week_01/homework.js new file mode 100644 index 00000000..81d09394 --- /dev/null +++ b/Week_01/homework.js @@ -0,0 +1,113 @@ +/** + * 1. 用 add first 或 add last 这套新的 API 改写 Deque 的代码 + * 思路: ?? + */ + + +/** + * 2. 分析 Queue 和 Priority Queue 的源码 + * 思路: ?? + */ + +/** + * 3. 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) + * easy | leetcode-026 | array + * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ + * 思路: + */ + +/** + * 4. 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) + * medium | leetcode-189 | array + * https://leetcode-cn.com/problems/rotate-array/ + * 思路: + */ + +/** + * 5. 合并两个有序链表(亚马逊、字节跳动在半年内面试常考) + * leetcode-021 | + * https://leetcode-cn.com/problems/merge-two-sorted-lists/ + */ +var mergeTwoLists = function(l1, l2) { + +}; + +/** + * 6. 合并两个有序数组(Facebook 在半年内面试常考) + * leetcode-088 | + * https://leetcode-cn.com/problems/merge-sorted-array/ + */ +var merge = function(nums1, m, nums2, n) { + +}; + + +/** + * 7. 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) + * leetcode-001 + * https://leetcode-cn.com/problems/two-sum/ + */ +var twoSum = function (nums, target) { + +}; + +/** + * 8. 移动零(Facebook、亚马逊、苹果在半年内面试中考过) + * leetcode-283 | + * https://leetcode-cn.com/problems/move-zeroes/ + */ +var moveZeroes = function(nums) { + +}; + +/** + * 9. 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) + * leetcode-066 | + * https://leetcode-cn.com/problems/plus-one/ + */ +var plusOne = function(digits) { + +}; + +/** + * 10. 设计循环双端队列(Facebook 在 1 年内面试中考过) + * leetcode-641 | + * https://leetcode-cn.com/problems/design-circular-deque/?utm_source=LCUS&utm_medium=ip_redirect&utm_campaign=transfer2china + */ +var MyCircularDeque = function(k) { + +}; +MyCircularDeque.prototype.insertFront = function(value) { + +}; +MyCircularDeque.prototype.insertLast = function(value) { + +}; +MyCircularDeque.prototype.deleteFront = function() { + +}; +MyCircularDeque.prototype.deleteLast = function() { + +}; +MyCircularDeque.prototype.getFront = function() { + +}; +MyCircularDeque.prototype.getRear = function() { + +}; +MyCircularDeque.prototype.isEmpty = function() { + +}; +MyCircularDeque.prototype.isFull = function() { + +}; + + +/** + * 11. 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) + * leetcode-042 | + * https://leetcode.com/problems/trapping-rain-water/ + */ +var trap = function(height) { + +}; From 1c0a4b394e4338402df576358e7ad9da98c5caff Mon Sep 17 00:00:00 2001 From: alwynzhou Date: Sat, 30 Jan 2021 17:39:47 +0800 Subject: [PATCH 005/210] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BD=9C=E4=B8=9A=20?= =?UTF-8?q?5=20-=209=20=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_01/homework.js | 71 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/Week_01/homework.js b/Week_01/homework.js index 81d09394..0870a4f0 100644 --- a/Week_01/homework.js +++ b/Week_01/homework.js @@ -25,20 +25,44 @@ /** * 5. 合并两个有序链表(亚马逊、字节跳动在半年内面试常考) - * leetcode-021 | + * easy | leetcode-021 | link-list * https://leetcode-cn.com/problems/merge-two-sorted-lists/ + * 思路: 类似归并排序的归并过程 */ var mergeTwoLists = function(l1, l2) { - + var dummyHead = {val: -1, next: null}, p = dummyHead + while(l1 && l2) { + if (l1.val <= l2.val) { + p.next = l1 + l1 = l1.next + } else { + p.next = l2 + l2 = l2.next + } + p = p.next + } + p.next = l1 || l2 + return dummyHead.next }; /** * 6. 合并两个有序数组(Facebook 在半年内面试常考) - * leetcode-088 | + * easy | leetcode-088 | array * https://leetcode-cn.com/problems/merge-sorted-array/ */ var merge = function(nums1, m, nums2, n) { - + var 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--] + } + } + while(j >= 0) { + nums1[k--] = nums2[j--] + } + return nums1 }; @@ -48,25 +72,56 @@ var merge = function(nums1, m, nums2, n) { * https://leetcode-cn.com/problems/two-sum/ */ var twoSum = function (nums, target) { - + var hashMap = {} + for (var i = 0; i < nums.length; ++i) { + if (hashMap[nums[i]] === void(0)) { + hashMap[target- nums[i]] = i + } else { + return [hashMap[nums[i]], i] + } + } + return [] }; /** * 8. 移动零(Facebook、亚马逊、苹果在半年内面试中考过) * leetcode-283 | * https://leetcode-cn.com/problems/move-zeroes/ + * 思路: 用一个标记记录非0的位置 */ var moveZeroes = function(nums) { - + var swap = function(nums, i, j) { + var tmp = nums[i] + nums[i] = nums[j] + nums[j] = tmp + } + +for (var i = 0, j = 0; i < nums.length; ++i) { + if (nums[i] !== 0) { + swap(nums, i, j++) + } +} +return nums }; /** * 9. 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) - * leetcode-066 | + * easy | leetcode-066 | array * https://leetcode-cn.com/problems/plus-one/ */ var plusOne = function(digits) { - + for (var i = digits.length - 1; i >= 0; --i) { + if (digits[i] < 9) { + ++digits[i] + break + } else { + digits[i] = 0 + if (i === 0) { + digits.unshift(1) + } + } + } + return digits }; /** From 821216d3e85e453da4ba8be542cda6539c0f015e Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 31 Jan 2021 10:02:08 +0800 Subject: [PATCH 006/210] =?UTF-8?q?=E5=AE=8C=E6=88=90week01=20homework=200?= =?UTF-8?q?2=E3=80=8103?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_01/README.md | 28 ++++------------------------ Week_01/homework.js | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/Week_01/README.md b/Week_01/README.md index 6c2a430a..6c1a255e 100644 --- a/Week_01/README.md +++ b/Week_01/README.md @@ -1,30 +1,13 @@ # 学习笔记 - -入学考试 -## 零、每日刷题 - -## 一、课堂题目 - -11 盛更多水的容器 https://leetcode-cn.com/problems/container-with-most-water/ -283 移动零 https://leetcode-cn.com/problems/move-zeroes/ -70 爬楼梯 https://leetcode.com/problems/climbing-stairs/ -15 三数之和 https://leetcode-cn.com/problems/3sum/ (高频老题) -206 反转链表 https://leetcode.com/problems/reverse-linked-list/ -24 两两交换链表中的节点 https://leetcode-cn.com/problems/swap-nodes-in-pairs/ -141 环形链表 https://leetcode.com/problems/linked-list-cycle -142 环形链表II https://leetcode-cn.com/problems/linked-list-cycle-ii/ -25 K 个一组翻转链表 https://leetcode.com/problems/reverse-nodes-in-k-group/ -20 有效的括号 https://leetcode-cn.com/problems/valid-parentheses/ -155 最小栈 https://leetcode-cn.com/problems/min-stack/ -84 柱状图中最大的矩形 https://leetcode-cn.com/problems/largest-rectangle-in-histogram -239 滑动窗口最大值 https://leetcode-cn.com/problems/sliding-window-maximum - -## 二、作业 +## 作业 **easy** + 用 add first 或 add last 这套新的 API 改写 Deque 的代码 + 分析 Queue 和 Priority Queue 的源码 + +大致过了一下 API,平时主要用JavaScript,不太熟悉Java。 + + 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) + 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) + 合并两个有序链表(亚马逊、字节跳动在半年内面试常考) @@ -40,6 +23,3 @@ **hard** + 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) - -## 三、训练场 - diff --git a/Week_01/homework.js b/Week_01/homework.js index 0870a4f0..935ef80c 100644 --- a/Week_01/homework.js +++ b/Week_01/homework.js @@ -1,27 +1,57 @@ /** * 1. 用 add first 或 add last 这套新的 API 改写 Deque 的代码 - * 思路: ?? + * 双端队列 deque */ - /** * 2. 分析 Queue 和 Priority Queue 的源码 - * 思路: ?? + * 队列:http://fuseyism.com/classpath/doc/java/util/Queue-source.html + * 优先队列:https://docs.oracle.com/javase/10/docs/api/java/util/PriorityQueue.html */ /** * 3. 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) * easy | leetcode-026 | array * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ - * 思路: + * 思路:利用数组是有序的特性,重复元素必相邻。遍历一轮,用cnt记录重复项数量,用第i个元素覆盖i-cnt个元素 */ +var removeDuplicates = function(nums) { + var cnt = 0; + for(var i = 1; i < nums.length; ++i) { + if (nums[i] === nums[i - 1]) { + cnt++ + } else { + nums[i - cnt] = nums[i] + } + } + return nums.length - cnt +}; /** * 4. 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) * medium | leetcode-189 | array * https://leetcode-cn.com/problems/rotate-array/ - * 思路: + * 思路:反转三次,时间复杂度O(n), 空间复杂度O(1) */ +// var rotate = function(nums, k) { +// var gap = nums.length - k +// nums = nums.slice(gap).concat(nums.slice(0, gap)) +// return nums +// }; +// O(1)空间复杂度解法: 反转3次 +var rotate = function(nums, k) { + var reverse = function(nums, start, end) { + while(start < end) { + var tmp = nums[start] + nums[start++] = nums[end] + nums[end--] = tmp + } + } + k %= nums.length + reverse(nums, 0, nums.length - 1) + reverse(nums, 0, k - 1) + reverse(nums, k, nums.length - 1) +}; /** * 5. 合并两个有序链表(亚马逊、字节跳动在半年内面试常考) From d51e587380e4e89445cc69ee41829f9e7c55e01e Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 31 Jan 2021 10:37:48 +0800 Subject: [PATCH 007/210] =?UTF-8?q?=E5=AE=8C=E6=88=90week01=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_01/homework.js | 71 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/Week_01/homework.js b/Week_01/homework.js index 935ef80c..9c297561 100644 --- a/Week_01/homework.js +++ b/Week_01/homework.js @@ -156,43 +156,88 @@ var plusOne = function(digits) { /** * 10. 设计循环双端队列(Facebook 在 1 年内面试中考过) - * leetcode-641 | + * medium | leetcode-641 | deque * https://leetcode-cn.com/problems/design-circular-deque/?utm_source=LCUS&utm_medium=ip_redirect&utm_campaign=transfer2china + * 思路: js的array完全是超集,约束下 length 可以很简单实现 */ var MyCircularDeque = function(k) { - + this.queue = new Array() + this.length = k }; -MyCircularDeque.prototype.insertFront = function(value) { +MyCircularDeque.prototype.insertFront = function(value) { + if (this.queue.length < this.length) { + this.queue.unshift(value) + return true + } + return false }; MyCircularDeque.prototype.insertLast = function(value) { - + if (this.queue.length < this.length) { + this.queue.push(value) + return true + } + return false }; MyCircularDeque.prototype.deleteFront = function() { - + if (this.queue.length > 0) { + this.queue.shift() + return true + } + return false }; MyCircularDeque.prototype.deleteLast = function() { - + if (this.queue.length > 0) { + this.queue.pop() + return true + } + return false }; MyCircularDeque.prototype.getFront = function() { - + if (this.queue.length === 0) { + return -1 + } + return this.queue[0] }; MyCircularDeque.prototype.getRear = function() { - + if (this.queue.length === 0) { + return -1 + } + return this.queue[this.queue.length - 1] }; MyCircularDeque.prototype.isEmpty = function() { - + return this.queue.length === 0 }; MyCircularDeque.prototype.isFull = function() { - + return this.queue.length === this.length }; /** * 11. 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) - * leetcode-042 | + * hard | leetcode-042 | array * https://leetcode.com/problems/trapping-rain-water/ + * 思路: maxLeft、maxRight 记录左右最高柱子 */ -var trap = function(height) { - +var trap = function(A) { + var left = 0, right = A.length - 1 + var res = 0, maxLeft = 0, maxRight = 0 + while (left < right) { + if (A[left] <= A[right]) { + if (A[left] >= maxLeft) { + maxLeft = A[left] + } else { + res += maxLeft - A[left] + } + ++left + } else { + if (A[right] >= maxRight) { + maxRight = A[right] + } else { + res += maxRight - A[right] + } + --right + } + } + return res }; From c68cb656bd3cd63a864ab2f3c2b8699839e14740 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 1 Feb 2021 23:42:18 +0800 Subject: [PATCH 008/210] =?UTF-8?q?350=20=E4=B8=A4=E4=B8=AA=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E7=9A=84=E4=BA=A4=E9=9B=86=20II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_02/350.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Week_02/350.js diff --git a/Week_02/350.js b/Week_02/350.js new file mode 100644 index 00000000..f37d5d9f --- /dev/null +++ b/Week_02/350.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number[]} + * https://leetcode-cn.com/problems/intersection-of-two-arrays-ii/submissions/ + * easy | 350. 两个数组的交集 II | hashmap + */ +var intersect = function(nums1, nums2) { + if(nums1.length > nums2.length) { + return intersect(nums2, nums1) + } + let cntMap = {}, res = [] + for(var i = 0; i < nums1.length; ++i) { + if (cntMap[nums1[i]] === void(0)) { + cntMap[nums1[i]] = 1 + } else { + ++cntMap[nums1[i]] + } + } + for(var i = 0; i < nums2.length; ++i) { + if (cntMap[nums2[i]] > 0) { + --cntMap[nums2[i]] + res.push(nums2[i]) + } + } + return res +}; From 2fc6368abeb5b00c5e25f3a7e8c29d310e97837b Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 2 Feb 2021 23:16:32 +0800 Subject: [PATCH 009/210] everyday offer-59-1 --- Week_02/offer59-1.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Week_02/offer59-1.js diff --git a/Week_02/offer59-1.js b/Week_02/offer59-1.js new file mode 100644 index 00000000..8b1d759f --- /dev/null +++ b/Week_02/offer59-1.js @@ -0,0 +1,44 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + * https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/ + * https://leetcode-cn.com/problems/sliding-window-maximum/ + * 思路1: 暴力求解 + */ +var maxSlidingWindow = function(nums, k) { + if (nums.length < 1 || k < 1) return [] + var res = [], start = 0; + for(var start = 0; start <= nums.length - k; ++start) { + var maxNum = nums[start] + for(var i = start + 1; i <= start + k - 1; ++i) { + maxNum = Math.max(maxNum, nums[i]) + } + res.push(maxNum) + } + return res +}; + +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + * 思路2: 用 window 记录当前窗口,如果当前窗口左边有小值,pop掉 + */ +var maxSlidingWindow = function(nums, k) { + if (nums.length < 1 || k < 1) return [] + var res = [], window = [] + nums.forEach((item, idx) => { + if (idx >= k + window[0]) { // 维护窗口 + window.shift() + } + while(window.length > 0 && item > nums[window[window.length - 1]]) { // pop掉“无出头之日”的小值 + window.pop() + } + window.push(idx) // 加入当前值 + if (idx >= k - 1) { // 有效窗口中最左边的值就是最大值 + res.push(nums[window[0]]) + } + }) + return res +}; From 8e487d9b3b42b8d3b8ac353c09450b5bc7a7efad Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 4 Feb 2021 00:35:54 +0800 Subject: [PATCH 010/210] solve 1021 --- Week_02/1021.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Week_02/1021.js diff --git a/Week_02/1021.js b/Week_02/1021.js new file mode 100644 index 00000000..a6bd0f70 --- /dev/null +++ b/Week_02/1021.js @@ -0,0 +1,15 @@ +/** + * @param {string} S + * @return {string} + * https://leetcode-cn.com/problems/remove-outermost-parentheses/ + * 思路: 一轮遍历,把非最外层的括号放入 res + */ +var removeOuterParentheses = function(S) { + var res = [], cnt = 0 + for(var i = 0; i < S.length; ++i) { + S[i] === ')' && --cnt + cnt > 0 && res.push(S[i]) + S[i] === '(' && ++cnt + } + return res.join('') +}; From 213a19090f7707ffa5532767699a2563b32795f8 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 4 Feb 2021 00:48:32 +0800 Subject: [PATCH 011/210] solve 412 FizzBuzz --- Week_02/412.js | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Week_02/412.js diff --git a/Week_02/412.js b/Week_02/412.js new file mode 100644 index 00000000..fdf3ad77 --- /dev/null +++ b/Week_02/412.js @@ -0,0 +1,39 @@ +/** + * @param {number} n + * @return {string[]} + * https://leetcode-cn.com/problems/fizz-buzz/submissions/ + * 思路1: 暴力 + */ +var fizzBuzz = function(n) { + var res = [] + for(var i = 1; i <= n; ++i) { + if (i % 3 === 0 && i % 5 === 0) { + res.push('FizzBuzz') + } else if (i % 3 === 0) { + res.push('Fizz') + } else if (i % 5 === 0) { + res.push('Buzz') + } else { + res.push(String(i)) + } + } + return res +}; + + +/** + * @param {number} n + * @return {string[]} + * 思路2: 对照表 + */ +var fizzBuzz = function(n) { + var arr = ['FizzBuzz', '', '', 'Fizz', '', 'Buzz', 'Fizz', '', '', 'Fizz', 'Buzz', '', 'Fizz', '', ''], res = [] + for(var i = 1; i <= n; ++i) { + if (!arr[i % 15]) { + res.push(String(i)) + } else { + res.push(arr[i % 15]) + } + } + return res +}; From a632e8bbc3aa84d62b9966f2aadbbb50787b6d57 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 6 Feb 2021 16:44:53 +0800 Subject: [PATCH 012/210] everyday solve --- Week_01/021.js | 30 ++++++++++++++++++++++++++++++ Week_01/024.js | 46 ++++++++++++++++++++++++++++++++++++++++++++++ Week_01/README.md | 17 +++++++++++++++++ Week_02/104.js | 20 ++++++++++++++++++++ Week_02/258.js | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+) create mode 100644 Week_01/021.js create mode 100644 Week_01/024.js create mode 100644 Week_02/104.js create mode 100644 Week_02/258.js diff --git a/Week_01/021.js b/Week_01/021.js new file mode 100644 index 00000000..7889f406 --- /dev/null +++ b/Week_01/021.js @@ -0,0 +1,30 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + * 21. 合并两个有序链表 + * 思路: 声明一个空指针头,遍历l1 和 l2,谁的值比较小就把谁拼接在后面 + */ +var mergeTwoLists = function(l1, l2) { + var dummy = { val: -1, next: null }, + cur = dummy + while(l1 && l2) { + if (l1.val < l2.val) { + cur.next = l1 + l1 = l1.next + } else { + cur.next = l2 + l2 = l2.next + } + cur = cur.next + } + cur.next = l1 || l2 + return dummy.next +}; diff --git a/Week_01/024.js b/Week_01/024.js new file mode 100644 index 00000000..33c2a7f8 --- /dev/null +++ b/Week_01/024.js @@ -0,0 +1,46 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * 24. 两两交换链表中的节点 + * 思路1: 递归 + * @param {ListNode} head + * @return {ListNode} + */ +var swapPairs = function(head) { + if (!head || !head.next) { + return head + } + var newHead = head.next, hnn = head.next.next + newHead.next = head + head.next = swapPairs(hnn) + return newHead +}; + + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** 思路2: 空指针头画图 + * @param {ListNode} head + * @return {ListNode} + */ +var swapPairs = function(head) { + var dummy = { val: -1, next: head }, cur = dummy + while(cur.next && cur.next.next) { + var p1 = cur.next + var p2 = cur.next.next + p1.next = p2.next + cur.next = p2 + p2.next = p1 + } + return dummy.next +}; diff --git a/Week_01/README.md b/Week_01/README.md index 6c1a255e..f59b0a35 100644 --- a/Week_01/README.md +++ b/Week_01/README.md @@ -1,4 +1,21 @@ # 学习笔记 + +## 听课笔记 + +> [Java.util.ArrayList](http://developer.classpath.org/doc/java/util/ArrayList-source.html) +> [Java.util.LinkedList](http://developer.classpath.org/doc/java/util/LinkedList-source.html) + +**时间复杂度** + +备注:skiplist 是有序的,实现简单,维护成本较高,空间复杂度O(n)。 + + array | linkedlist | skiplist +prepend O(1) O(1) O(1) +append O(1) O(1) O(1) +lookup O(1) O(n) O(logn) +insert O(n) O(1) O(logn) +delete O(n) O(1) O(logn) + ## 作业 **easy** diff --git a/Week_02/104.js b/Week_02/104.js new file mode 100644 index 00000000..a2450452 --- /dev/null +++ b/Week_02/104.js @@ -0,0 +1,20 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {number} + * https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/submissions/ + * 思路:递归遍历左右子树 + */ +var maxDepth = function(root) { + if (!root) return 0 + const left = maxDepth(root.left) + const right = maxDepth(root.right) + return Math.max(left, right) + 1 +}; diff --git a/Week_02/258.js b/Week_02/258.js new file mode 100644 index 00000000..15556749 --- /dev/null +++ b/Week_02/258.js @@ -0,0 +1,32 @@ +/** + * @param {number} num + * @return {number} + * https://leetcode-cn.com/problems/add-digits/ + * 思路1: 强制转换 + */ +var addDigits = function(num) { + while(num > 9) { + var sum = 0 + num = String(num).split('').forEach(item => sum += Number(item)) + num = sum + } + return num +}; + + +/** + * @param {number} num + * @return {number} + * 思路2: while + */ +var addDigits = function(num) { + while(num > 9) { + var sum = 0 + while(num > 9) { + sum += num % 10 + num /= 10 + } + num = sum + } + return num +}; From 1e115ac861075f0c61687467fdc7392ca7433a62 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 7 Feb 2021 01:55:38 +0800 Subject: [PATCH 013/210] =?UTF-8?q?week02=20=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_02/README.md | 11 ++++- Week_02/homework.js | 118 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 Week_02/homework.js diff --git a/Week_02/README.md b/Week_02/README.md index 50de3041..8b8ce6ed 100644 --- a/Week_02/README.md +++ b/Week_02/README.md @@ -1 +1,10 @@ -学习笔记 \ No newline at end of file +学习笔记 + +1. [JavaScript 中的 Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) +2. [JS中,Set、Map、WeakSet 和 WeakMap 的区别](https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/6) + ++ TODO [JavaScript 实现 PriorityQueue](./priorityQueue.js) + +## 作业 + +[week02 作业](./homework.js) diff --git a/Week_02/homework.js b/Week_02/homework.js new file mode 100644 index 00000000..2adc77c1 --- /dev/null +++ b/Week_02/homework.js @@ -0,0 +1,118 @@ +/** + * 1. 写一个关于HashMap的小总结 + * TODO + */ + +/** + * 2. 有效字母的异位词(亚马逊、Facebook、谷歌在半年内面试中考过) + * leetcode-242 | easy + * https://leetcode-cn.com/problems/valid-anagram/submissions/ + * 思路1: 排序 O(nlogn) + */ +var isAnagram = function(s, t) { + if (s.length !== t.length) return false + var stringSort = function(str){ + return str.split('').sort().join('') + } + return stringSort(s) === stringSort(t) +}; +/** 思路2: 用hashmap统计,计数 */ +var isAnagram = function(s, t) { + if (s.length !== t.length) return false + var map = {} + for(var i = 0; i < s.length; ++i) { + if (map[s[i]] === void(0)) { + map[s[i]] = 1 + } else { + ++map[s[i]] + } + } + for(var i = 0; i < t.length; ++i) { + if (map[t[i]] === void(0) || map[t[i]] <= 0) { + return false + } else { + --map[t[i]] + } + } + for(key in map) { + if (map[key] !== 0) { + return false + } + } + return true +}; +/** 思路3: 数组记录,增减记数(O(n))trick: charCodeAt */ +var isAnagram = function(s, t) { + if (s.length !== t.length) return false + var arr = Array(26).fill(0) + for(var i = 0; i < s.length; ++i) { + ++arr[s[i].charCodeAt(0) - 'a'.charCodeAt(0)] + } + for(var i = 0; i < t.length; ++i) { + --arr[t[i].charCodeAt(0) - 'a'.charCodeAt(0)] + } + return arr.filter(item => item !== 0).length === 0 +}; + +/** + * 3. 两数之和(近半年内,亚马逊考查此题达到 216 次、字节跳动 147 次、谷歌 104 次,Facebook、苹果、微软、腾讯也在近半年内面试常考) + * https://leetcode-cn.com/problems/two-sum/ + */ +var twoSum = function(nums, target) { + var hashMap = {} + for(var i = 0; i < nums.length; ++i) { + if (hashMap[nums[i]] === void(0)) { + hashMap[target - nums[i]] = i + } else { + return [hashMap[nums[i]], i] + } + } + return [] +}; + +/** + * 4. N 叉树的前序遍历(亚马逊在半年内面试中考过) + * + */ + + + +/** + * 5. HeapSort + * 自学 https://www.geeksforgeeks.org/heap-sort/ + * + */ + +/** + * 6. 字母异位词分组(亚马逊在半年内面试中常考) + * + */ + +/** + * 7. 二叉树的中序遍历(亚马逊、字节跳动、微软在半年内面试中考过) + * + */ + + +/** + * 8. 二叉树的前序遍历(字节跳动、谷歌、腾讯在半年内面试中考过) + * leetcode- + */ + +/** + * 9. N 叉树的层序遍历(亚马逊在半年内面试中考过) + * easy | leetcode- + */ + + +/** + * 10. 丑数(字节跳动在半年内面试中考过) + * medium | leetcode- + */ + + + +/** + * 11. 前 K 个高频元素(亚马逊在半年内面试中常考) + * + */ From c8213660700fc19986b1b3b7a5819477e7491c07 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 7 Feb 2021 02:05:38 +0800 Subject: [PATCH 014/210] =?UTF-8?q?js=20=E5=AE=9E=E7=8E=B0=E4=BC=98?= =?UTF-8?q?=E5=85=88=E9=98=9F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_02/README.md | 2 +- Week_02/priorityQueue.js | 92 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 Week_02/priorityQueue.js diff --git a/Week_02/README.md b/Week_02/README.md index 8b8ce6ed..1a7abee0 100644 --- a/Week_02/README.md +++ b/Week_02/README.md @@ -3,7 +3,7 @@ 1. [JavaScript 中的 Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) 2. [JS中,Set、Map、WeakSet 和 WeakMap 的区别](https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/6) -+ TODO [JavaScript 实现 PriorityQueue](./priorityQueue.js) ++ [JavaScript 实现 PriorityQueue](./priorityQueue.js) ## 作业 diff --git a/Week_02/priorityQueue.js b/Week_02/priorityQueue.js new file mode 100644 index 00000000..21c1ec49 --- /dev/null +++ b/Week_02/priorityQueue.js @@ -0,0 +1,92 @@ +const top = 0 +const parent = i => ((i+1) >>> 1) - 1 +const left = i => (i << 1) + 1 +const right = i => (i + 1) << 1 + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this._heap = []; + this._comparator = comparator; + } + size() { + return this._heap.length; + } + isEmpty() { + return this.size() == 0; + } + peek() { + return this._heap[top]; + } + push(...values) { + values.forEach(value => { + this._heap.push(value); + this._siftUp(); + }); + return this.size(); + } + pop() { + const poppedValue = this.peek(); + const bottom = this.size() - 1; + if (bottom > top) { + this._swap(top, bottom); + } + this._heap.pop(); + this._siftDown(); + return poppedValue; + } + replace(value) { + const replacedValue = this.peek(); + this._heap[top] = value; + this._siftDown(); + return replacedValue; + } + _greater(i, j) { + return this._comparator(this._heap[i], this._heap[j]); + } + _swap(i, j) { + [this._heap[i], this._heap[j]] = [this._heap[j], this._heap[i]]; + } + _siftUp() { + let node = this.size() - 1; + while (node > top && this._greater(node, parent(node))) { + this._swap(node, parent(node)); + node = parent(node); + } + } + _siftDown() { + let node = top; + while ( + (left(node) < this.size() && this._greater(left(node), node)) || + (right(node) < this.size() && this._greater(right(node), node)) + ) { + let maxChild = (right(node) < this.size() && this._greater(right(node), left(node))) ? right(node) : left(node); + this._swap(node, maxChild); + node = maxChild; + } + } +} + +// test case +var s = new PriorityQueue() +console.log(s.size()) +s.push(56) +s.push(156) +s.push(536) +s.push(456) +s.push(564) +s.push(561) +console.log(s.size(), s.peek()) +console.log('pop:', s.pop()) +console.log(s.size(), s.peek()) +console.log('pop:', s.pop()) +console.log(s.size(), s.peek()) +console.log('pop:', s.pop()) +console.log(s.size(), s.peek()) +console.log('pop:', s.pop()) +console.log(s.size(), s.peek()) +console.log('pop:', s.pop()) +console.log(s.size(), s.peek()) +console.log('pop:', s.pop()) +console.log(s.size(), s.peek()) +console.log('pop:', s.pop()) + From 6ffa1e2afa5b5edd3b2d3bffe5be011161e26b24 Mon Sep 17 00:00:00 2001 From: alwynzhou Date: Sun, 7 Feb 2021 21:22:56 +0800 Subject: [PATCH 015/210] solve tree traversal --- Week_02/homework.js | 157 +++++++++++++++++++++++++++++--------------- 1 file changed, 103 insertions(+), 54 deletions(-) diff --git a/Week_02/homework.js b/Week_02/homework.js index 2adc77c1..d8cb2f3c 100644 --- a/Week_02/homework.js +++ b/Week_02/homework.js @@ -9,73 +9,89 @@ * https://leetcode-cn.com/problems/valid-anagram/submissions/ * 思路1: 排序 O(nlogn) */ -var isAnagram = function(s, t) { - if (s.length !== t.length) return false - var stringSort = function(str){ - return str.split('').sort().join('') - } - return stringSort(s) === stringSort(t) +var isAnagram = function (s, t) { + if (s.length !== t.length) return false; + var stringSort = function (str) { + return str.split("").sort().join(""); + }; + return stringSort(s) === stringSort(t); }; /** 思路2: 用hashmap统计,计数 */ -var isAnagram = function(s, t) { - if (s.length !== t.length) return false - var map = {} - for(var i = 0; i < s.length; ++i) { - if (map[s[i]] === void(0)) { - map[s[i]] = 1 - } else { - ++map[s[i]] - } +var isAnagram = function (s, t) { + if (s.length !== t.length) return false; + var map = {}; + for (var i = 0; i < s.length; ++i) { + if (map[s[i]] === void 0) { + map[s[i]] = 1; + } else { + ++map[s[i]]; + } } - for(var i = 0; i < t.length; ++i) { - if (map[t[i]] === void(0) || map[t[i]] <= 0) { - return false - } else { - --map[t[i]] - } + for (var i = 0; i < t.length; ++i) { + if (map[t[i]] === void 0 || map[t[i]] <= 0) { + return false; + } else { + --map[t[i]]; + } } - for(key in map) { - if (map[key] !== 0) { - return false - } + for (key in map) { + if (map[key] !== 0) { + return false; + } } - return true + return true; }; /** 思路3: 数组记录,增减记数(O(n))trick: charCodeAt */ -var isAnagram = function(s, t) { - if (s.length !== t.length) return false - var arr = Array(26).fill(0) - for(var i = 0; i < s.length; ++i) { - ++arr[s[i].charCodeAt(0) - 'a'.charCodeAt(0)] +var isAnagram = function (s, t) { + if (s.length !== t.length) return false; + var arr = Array(26).fill(0); + for (var i = 0; i < s.length; ++i) { + ++arr[s[i].charCodeAt(0) - "a".charCodeAt(0)]; } - for(var i = 0; i < t.length; ++i) { - --arr[t[i].charCodeAt(0) - 'a'.charCodeAt(0)] + for (var i = 0; i < t.length; ++i) { + --arr[t[i].charCodeAt(0) - "a".charCodeAt(0)]; } - return arr.filter(item => item !== 0).length === 0 + return arr.filter((item) => item !== 0).length === 0; }; /** * 3. 两数之和(近半年内,亚马逊考查此题达到 216 次、字节跳动 147 次、谷歌 104 次,Facebook、苹果、微软、腾讯也在近半年内面试常考) * https://leetcode-cn.com/problems/two-sum/ */ -var twoSum = function(nums, target) { - var hashMap = {} - for(var i = 0; i < nums.length; ++i) { - if (hashMap[nums[i]] === void(0)) { - hashMap[target - nums[i]] = i - } else { - return [hashMap[nums[i]], i] - } +var twoSum = function (nums, target) { + var hashMap = {}; + for (var i = 0; i < nums.length; ++i) { + if (hashMap[nums[i]] === void 0) { + hashMap[target - nums[i]] = i; + } else { + return [hashMap[nums[i]], i]; + } } - return [] + return []; }; /** * 4. N 叉树的前序遍历(亚马逊在半年内面试中考过) - * + * https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/ + * leetcode-589 + * 思路1: 递归 + 闭包函数 */ - - +/** + * @param {Node} root + * @return {number[]} + */ +var preorder = function (root) { + var res = []; + (function (root) { + if (root !== null) { + res.push(root.val) + root.children.forEach(child => { + arguments.callee(child) + }) + } + })(root) + return res +}; /** * 5. HeapSort @@ -90,29 +106,62 @@ var twoSum = function(nums, target) { /** * 7. 二叉树的中序遍历(亚马逊、字节跳动、微软在半年内面试中考过) - * + * https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + * leetcode-94 */ - +var inorderTraversal = function(root) { + var res = [] + ;(function(root) { + if (root !== null) { + arguments.callee(root.left) + res.push(root.val) + arguments.callee(root.right) + } + })(root) + return res +}; /** * 8. 二叉树的前序遍历(字节跳动、谷歌、腾讯在半年内面试中考过) - * leetcode- + * https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ + * leetcode-144 */ +var preorderTraversal = function(root) { + var res = [] + ;(function(root) { + if (root !== null) { + res.push(root.val) + arguments.callee(root.left) + arguments.callee(root.right) + } + })(root) + return res +}; /** * 9. N 叉树的层序遍历(亚马逊在半年内面试中考过) - * easy | leetcode- + * https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/submissions/ + * easy | leetcode-590 */ - +var postorder = function(root) { + var res = [] + ;(function(root) { + if (root !== null) { + root.children.forEach(child => { + arguments.callee(child) + }) + res.push(root.val) + } + })(root) + return res +}; /** * 10. 丑数(字节跳动在半年内面试中考过) * medium | leetcode- */ - - /** * 11. 前 K 个高频元素(亚马逊在半年内面试中常考) - * + * */ From 5584c65168720ca0f69e7744d682e0f07ba562bf Mon Sep 17 00:00:00 2001 From: alwynzhou Date: Sun, 7 Feb 2021 21:57:51 +0800 Subject: [PATCH 016/210] refactor style --- Week_02/homework.js | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Week_02/homework.js b/Week_02/homework.js index d8cb2f3c..c4bfe21e 100644 --- a/Week_02/homework.js +++ b/Week_02/homework.js @@ -109,9 +109,9 @@ var preorder = function (root) { * https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ * leetcode-94 */ -var inorderTraversal = function(root) { - var res = [] - ;(function(root) { +var inorderTraversal = function (root) { + var res = []; + (function (root) { if (root !== null) { arguments.callee(root.left) res.push(root.val) @@ -126,9 +126,9 @@ var inorderTraversal = function(root) { * https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ * leetcode-144 */ -var preorderTraversal = function(root) { - var res = [] - ;(function(root) { +var preorderTraversal = function (root) { + var res = []; + (function (root) { if (root !== null) { res.push(root.val) arguments.callee(root.left) @@ -143,21 +143,22 @@ var preorderTraversal = function(root) { * https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/submissions/ * easy | leetcode-590 */ -var postorder = function(root) { - var res = [] - ;(function(root) { - if (root !== null) { - root.children.forEach(child => { - arguments.callee(child) - }) - res.push(root.val) - } +var postorder = function (root) { + var res = []; + (function (root) { + if (root !== null) { + root.children.forEach(child => { + arguments.callee(child) + }) + res.push(root.val) + } })(root) return res }; /** * 10. 丑数(字节跳动在半年内面试中考过) + * https://leetcode-cn.com/problems/ugly-number/ * medium | leetcode- */ From 20308fe662a81e8065ae7db4971435922bd6d108 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 8 Feb 2021 00:13:00 +0800 Subject: [PATCH 017/210] solve medium 049 --- Week_02/homework.js | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Week_02/homework.js b/Week_02/homework.js index c4bfe21e..2360c45e 100644 --- a/Week_02/homework.js +++ b/Week_02/homework.js @@ -101,8 +101,40 @@ var preorder = function (root) { /** * 6. 字母异位词分组(亚马逊在半年内面试中常考) - * + * https://leetcode-cn.com/problems/group-anagrams/ + * medium | leetcode 049 + */ +/** + * @param {string[]} strs + * @return {string[][]} + * 思路:记录到哈希表中,key值为统计数组toString,value值为字符串数组。最后返回 map 所有的values + */ +/** + * @param {string[]} strs + * @return {string[][]} + * 思路:记录到哈希表中,key值为统计数组toString,value值为字符串数组。最后返回 map 所有的values */ +var groupAnagrams = function(strs) { + if (!Object.prototype.toString.apply(strs) === '[object Array]' + || strs.length < 1 + ) { + return [] + } + + var map = {} + strs.forEach(str => { + var arr = Array(26).fill(0) + str.split('').forEach(ch => { + ++arr[ch.charCodeAt(0) - 'a'.charCodeAt(0)] + }) + if (map[arr.toString()] === void(0)) { + map[arr.toString()] = [str] + } else { + map[arr.toString()].push(str) + } + }) + return Object.values(map) +}; /** * 7. 二叉树的中序遍历(亚马逊、字节跳动、微软在半年内面试中考过) From e961bc0291fe85cc40a1bcbfa13c1d0c18722936 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 8 Feb 2021 00:13:21 +0800 Subject: [PATCH 018/210] solve 283 --- Week_02/283.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Week_02/283.js diff --git a/Week_02/283.js b/Week_02/283.js new file mode 100644 index 00000000..94abc592 --- /dev/null +++ b/Week_02/283.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + * 思路:保证insertPos指针之前的元素是全非零 + */ +var moveZeroes = function (nums) { + var insertPos = 0 + for (var i = 0; i < nums.length; ++i) { + if (nums[i] !== 0) { + nums[insertPos++] = nums[i] + } + } + while (insertPos < nums.length) { + nums[insertPos++] = 0 + } +}; From 0eca4fd317aa78dfa51f46f97ef26f4373256871 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 8 Feb 2021 00:54:28 +0800 Subject: [PATCH 019/210] complete homework --- Week_02/homework.js | 50 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/Week_02/homework.js b/Week_02/homework.js index 2360c45e..3ba7e8eb 100644 --- a/Week_02/homework.js +++ b/Week_02/homework.js @@ -103,15 +103,6 @@ var preorder = function (root) { * 6. 字母异位词分组(亚马逊在半年内面试中常考) * https://leetcode-cn.com/problems/group-anagrams/ * medium | leetcode 049 - */ -/** - * @param {string[]} strs - * @return {string[][]} - * 思路:记录到哈希表中,key值为统计数组toString,value值为字符串数组。最后返回 map 所有的values - */ -/** - * @param {string[]} strs - * @return {string[][]} * 思路:记录到哈希表中,key值为统计数组toString,value值为字符串数组。最后返回 map 所有的values */ var groupAnagrams = function(strs) { @@ -191,10 +182,47 @@ var postorder = function (root) { /** * 10. 丑数(字节跳动在半年内面试中考过) * https://leetcode-cn.com/problems/ugly-number/ - * medium | leetcode- + * easy | leetcode-263 + * 思路: 两重循环,一直判断是否整除2、3、5无余数。最后判断是否得到1 */ +var isUgly = function(num) { + for(var p of [2, 3, 5]) { + while(num && num % p === 0) { + num /= p + } + } + return num === 1 +}; /** * 11. 前 K 个高频元素(亚马逊在半年内面试中常考) - * + * https://leetcode-cn.com/problems/top-k-frequent-elements/ + * medium | leetcode-347 + * 思路1: + * Step1: map统计 O(n) + * Step2: 放入数组 + * Step3: 按照 v 排序 O(nlogn) + * Step4: 取出前k个 */ +var topKFrequent = function(nums, k) { + var map = {} + nums.forEach(num => { + if (map[num] === void(0)) { + map[num] = 1 + } else { + ++map[num] + } + }) + var arr = [] + for(var key in map) { + arr.push([key, map[key]]) + } + arr.sort(function(a, b) { + return b[1] - a[1] + }) + var res = [] + for(var i = 0; i < k; ++i) { + res.push(arr[i][0]) + } + return res +}; From 782d84645b8c0dff1ab454506a6d34418704fb7c Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 8 Feb 2021 01:26:04 +0800 Subject: [PATCH 020/210] week02 homework --- Week_02/homework.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Week_02/homework.js b/Week_02/homework.js index 3ba7e8eb..59daa4da 100644 --- a/Week_02/homework.js +++ b/Week_02/homework.js @@ -1,6 +1,7 @@ /** * 1. 写一个关于HashMap的小总结 - * TODO + * https://time.geekbang.org/column/article/64233 + * 解决散列冲突:1. 开放寻址法(线性探测) 2. 拉链法 */ /** @@ -96,7 +97,10 @@ var preorder = function (root) { /** * 5. HeapSort * 自学 https://www.geeksforgeeks.org/heap-sort/ - * + * 时间复杂度 O(nlogn), 稳定的原地排序 + * https://time.geekbang.org/column/article/69913 + * Step1: 建堆 + * Step2: 排序 */ /** From b936566fd71f8f93921d40be2d277bcbf4f8facd Mon Sep 17 00:00:00 2001 From: alwynzhou Date: Tue, 9 Feb 2021 11:34:21 +0800 Subject: [PATCH 021/210] learn hash map --- Week_02/homework.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Week_02/homework.js b/Week_02/homework.js index 59daa4da..46b66bfc 100644 --- a/Week_02/homework.js +++ b/Week_02/homework.js @@ -1,7 +1,27 @@ /** * 1. 写一个关于HashMap的小总结 * https://time.geekbang.org/column/article/64233 - * 解决散列冲突:1. 开放寻址法(线性探测) 2. 拉链法 + * + * 衡量散列表负载:装载因子 = 已载入元素 / 散列表容量 + * 动态扩容/缩容:(根据 load factor,重新计算,迁移) + * 优化:一次性扩容 -> 均摊扩容 + * + * + * 解决散列冲突: + * 1. 开放寻址法(线性探测) + * - eg: Java 的 ThreadLocalMap + * - 线性探测 + * - 二次探测 + * - 双重散列 + * - (优点:1、因为数据都存储在数组中,可以有效利用CPU cache加快查询速度;2、序列化更简单) + * - (缺点:1、删除需要标记;2、对load factor更敏感、内存利用率更低;) + * - (适合:数据量较小、load factor小) + * 2. 拉链法 + * - eg: Java 的 LinkedHashMap + * - (优点:1、对load factor容忍度更高、内存利用率更高;2、更灵活地支持优化策略,例如红黑树代替链表) + * - (适合:大对象、大数据量) + * + * 散列碰撞攻击 */ /** From aa2fb5484928d443d0e12d06ee68cd997f862cda Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 10 Feb 2021 23:52:02 +0800 Subject: [PATCH 022/210] every day solve leetcode --- Week_03/226.js | 26 ++++++++++++++++++++++++++ Week_03/offer-006.js | 25 +++++++++++++++++++++++++ Week_03/offer-068.js | 24 ++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 Week_03/226.js create mode 100644 Week_03/offer-006.js create mode 100644 Week_03/offer-068.js diff --git a/Week_03/226.js b/Week_03/226.js new file mode 100644 index 00000000..f147a6b4 --- /dev/null +++ b/Week_03/226.js @@ -0,0 +1,26 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + * https://leetcode-cn.com/problems/invert-binary-tree/submissions/ + * 1. 边界条件 + * 2. 交换 + * 3. 递归处理子问题 + * 4. return + */ +/** + * @param {TreeNode} root + * @return {TreeNode} + */ +var invertTree = function(root) { + if (!root) return null + var tmp = root.left + root.left = root.right + root.right = tmp + invertTree(root.left) + invertTree(root.right) + return root +}; diff --git a/Week_03/offer-006.js b/Week_03/offer-006.js new file mode 100644 index 00000000..4c8e5542 --- /dev/null +++ b/Week_03/offer-006.js @@ -0,0 +1,25 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + * easy | https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/ + * 思路:利用stack + */ +/** + * @param {ListNode} head + * @return {number[]} + */ +var reversePrint = function(head) { + var p = head, stack = [] + while(p) { + stack.push(p.val) + p = p.next + } + var res = [] + while(stack.length) { + res.push(stack.pop()) + } + return res +}; diff --git a/Week_03/offer-068.js b/Week_03/offer-068.js new file mode 100644 index 00000000..c8ca40a8 --- /dev/null +++ b/Week_03/offer-068.js @@ -0,0 +1,24 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + * https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/ + * 思路:递归 + */ +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +var lowestCommonAncestor = function(root, p, q) { + if(root === null || root === p || root === q) return root + var left = lowestCommonAncestor(root.left, p, q) + var right = lowestCommonAncestor(root.right, p, q) + // if (left === null && right === null) return null + if (left === null) return right + if (right === null) return left + return root +}; From 50dfa8630166b820d07736a6d1b76ce1513521d6 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 16 Feb 2021 18:59:07 +0800 Subject: [PATCH 023/210] refactor --- .gitignore | 1 + Week_01/README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e43b0f98..162304d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store +note.md diff --git a/Week_01/README.md b/Week_01/README.md index f59b0a35..813f4b7a 100644 --- a/Week_01/README.md +++ b/Week_01/README.md @@ -9,7 +9,7 @@ 备注:skiplist 是有序的,实现简单,维护成本较高,空间复杂度O(n)。 - array | linkedlist | skiplist +array | linkedlist | skiplist prepend O(1) O(1) O(1) append O(1) O(1) O(1) lookup O(1) O(n) O(logn) From 3bc0fd11c3f87420cc474a1b466ce39e34fdc726 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 17 Feb 2021 00:30:52 +0800 Subject: [PATCH 024/210] solve threeSum --- Week_01/015.js | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Week_01/015.js diff --git a/Week_01/015.js b/Week_01/015.js new file mode 100644 index 00000000..543bfd23 --- /dev/null +++ b/Week_01/015.js @@ -0,0 +1,61 @@ +/** + * 015 三数之和 medium + * https://leetcode.com/problems/3sum/ + * 思路: + * 1. 暴力,三重循环(O(n^3)超时) + * 2. hash,两重暴力 + hash + * 3. 夹逼,因为不需要给下标,先排序后夹逼 + */ +// 解法2 O(n^2) +// trick: 用set 和 JSON.stringify 去重 +let threeSum2 = function(nums) { + if (Object.prototype.toString.apply(nums) !== '[object Array]' || nums.length < 3) return [] + nums.sort((a, b) => a - b) + let resSet = new Set(), res = [] + for (let i = 0; i < nums.length - 2; ++i) { + let target = -nums[i], hashmap = {} + for (let j = i + 1; j < nums.length; ++j) { + if (hashmap[nums[j]] === void(0)) { + hashmap[target - nums[j]] = j + } else { + let curItem = [-target, nums[hashmap[nums[j]]], nums[j]] + let sCurItem = JSON.stringify(curItem) + if (!resSet.has(sCurItem)) { + resSet.add(sCurItem) + res.push(curItem) + } + } + } + } + return res +}; + +console.log('solution 1: ', threeSum2([-1,0,1,2,-1,-4])) + +// 解法3 O(n^2) +const threeSum = function(nums) { + if (Object.prototype.toString.apply(nums) !== '[object Array]' || nums.length < 3) return [] + nums.sort((a, b) => a - b) + const res = [] + for (let k = 0; k < nums.length - 2; ++k) { + if (nums[k] > 0) break + if (k > 0 && nums[k] === nums[k - 1]) continue + let i = k + 1, j = nums.length - 1 + while(i < j) { + const sum = nums[k] + nums[i] + nums[j] + if (sum < 0) { + while(i < j && nums[i] === nums[++i]) {} + } else if (sum > 0) { + while(i < j && nums[j] === nums[--j]) {} + } else { + res.push([nums[k], nums[i], nums[j]]) + while(i < j && nums[i] === nums[++i]) {} // 指针移动顺便去重 + while(i < j && nums[j] === nums[--j]) {} // 指针移动顺便去重 + } + } + } + return res +} + +console.log('solution 2: ', threeSum([-1,0,1,2,-1,-4])) +console.log('solution 2: ', threeSum([-2,0,0,2,2])) From 44986764afc398ee330fa499065b9c6206fde1f5 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 17 Feb 2021 01:07:23 +0800 Subject: [PATCH 025/210] solve 011 maxArea --- Week_01/011.js | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Week_01/011.js diff --git a/Week_01/011.js b/Week_01/011.js new file mode 100644 index 00000000..ca2d18d7 --- /dev/null +++ b/Week_01/011.js @@ -0,0 +1,47 @@ +/** + * 011 盛水最多的容器 medium + * https://leetcode-cn.com/problems/container-with-most-water/ + * 思路: + * 1. 暴力枚举 O(n^2) + * 2. 双指针,矮的挪位置 + */ + +// 解法一: O(n^2) +const maxArea1 = function(a) { + if (Object.prototype.toString.apply(a) !== '[object Array]' + || a.length < 2) return 0 + const _getArea = function(a, i, j) { + return (j - i) * Math.min(a[i], a[j]) + } + let max = 0 + for (let i = 0; i < a.length - 1; ++i) { + for (let j = i + 1; j < a.length; ++j) { + const area = _getArea(a, i, j) + max = Math.max(max, area) + } + } + return max +} + +console.log(maxArea1([1,8,6,2,5,4,8,3,7])) +console.log(maxArea1([1,1])) +console.log(maxArea1([4,3,2,1,4])) +console.log(maxArea1([1,2,1])) + +// 解法二: O(n) +const maxArea = function(a) { + if (Object.prototype.toString.apply(a) !== '[object Array]' + || a.length < 2) return 0 + let max = 0 + for(let i = 0, j = a.length - 1; i < j;) { + const minHeight = a[i] < a[j] ? a[i++] : a[j--] + const area = (j - i + 1) * minHeight + max = Math.max(max, area) + } + return max +} + +console.log(maxArea([1,8,6,2,5,4,8,3,7])) +console.log(maxArea([1,1])) +console.log(maxArea([4,3,2,1,4])) +console.log(maxArea([1,2,1])) From c4dcd0fe24022fbf03dcdbea9771c6ae0558510f Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 17 Feb 2021 01:14:14 +0800 Subject: [PATCH 026/210] rename --- Week_01/{001.js => 001twoSum.js} | 14 ++++++------ Week_01/{011.js => 011maxArea.js} | 0 Week_01/{015.js => 015threeSum.js} | 29 ++++++++++++++----------- Week_01/{021.js => 021mergeTwoLists.js} | 27 +++++++++++++---------- Week_01/{024.js => 024swapPairs.js} | 0 Week_01/{066.js => 066plusOne.js} | 0 Week_01/{070.js => 070climbStairs.js} | 0 7 files changed, 38 insertions(+), 32 deletions(-) rename Week_01/{001.js => 001twoSum.js} (52%) rename Week_01/{011.js => 011maxArea.js} (100%) rename Week_01/{015.js => 015threeSum.js} (67%) rename Week_01/{021.js => 021mergeTwoLists.js} (61%) rename Week_01/{024.js => 024swapPairs.js} (100%) rename Week_01/{066.js => 066plusOne.js} (100%) rename Week_01/{070.js => 070climbStairs.js} (100%) diff --git a/Week_01/001.js b/Week_01/001twoSum.js similarity index 52% rename from Week_01/001.js rename to Week_01/001twoSum.js index 969dd25a..b9a392ef 100644 --- a/Week_01/001.js +++ b/Week_01/001twoSum.js @@ -4,14 +4,14 @@ * @param {number} target * @return {number[]} */ -var twoSum = function(nums, target) { +var twoSum = function (nums, target) { var hashMap = {} - for(var i = 0; i < nums.length; ++i) { - if (hashMap[nums[i]] === undefined) { - hashMap[target - nums[i]] = i - } else { - return [hashMap[nums[i]], i] - } + for (var i = 0; i < nums.length; ++i) { + if (hashMap[nums[i]] === undefined) { + hashMap[target - nums[i]] = i + } else { + return [hashMap[nums[i]], i] + } } return [] }; diff --git a/Week_01/011.js b/Week_01/011maxArea.js similarity index 100% rename from Week_01/011.js rename to Week_01/011maxArea.js diff --git a/Week_01/015.js b/Week_01/015threeSum.js similarity index 67% rename from Week_01/015.js rename to Week_01/015threeSum.js index 543bfd23..da0bc15e 100644 --- a/Week_01/015.js +++ b/Week_01/015threeSum.js @@ -8,12 +8,14 @@ */ // 解法2 O(n^2) // trick: 用set 和 JSON.stringify 去重 -let threeSum2 = function(nums) { +let threeSum2 = function (nums) { if (Object.prototype.toString.apply(nums) !== '[object Array]' || nums.length < 3) return [] nums.sort((a, b) => a - b) - let resSet = new Set(), res = [] + let resSet = new Set(), + res = [] for (let i = 0; i < nums.length - 2; ++i) { - let target = -nums[i], hashmap = {} + let target = -nums[i], + hashmap = {} for (let j = i + 1; j < nums.length; ++j) { if (hashmap[nums[j]] === void(0)) { hashmap[target - nums[j]] = j @@ -30,32 +32,33 @@ let threeSum2 = function(nums) { return res }; -console.log('solution 1: ', threeSum2([-1,0,1,2,-1,-4])) +console.log('solution 1: ', threeSum2([-1, 0, 1, 2, -1, -4])) // 解法3 O(n^2) -const threeSum = function(nums) { +const threeSum = function (nums) { if (Object.prototype.toString.apply(nums) !== '[object Array]' || nums.length < 3) return [] nums.sort((a, b) => a - b) const res = [] for (let k = 0; k < nums.length - 2; ++k) { if (nums[k] > 0) break if (k > 0 && nums[k] === nums[k - 1]) continue - let i = k + 1, j = nums.length - 1 - while(i < j) { + let i = k + 1, + j = nums.length - 1 + while (i < j) { const sum = nums[k] + nums[i] + nums[j] if (sum < 0) { - while(i < j && nums[i] === nums[++i]) {} + while (i < j && nums[i] === nums[++i]) {} } else if (sum > 0) { - while(i < j && nums[j] === nums[--j]) {} + while (i < j && nums[j] === nums[--j]) {} } else { res.push([nums[k], nums[i], nums[j]]) - while(i < j && nums[i] === nums[++i]) {} // 指针移动顺便去重 - while(i < j && nums[j] === nums[--j]) {} // 指针移动顺便去重 + while (i < j && nums[i] === nums[++i]) {} // 指针移动顺便去重 + while (i < j && nums[j] === nums[--j]) {} // 指针移动顺便去重 } } } return res } -console.log('solution 2: ', threeSum([-1,0,1,2,-1,-4])) -console.log('solution 2: ', threeSum([-2,0,0,2,2])) +console.log('solution 2: ', threeSum([-1, 0, 1, 2, -1, -4])) +console.log('solution 2: ', threeSum([-2, 0, 0, 2, 2])) diff --git a/Week_01/021.js b/Week_01/021mergeTwoLists.js similarity index 61% rename from Week_01/021.js rename to Week_01/021mergeTwoLists.js index 7889f406..f4c64994 100644 --- a/Week_01/021.js +++ b/Week_01/021mergeTwoLists.js @@ -12,18 +12,21 @@ * 21. 合并两个有序链表 * 思路: 声明一个空指针头,遍历l1 和 l2,谁的值比较小就把谁拼接在后面 */ -var mergeTwoLists = function(l1, l2) { - var dummy = { val: -1, next: null }, - cur = dummy - while(l1 && l2) { - if (l1.val < l2.val) { - cur.next = l1 - l1 = l1.next - } else { - cur.next = l2 - l2 = l2.next - } - cur = cur.next +var mergeTwoLists = function (l1, l2) { + var dummy = { + val: -1, + next: null + }, + cur = dummy + while (l1 && l2) { + if (l1.val < l2.val) { + cur.next = l1 + l1 = l1.next + } else { + cur.next = l2 + l2 = l2.next + } + cur = cur.next } cur.next = l1 || l2 return dummy.next diff --git a/Week_01/024.js b/Week_01/024swapPairs.js similarity index 100% rename from Week_01/024.js rename to Week_01/024swapPairs.js diff --git a/Week_01/066.js b/Week_01/066plusOne.js similarity index 100% rename from Week_01/066.js rename to Week_01/066plusOne.js diff --git a/Week_01/070.js b/Week_01/070climbStairs.js similarity index 100% rename from Week_01/070.js rename to Week_01/070climbStairs.js From 30b61475bd3b05da7095037e3135256936dbb4f5 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 17 Feb 2021 01:47:43 +0800 Subject: [PATCH 027/210] refactor --- Week_01/001twoSum.js | 5 + Week_01/021mergeTwoLists.js | 5 + Week_01/026removeDuplicates.js | 17 +++ Week_01/042trap.js | 28 ++++ Week_01/066plusOne.js | 5 + Week_01/088merge.js | 19 +++ Week_01/189rotate.js | 25 ++++ Week_01/283moveZeros.js | 20 +++ Week_01/641MyCircularDeque.js | 58 ++++++++ Week_01/homework.js | 243 --------------------------------- Week_01/homework.md | 44 ++++++ 11 files changed, 226 insertions(+), 243 deletions(-) create mode 100644 Week_01/026removeDuplicates.js create mode 100644 Week_01/042trap.js create mode 100644 Week_01/088merge.js create mode 100644 Week_01/189rotate.js create mode 100644 Week_01/283moveZeros.js create mode 100644 Week_01/641MyCircularDeque.js delete mode 100644 Week_01/homework.js create mode 100644 Week_01/homework.md diff --git a/Week_01/001twoSum.js b/Week_01/001twoSum.js index b9a392ef..b2d7f8ed 100644 --- a/Week_01/001twoSum.js +++ b/Week_01/001twoSum.js @@ -1,3 +1,8 @@ +/** + * 7. 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) + * leetcode-001 + * https://leetcode-cn.com/problems/two-sum/ + */ /** * 思路:类似去婚姻登记所找另一半,如果没找到匹配对象,就利用哈希表登记下;找到了就ok。 * @param {number[]} nums diff --git a/Week_01/021mergeTwoLists.js b/Week_01/021mergeTwoLists.js index f4c64994..1aa864ff 100644 --- a/Week_01/021mergeTwoLists.js +++ b/Week_01/021mergeTwoLists.js @@ -1,3 +1,8 @@ +/** + * easy | leetcode-021 | link-list + * https://leetcode-cn.com/problems/merge-two-sorted-lists/ + * 思路: 类似归并排序的归并过程 + */ /** * Definition for singly-linked list. * function ListNode(val, next) { diff --git a/Week_01/026removeDuplicates.js b/Week_01/026removeDuplicates.js new file mode 100644 index 00000000..ce598981 --- /dev/null +++ b/Week_01/026removeDuplicates.js @@ -0,0 +1,17 @@ +/** + * 3. 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) + * easy | leetcode-026 | array + * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ + * 思路:利用数组是有序的特性,重复元素必相邻。遍历一轮,用cnt记录重复项数量,用第i个元素覆盖i-cnt个元素 + */ +var removeDuplicates = function (nums) { + var cnt = 0; + for (var i = 1; i < nums.length; ++i) { + if (nums[i] === nums[i - 1]) { + cnt++ + } else { + nums[i - cnt] = nums[i] + } + } + return nums.length - cnt +}; diff --git a/Week_01/042trap.js b/Week_01/042trap.js new file mode 100644 index 00000000..adbc435b --- /dev/null +++ b/Week_01/042trap.js @@ -0,0 +1,28 @@ +/** + * 11. 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) + * hard | leetcode-042 | array + * https://leetcode.com/problems/trapping-rain-water/ + * 思路: maxLeft、maxRight 记录左右最高柱子 + */ +var trap = function (A) { + var left = 0, right = A.length - 1 + var res = 0, maxLeft = 0, maxRight = 0 + while (left < right) { + if (A[left] <= A[right]) { + if (A[left] >= maxLeft) { + maxLeft = A[left] + } else { + res += maxLeft - A[left] + } + ++left + } else { + if (A[right] >= maxRight) { + maxRight = A[right] + } else { + res += maxRight - A[right] + } + --right + } + } + return res +}; diff --git a/Week_01/066plusOne.js b/Week_01/066plusOne.js index 3599db89..a8c51068 100644 --- a/Week_01/066plusOne.js +++ b/Week_01/066plusOne.js @@ -1,3 +1,8 @@ +/** + * 9. 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) + * easy | leetcode-066 | array + * https://leetcode-cn.com/problems/plus-one/ + */ /** * 思路:从右往左遍历,遇9进位 * @param {number[]} digits diff --git a/Week_01/088merge.js b/Week_01/088merge.js new file mode 100644 index 00000000..0d9302c5 --- /dev/null +++ b/Week_01/088merge.js @@ -0,0 +1,19 @@ +/** + * 6. 合并两个有序数组(Facebook 在半年内面试常考) + * easy | leetcode-088 | array + * https://leetcode-cn.com/problems/merge-sorted-array/ + */ +var merge = function(nums1, m, nums2, n) { + var 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--] + } + } + while(j >= 0) { + nums1[k--] = nums2[j--] + } + return nums1 +}; diff --git a/Week_01/189rotate.js b/Week_01/189rotate.js new file mode 100644 index 00000000..8001483f --- /dev/null +++ b/Week_01/189rotate.js @@ -0,0 +1,25 @@ +/** + * 4. 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) + * medium | leetcode-189 | array + * https://leetcode-cn.com/problems/rotate-array/ + * 思路:反转三次,时间复杂度O(n), 空间复杂度O(1) + */ +// var rotate = function(nums, k) { +// var gap = nums.length - k +// nums = nums.slice(gap).concat(nums.slice(0, gap)) +// return nums +// }; +// O(1)空间复杂度解法: 反转3次 +var rotate = function(nums, k) { + var reverse = function(nums, start, end) { + while(start < end) { + var tmp = nums[start] + nums[start++] = nums[end] + nums[end--] = tmp + } + } + k %= nums.length + reverse(nums, 0, nums.length - 1) + reverse(nums, 0, k - 1) + reverse(nums, k, nums.length - 1) +}; diff --git a/Week_01/283moveZeros.js b/Week_01/283moveZeros.js new file mode 100644 index 00000000..d6f143b1 --- /dev/null +++ b/Week_01/283moveZeros.js @@ -0,0 +1,20 @@ +/* + * leetcode-283 | + * https://leetcode-cn.com/problems/move-zeroes/ + * 思路: 用一个标记记录非0的位置 + */ + +var moveZeroes = function (nums) { + var swap = function (nums, i, j) { + var tmp = nums[i] + nums[i] = nums[j] + nums[j] = tmp + } + + for (var i = 0, j = 0; i < nums.length; ++i) { + if (nums[i] !== 0) { + swap(nums, i, j++) + } + } + return nums +}; diff --git a/Week_01/641MyCircularDeque.js b/Week_01/641MyCircularDeque.js new file mode 100644 index 00000000..e3904892 --- /dev/null +++ b/Week_01/641MyCircularDeque.js @@ -0,0 +1,58 @@ +/** + * 10. 设计循环双端队列(Facebook 在 1 年内面试中考过) + * medium | leetcode-641 | deque + * https://leetcode-cn.com/problems/design-circular-deque/?utm_source=LCUS&utm_medium=ip_redirect&utm_campaign=transfer2china + * 思路: js的array完全是超集,约束下 length 可以很简单实现 + */ + +var MyCircularDeque = function(k) { + this.queue = new Array() + this.length = k +}; + +MyCircularDeque.prototype.insertFront = function(value) { + if (this.queue.length < this.length) { + this.queue.unshift(value) + return true + } + return false +}; +MyCircularDeque.prototype.insertLast = function(value) { + if (this.queue.length < this.length) { + this.queue.push(value) + return true + } + return false +}; +MyCircularDeque.prototype.deleteFront = function() { + if (this.queue.length > 0) { + this.queue.shift() + return true + } + return false +}; +MyCircularDeque.prototype.deleteLast = function() { + if (this.queue.length > 0) { + this.queue.pop() + return true + } + return false +}; +MyCircularDeque.prototype.getFront = function() { + if (this.queue.length === 0) { + return -1 + } + return this.queue[0] +}; +MyCircularDeque.prototype.getRear = function() { + if (this.queue.length === 0) { + return -1 + } + return this.queue[this.queue.length - 1] +}; +MyCircularDeque.prototype.isEmpty = function() { + return this.queue.length === 0 +}; +MyCircularDeque.prototype.isFull = function() { + return this.queue.length === this.length +}; diff --git a/Week_01/homework.js b/Week_01/homework.js deleted file mode 100644 index 9c297561..00000000 --- a/Week_01/homework.js +++ /dev/null @@ -1,243 +0,0 @@ -/** - * 1. 用 add first 或 add last 这套新的 API 改写 Deque 的代码 - * 双端队列 deque - */ - -/** - * 2. 分析 Queue 和 Priority Queue 的源码 - * 队列:http://fuseyism.com/classpath/doc/java/util/Queue-source.html - * 优先队列:https://docs.oracle.com/javase/10/docs/api/java/util/PriorityQueue.html - */ - -/** - * 3. 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) - * easy | leetcode-026 | array - * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ - * 思路:利用数组是有序的特性,重复元素必相邻。遍历一轮,用cnt记录重复项数量,用第i个元素覆盖i-cnt个元素 - */ -var removeDuplicates = function(nums) { - var cnt = 0; - for(var i = 1; i < nums.length; ++i) { - if (nums[i] === nums[i - 1]) { - cnt++ - } else { - nums[i - cnt] = nums[i] - } - } - return nums.length - cnt -}; - -/** - * 4. 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) - * medium | leetcode-189 | array - * https://leetcode-cn.com/problems/rotate-array/ - * 思路:反转三次,时间复杂度O(n), 空间复杂度O(1) - */ -// var rotate = function(nums, k) { -// var gap = nums.length - k -// nums = nums.slice(gap).concat(nums.slice(0, gap)) -// return nums -// }; -// O(1)空间复杂度解法: 反转3次 -var rotate = function(nums, k) { - var reverse = function(nums, start, end) { - while(start < end) { - var tmp = nums[start] - nums[start++] = nums[end] - nums[end--] = tmp - } - } - k %= nums.length - reverse(nums, 0, nums.length - 1) - reverse(nums, 0, k - 1) - reverse(nums, k, nums.length - 1) -}; - -/** - * 5. 合并两个有序链表(亚马逊、字节跳动在半年内面试常考) - * easy | leetcode-021 | link-list - * https://leetcode-cn.com/problems/merge-two-sorted-lists/ - * 思路: 类似归并排序的归并过程 - */ -var mergeTwoLists = function(l1, l2) { - var dummyHead = {val: -1, next: null}, p = dummyHead - while(l1 && l2) { - if (l1.val <= l2.val) { - p.next = l1 - l1 = l1.next - } else { - p.next = l2 - l2 = l2.next - } - p = p.next - } - p.next = l1 || l2 - return dummyHead.next -}; - -/** - * 6. 合并两个有序数组(Facebook 在半年内面试常考) - * easy | leetcode-088 | array - * https://leetcode-cn.com/problems/merge-sorted-array/ - */ -var merge = function(nums1, m, nums2, n) { - var 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--] - } - } - while(j >= 0) { - nums1[k--] = nums2[j--] - } - return nums1 -}; - - -/** - * 7. 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) - * leetcode-001 - * https://leetcode-cn.com/problems/two-sum/ - */ -var twoSum = function (nums, target) { - var hashMap = {} - for (var i = 0; i < nums.length; ++i) { - if (hashMap[nums[i]] === void(0)) { - hashMap[target- nums[i]] = i - } else { - return [hashMap[nums[i]], i] - } - } - return [] -}; - -/** - * 8. 移动零(Facebook、亚马逊、苹果在半年内面试中考过) - * leetcode-283 | - * https://leetcode-cn.com/problems/move-zeroes/ - * 思路: 用一个标记记录非0的位置 - */ -var moveZeroes = function(nums) { - var swap = function(nums, i, j) { - var tmp = nums[i] - nums[i] = nums[j] - nums[j] = tmp - } - -for (var i = 0, j = 0; i < nums.length; ++i) { - if (nums[i] !== 0) { - swap(nums, i, j++) - } -} -return nums -}; - -/** - * 9. 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) - * easy | leetcode-066 | array - * https://leetcode-cn.com/problems/plus-one/ - */ -var plusOne = function(digits) { - for (var i = digits.length - 1; i >= 0; --i) { - if (digits[i] < 9) { - ++digits[i] - break - } else { - digits[i] = 0 - if (i === 0) { - digits.unshift(1) - } - } - } - return digits -}; - -/** - * 10. 设计循环双端队列(Facebook 在 1 年内面试中考过) - * medium | leetcode-641 | deque - * https://leetcode-cn.com/problems/design-circular-deque/?utm_source=LCUS&utm_medium=ip_redirect&utm_campaign=transfer2china - * 思路: js的array完全是超集,约束下 length 可以很简单实现 - */ -var MyCircularDeque = function(k) { - this.queue = new Array() - this.length = k -}; - -MyCircularDeque.prototype.insertFront = function(value) { - if (this.queue.length < this.length) { - this.queue.unshift(value) - return true - } - return false -}; -MyCircularDeque.prototype.insertLast = function(value) { - if (this.queue.length < this.length) { - this.queue.push(value) - return true - } - return false -}; -MyCircularDeque.prototype.deleteFront = function() { - if (this.queue.length > 0) { - this.queue.shift() - return true - } - return false -}; -MyCircularDeque.prototype.deleteLast = function() { - if (this.queue.length > 0) { - this.queue.pop() - return true - } - return false -}; -MyCircularDeque.prototype.getFront = function() { - if (this.queue.length === 0) { - return -1 - } - return this.queue[0] -}; -MyCircularDeque.prototype.getRear = function() { - if (this.queue.length === 0) { - return -1 - } - return this.queue[this.queue.length - 1] -}; -MyCircularDeque.prototype.isEmpty = function() { - return this.queue.length === 0 -}; -MyCircularDeque.prototype.isFull = function() { - return this.queue.length === this.length -}; - - -/** - * 11. 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) - * hard | leetcode-042 | array - * https://leetcode.com/problems/trapping-rain-water/ - * 思路: maxLeft、maxRight 记录左右最高柱子 - */ -var trap = function(A) { - var left = 0, right = A.length - 1 - var res = 0, maxLeft = 0, maxRight = 0 - while (left < right) { - if (A[left] <= A[right]) { - if (A[left] >= maxLeft) { - maxLeft = A[left] - } else { - res += maxLeft - A[left] - } - ++left - } else { - if (A[right] >= maxRight) { - maxRight = A[right] - } else { - res += maxRight - A[right] - } - --right - } - } - return res -}; diff --git a/Week_01/homework.md b/Week_01/homework.md new file mode 100644 index 00000000..05deb4a1 --- /dev/null +++ b/Week_01/homework.md @@ -0,0 +1,44 @@ +# 作业 + +## 1. 用 add first 或 add last 这套新的 API 改写 Deque 的代码 + +## 2. 分析 Queue 和 Priority Queue 的源码 + +> [队列](http://fuseyism.com/classpath/doc/java/util/Queue-source.html) +> [优先队列](https://docs.oracle.com/javase/10/docs/api/java/util/PriorityQueue.html) + +## 3. 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) + +[实现代码](./026removeDuplicates.js) + +## 4. 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) + +[实现代码](./189rotate.js) + +## 5. 合并两个有序链表(亚马逊、字节跳动在半年内面试常考) + +[实现代码](./021mergeTwoLists.js) + +## 6. 合并两个有序数组(Facebook 在半年内面试常考) + +[实现代码](./088merge.js) + +## 7. 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) + +[实现代码](./001twoSum.js) + +## 8. 移动零(Facebook、亚马逊、苹果在半年内面试中考过) + +[实现代码](./283moveZeros.js) + +## 9. 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) + +[实现代码](./066plusOne.js) + +## 10. 设计循环双端队列(Facebook 在 1 年内面试中考过) + +[实现代码](./641MyCircularDeque.js) + +## 11. 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) + +[实现代码](./042trap.js) From b8c5ad501921f605c7ea0764fef3117297ed9c9d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 17 Feb 2021 16:36:54 +0800 Subject: [PATCH 028/210] refactor --- .editorconfig | 5 ++++ Week_01/README.md | 30 +++++----------------- Week_02/README.md | 61 +++++++++++++++++++++++++++++++++++++++++---- Week_02/homework.js | 26 ------------------- 4 files changed, 67 insertions(+), 55 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..7053c49a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +[*.{js,jsx,ts,tsx,vue}] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/Week_01/README.md b/Week_01/README.md index 813f4b7a..c4cb027e 100644 --- a/Week_01/README.md +++ b/Week_01/README.md @@ -1,6 +1,6 @@ # 学习笔记 -## 听课笔记 +## 第3课:数组、链表、跳表 > [Java.util.ArrayList](http://developer.classpath.org/doc/java/util/ArrayList-source.html) > [Java.util.LinkedList](http://developer.classpath.org/doc/java/util/LinkedList-source.html) @@ -16,27 +16,9 @@ lookup O(1) O(n) O(logn) insert O(n) O(1) O(logn) delete O(n) O(1) O(logn) -## 作业 +## 第4课:栈、队列、优先队列、双端队列 -**easy** - -+ 用 add first 或 add last 这套新的 API 改写 Deque 的代码 -+ 分析 Queue 和 Priority Queue 的源码 - -大致过了一下 API,平时主要用JavaScript,不太熟悉Java。 - -+ 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) -+ 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) -+ 合并两个有序链表(亚马逊、字节跳动在半年内面试常考) -+ 合并两个有序数组(Facebook 在半年内面试常考) -+ 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) -+ 移动零(Facebook、亚马逊、苹果在半年内面试中考过) -+ 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) - -**medium** - -+ 设计循环双端队列(Facebook 在 1 年内面试中考过) - -**hard** - -+ 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) ++ stack FILO ++ queue FIFO ++ priorityQueue (heap) ++ deque diff --git a/Week_02/README.md b/Week_02/README.md index 1a7abee0..0b3f6b80 100644 --- a/Week_02/README.md +++ b/Week_02/README.md @@ -1,10 +1,61 @@ -学习笔记 +# 学习笔记 -1. [JavaScript 中的 Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) -2. [JS中,Set、Map、WeakSet 和 WeakMap 的区别](https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/6) +## 第5课:哈希表、映射、集合 + +### 哈希表总结 + +1. 写一个关于HashMap的小总结 + +> 资料:https://time.geekbang.org/column/article/64233 + ++ 衡量散列表负载:装载因子 = 已载入元素 / 散列表容量 ++ 动态扩容/缩容:(根据 load factor,重新计算,迁移) ++ 优化:一次性扩容 -> 均摊扩容 + +**解决散列冲突:** +1. 开放寻址法(线性探测) + - eg: Java 的 ThreadLocalMap + - 线性探测 + - 二次探测 + - 双重散列 + - (优点:1、因为数据都存储在数组中,可以有效利用CPU cache加快查询速度;2、序列化更简单) + - (缺点:1、删除需要标记;2、对load factor更敏感、内存利用率更低;) + - (适合:数据量较小、load factor小) +2. 拉链法 + - eg: Java 的 LinkedHashMap + - (优点:1、对load factor容忍度更高、内存利用率更高;2、更灵活地支持优化策略,例如红黑树代替链表) + - (适合:大对象、大数据量) + +> 一种攻击手段:散列碰撞攻击 + +### [JS中,Set、Map、WeakSet 和 WeakMap 的区别](https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/6) + +**Set** + +1. 成员不能重复 +2. 只有健值,没有健名,有点类似数组 +3. 可以遍历,方法有add, delete, has + +**weakSet** + +1. 成员都是对象 +2. 成员都是弱引用,随时可以消失。 可以用来保存DOM节点,不容易造成内存泄漏 +3. 不能遍历,方法有add, delete, has + +**Map** + +1. 本质上是健值对的集合,类似集合 +2. 可以遍历,方法很多,可以干跟各种数据格式转换 + +**weakMap** + +1. 直接受对象作为健名(null除外),不接受其他类型的值作为健名 +2. 健名所指向的对象,不计入垃圾回收机制 +3. 不能遍历,方法同 get, set, delete, has + [JavaScript 实现 PriorityQueue](./priorityQueue.js) -## 作业 +## 第6课:树、二叉树、二叉搜索树 + +## 第6课:堆和二叉堆、图 -[week02 作业](./homework.js) diff --git a/Week_02/homework.js b/Week_02/homework.js index 46b66bfc..c95682b6 100644 --- a/Week_02/homework.js +++ b/Week_02/homework.js @@ -1,29 +1,3 @@ -/** - * 1. 写一个关于HashMap的小总结 - * https://time.geekbang.org/column/article/64233 - * - * 衡量散列表负载:装载因子 = 已载入元素 / 散列表容量 - * 动态扩容/缩容:(根据 load factor,重新计算,迁移) - * 优化:一次性扩容 -> 均摊扩容 - * - * - * 解决散列冲突: - * 1. 开放寻址法(线性探测) - * - eg: Java 的 ThreadLocalMap - * - 线性探测 - * - 二次探测 - * - 双重散列 - * - (优点:1、因为数据都存储在数组中,可以有效利用CPU cache加快查询速度;2、序列化更简单) - * - (缺点:1、删除需要标记;2、对load factor更敏感、内存利用率更低;) - * - (适合:数据量较小、load factor小) - * 2. 拉链法 - * - eg: Java 的 LinkedHashMap - * - (优点:1、对load factor容忍度更高、内存利用率更高;2、更灵活地支持优化策略,例如红黑树代替链表) - * - (适合:大对象、大数据量) - * - * 散列碰撞攻击 - */ - /** * 2. 有效字母的异位词(亚马逊、Facebook、谷歌在半年内面试中考过) * leetcode-242 | easy From 27684622acb7f815ade0b4d17c56f4d18cb62b83 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 17 Feb 2021 16:46:57 +0800 Subject: [PATCH 029/210] week03 homework --- Week_03/046permute.js | 0 Week_03/047permuteUnique.js | 0 Week_03/077combine.js | 0 Week_03/105buildTree.js | 0 Week_03/236lowestCommonAncestor.js | 21 +++++++++++++++++++++ Week_03/homework.md | 21 +++++++++++++++++++++ 6 files changed, 42 insertions(+) create mode 100644 Week_03/046permute.js create mode 100644 Week_03/047permuteUnique.js create mode 100644 Week_03/077combine.js create mode 100644 Week_03/105buildTree.js create mode 100644 Week_03/236lowestCommonAncestor.js create mode 100644 Week_03/homework.md diff --git a/Week_03/046permute.js b/Week_03/046permute.js new file mode 100644 index 00000000..e69de29b diff --git a/Week_03/047permuteUnique.js b/Week_03/047permuteUnique.js new file mode 100644 index 00000000..e69de29b diff --git a/Week_03/077combine.js b/Week_03/077combine.js new file mode 100644 index 00000000..e69de29b diff --git a/Week_03/105buildTree.js b/Week_03/105buildTree.js new file mode 100644 index 00000000..e69de29b diff --git a/Week_03/236lowestCommonAncestor.js b/Week_03/236lowestCommonAncestor.js new file mode 100644 index 00000000..8dc4ed7d --- /dev/null +++ b/Week_03/236lowestCommonAncestor.js @@ -0,0 +1,21 @@ +/** + * medium + * https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/ + */ + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +var lowestCommonAncestor = function(root, p, q) { + +}; diff --git a/Week_03/homework.md b/Week_03/homework.md new file mode 100644 index 00000000..b743c8e4 --- /dev/null +++ b/Week_03/homework.md @@ -0,0 +1,21 @@ +# 作业 + +## 1. 二叉树的最近公共祖先(Facebook 在半年内面试常考) + +[实现代码](./236lowestCommonAncestor.js) + +## 2. 从前序与中序遍历序列构造二叉树(字节跳动、亚马逊、微软在半年内面试中考过) + +[实现代码](./105buildTree.js) + +## 3. 组合(微软、亚马逊、谷歌在半年内面试中考过) + +[实现代码](./077combine.js) + +## 4. 全排列(字节跳动在半年内面试常考) + +[实现代码](./046permute.js) + +## 5. 全排列 II (亚马逊、字节跳动、Facebook 在半年内面试中考过) + +[实现代码](./047permuteUnique.js) From 0a1503b798ebcd8d6df3de4fce6633c496965145 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 17 Feb 2021 17:26:05 +0800 Subject: [PATCH 030/210] solve 022 & 070 --- Week_03/022generateParenthesis.js | 39 +++++++++++++++++++++++++++++++ Week_03/070climbStairs.js | 17 ++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 Week_03/022generateParenthesis.js create mode 100644 Week_03/070climbStairs.js diff --git a/Week_03/022generateParenthesis.js b/Week_03/022generateParenthesis.js new file mode 100644 index 00000000..a4f638b3 --- /dev/null +++ b/Week_03/022generateParenthesis.js @@ -0,0 +1,39 @@ +/** + * medium + * https://leetcode-cn.com/problems/generate-parentheses/ + * @param {number} n + * @return {string[]} + * 思路:递归、辅助函数、剪枝 + */ +const generateParenthesis = function(n) { + /** + * 辅助函数 + * @param {Number} left 当前左括号的个数 + * @param {Number} right 当前右括号的个数 + * @param {Number} n 括号配额 + * @param {String} s 当前子问题的生成结果 + */ + const _generate = function(left, right, n, s) { + // terminator + if (left === n && right === n) { + res.push(s) + return null + } + // process + // drill down + if (left < n) { + _generate(left + 1, right, n, s + '(') + } + if (right < left) { + _generate(left, right + 1, n, s + ')') + } + // reverse states + } + + const res = [] + _generate(0, 0, n, '') + return res +}; + +// ---- test case ---- +console.log(generateParenthesis(3)) diff --git a/Week_03/070climbStairs.js b/Week_03/070climbStairs.js new file mode 100644 index 00000000..4f9893b0 --- /dev/null +++ b/Week_03/070climbStairs.js @@ -0,0 +1,17 @@ +/** + * https://leetcode-cn.com/problems/climbing-stairs/ + * @param {number} n + * @return {number} + */ +// 思路:fibnacci f(n) = f(n-1) + f(n-2) +var climbStairs = function(n) { + if (typeof n !== 'number') return 0 + if (n < 3) return n + let f1 = 1, f2 = 2, f3 = 3 + for(let i = 3; i <= n; ++i) { + f3 = f1 + f2 + f1 = f2 + f2 = f3 + } + return f3 +}; From 0f1f46f04f0ac0f20266a25022d61d6993b19261 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 17 Feb 2021 17:29:12 +0800 Subject: [PATCH 031/210] refactor rename --- Week_03/{226.js => 226invertTree.js} | 12 ++++++++---- Week_03/README.md | 13 ++++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) rename Week_03/{226.js => 226invertTree.js} (80%) diff --git a/Week_03/226.js b/Week_03/226invertTree.js similarity index 80% rename from Week_03/226.js rename to Week_03/226invertTree.js index f147a6b4..fd534bde 100644 --- a/Week_03/226.js +++ b/Week_03/226invertTree.js @@ -6,21 +6,25 @@ * this.right = (right===undefined ? null : right) * } * https://leetcode-cn.com/problems/invert-binary-tree/submissions/ - * 1. 边界条件 - * 2. 交换 - * 3. 递归处理子问题 - * 4. return + * 1. terminator + * 2. process + * 3. drill down + * 4. reverse states */ /** * @param {TreeNode} root * @return {TreeNode} */ var invertTree = function(root) { + // terminator if (!root) return null + // process var tmp = root.left root.left = root.right root.right = tmp + // drill down invertTree(root.left) invertTree(root.right) + // reverse states return root }; diff --git a/Week_03/README.md b/Week_03/README.md index 50de3041..5cfc468f 100644 --- a/Week_03/README.md +++ b/Week_03/README.md @@ -1 +1,12 @@ -学习笔记 \ No newline at end of file +## 学习笔记 + +## 第7课:泛型递归、树的递归 + +**递归模版** + +1. terminator +2. process +3. drill down +4. reverse states + +## 第8课:分治、回溯 From 2b5c5e3fa168ae3c21f710e9473cea6ea7f89833 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 17 Feb 2021 18:01:46 +0800 Subject: [PATCH 032/210] divide conquer --- Week_03/050myPow.js | 24 ++++++++++++++++++++++++ Week_03/README.md | 32 +++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 Week_03/050myPow.js diff --git a/Week_03/050myPow.js b/Week_03/050myPow.js new file mode 100644 index 00000000..54e3c61c --- /dev/null +++ b/Week_03/050myPow.js @@ -0,0 +1,24 @@ +/** + * medium + * https://leetcode-cn.com/problems/powx-n/ + * @param {number} x + * @param {number} n + * @return {number} + * 思路:自顶向下迭代,遇到奇数扩大为 x * x ^ 2, 遇到偶数扩大为 x ^ 2 + */ +const myPow = function(x, n) { + if (n < 0) return 1.0 / myPow(x, -n) + let res = 1.0 + for(let i = n; i != 0; i = Math.floor(i / 2)) { + if (i % 2 !== 0) { + res *= x + } + x *= x + } + return res +} + +// ---- test case ---- +console.log(myPow(2.0, 10)) +console.log(myPow(2.1, 3)) +console.log(myPow(2.0, -2)) diff --git a/Week_03/README.md b/Week_03/README.md index 5cfc468f..ccebdab2 100644 --- a/Week_03/README.md +++ b/Week_03/README.md @@ -7,6 +7,36 @@ 1. terminator 2. process 3. drill down -4. reverse states +4. revert states ## 第8课:分治、回溯 + +**分治模版** + +1. recursion terminator +2. process logic in current level +3. drill down +4. merge results +5. revert the current level status if needed + +```js +const divide_conquer = (problem, params) => { + // terminator + if (problem == null) { + process_result + return + } + // process current problem + subproblems = split_problem(problem, data) + subresult1 = divide_conquer(subproblem[0], p1) + subresult2 = divide_conquer(subproblem[1], p1) + ... + subresultn = divide_conquer(subproblem[2], p1) + // merge + result = process_result(subresult1, rubresult2, ..., subresultn) + // revert the current level status +} +``` + +**回溯(backtracing)** + From 2cdd2e891a1a2f188d6571c7b9ef45a275f017e6 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 17 Feb 2021 23:34:04 +0800 Subject: [PATCH 033/210] solve --- Week_03/098isValidBST.js | 32 ++++++++++++++++++++++++++++++++ Week_03/104maxDepth.js | 23 +++++++++++++++++++++++ Week_03/111minDepth.js | 32 ++++++++++++++++++++++++++++++++ Week_03/169majorityElement.js | 23 +++++++++++++++++++++++ Week_03/226invertTree.js | 10 +++++----- 5 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 Week_03/098isValidBST.js create mode 100644 Week_03/104maxDepth.js create mode 100644 Week_03/111minDepth.js create mode 100644 Week_03/169majorityElement.js diff --git a/Week_03/098isValidBST.js b/Week_03/098isValidBST.js new file mode 100644 index 00000000..90531604 --- /dev/null +++ b/Week_03/098isValidBST.js @@ -0,0 +1,32 @@ +/** + * https://leetcode-cn.com/problems/validate-binary-search-tree/ + * 思路: + * 分治法,左子树全小于根结点,右子树全大于根结点 + * 构造辅助函数,扩展参数 lower(下界) 和 upper(上界) + */ + +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {boolean} + */ +const isValidBST = function(root) { + function helper(root, lower, upper) { + // terminator + if (root == null) return true + // process + if (root.val <= lower || root.val >= upper) return false + // drill down + return helper(root.left, lower, root.val) && helper(root.right, root.val, upper) + // revert states + } + + return helper(root, -Infinity, Infinity) +} diff --git a/Week_03/104maxDepth.js b/Week_03/104maxDepth.js new file mode 100644 index 00000000..12bb76b1 --- /dev/null +++ b/Week_03/104maxDepth.js @@ -0,0 +1,23 @@ +/** + * https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/ + * 思路: 递归 + * + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const maxDepth = function(root) { + // terminator + if (root == null) return 0 + // process + return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1 + // drill down + // revert states +} diff --git a/Week_03/111minDepth.js b/Week_03/111minDepth.js new file mode 100644 index 00000000..96166218 --- /dev/null +++ b/Week_03/111minDepth.js @@ -0,0 +1,32 @@ +/** + * https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/ + * 思路: 递归 + * + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const minDepth = function(root) { + // terminator + if(root == null) return 0 + // process + if (root.left == null && root.right == null) return 1 + // drill down + const dLeft = minDepth(root.left) + const dRight = minDepth(root.right) + // revert states + if (root.left == null) { + return dRight + 1 + } else if (root.right == null) { + return dLeft + 1 + } else { + return Math.min(dLeft, dRight) + 1 + } +} diff --git a/Week_03/169majorityElement.js b/Week_03/169majorityElement.js new file mode 100644 index 00000000..b5fe3f20 --- /dev/null +++ b/Week_03/169majorityElement.js @@ -0,0 +1,23 @@ +/** + * https://leetcode-cn.com/problems/majority-element/ + * 思路: 计数法 + * + * @param {number[]} nums + * @return {number} + */ +var majorityElement = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return 0 + let res = nums[0], cnt = 1 + for(let i = 1; i < nums.length; ++i) { + if (nums[i] === res) { + ++cnt + } else { + --cnt + if (cnt < 0) { + res = nums[i] + cnt = 1 + } + } + } + return res +}; diff --git a/Week_03/226invertTree.js b/Week_03/226invertTree.js index fd534bde..0c8b8023 100644 --- a/Week_03/226invertTree.js +++ b/Week_03/226invertTree.js @@ -15,16 +15,16 @@ * @param {TreeNode} root * @return {TreeNode} */ -var invertTree = function(root) { +const invertTree = function(root) { // terminator - if (!root) return null + if (root == null) return root // process - var tmp = root.left + const tmp = root.left root.left = root.right root.right = tmp // drill down invertTree(root.left) invertTree(root.right) - // reverse states + // revert states return root -}; +} From 57a3be457bb61b7b07a39a68148f9e123b95c2fc Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 18 Feb 2021 22:24:34 +0800 Subject: [PATCH 034/210] solve lowestCommonAncestor --- Week_03/236lowestCommonAncestor.js | 17 ++++++++++++++--- ...68.js => offer-068lowestCommonAncestor.js} | 19 +++++++++++-------- 2 files changed, 25 insertions(+), 11 deletions(-) rename Week_03/{offer-068.js => offer-068lowestCommonAncestor.js} (50%) diff --git a/Week_03/236lowestCommonAncestor.js b/Week_03/236lowestCommonAncestor.js index 8dc4ed7d..bce8113e 100644 --- a/Week_03/236lowestCommonAncestor.js +++ b/Week_03/236lowestCommonAncestor.js @@ -1,6 +1,7 @@ /** * medium * https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/ + * 思路:递归 */ /** @@ -16,6 +17,16 @@ * @param {TreeNode} q * @return {TreeNode} */ -var lowestCommonAncestor = function(root, p, q) { - -}; + +const lowestCommonAncestor = function(root, p, q) { + // terminator + if (root == null || root == p || root == q) return root + // process + // drill down + const findL = lowestCommonAncestor(root.left, p, q) + const findR = lowestCommonAncestor(root.right, p, q) + if (findL == null) return findR + if (findR == null) return findL + // revert states + return root +} diff --git a/Week_03/offer-068.js b/Week_03/offer-068lowestCommonAncestor.js similarity index 50% rename from Week_03/offer-068.js rename to Week_03/offer-068lowestCommonAncestor.js index c8ca40a8..a1944d87 100644 --- a/Week_03/offer-068.js +++ b/Week_03/offer-068lowestCommonAncestor.js @@ -13,12 +13,15 @@ * @param {TreeNode} q * @return {TreeNode} */ -var lowestCommonAncestor = function(root, p, q) { - if(root === null || root === p || root === q) return root - var left = lowestCommonAncestor(root.left, p, q) - var right = lowestCommonAncestor(root.right, p, q) - // if (left === null && right === null) return null - if (left === null) return right - if (right === null) return left +const lowestCommonAncestor = function(root, p, q) { + // terminator + if (root == null || root == p || root == q) return root + // process + // drill down + const findL = lowestCommonAncestor(root.left, p, q) + const findR = lowestCommonAncestor(root.right, p, q) + if (findL == null) return findR + if (findR == null) return findL + // revert states return root -}; +} From 65ae341e4070a96437c104798f3c5b4ce866d504 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 18 Feb 2021 22:50:02 +0800 Subject: [PATCH 035/210] solve 75 sortColors --- Week_01/075sortColors.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Week_01/075sortColors.js diff --git a/Week_01/075sortColors.js b/Week_01/075sortColors.js new file mode 100644 index 00000000..9830b971 --- /dev/null +++ b/Week_01/075sortColors.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +/** + * medium + * https://leetcode-cn.com/problems/sort-colors/ + * 思路:双指针夹逼,维护l指针左边全是0,r指针右边全是2 + */ + +const sortColors = function(nums) { + const swap = function(arr, i, j) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp + } + let l = 0, r = nums.length - 1, i = 0 + while(i <= r) { + if (nums[i] === 0) { + swap(nums, i++, l++) + } else if (nums[i] === 2) { + swap(nums, i, r--) + } else { + ++i + } + } +} From edc328015aa58d6b58c06b6f1762ea9f444667a5 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 18 Feb 2021 22:54:45 +0800 Subject: [PATCH 036/210] refactor 075 sort colors --- Week_01/075sortColors.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Week_01/075sortColors.js b/Week_01/075sortColors.js index 9830b971..7b422a33 100644 --- a/Week_01/075sortColors.js +++ b/Week_01/075sortColors.js @@ -14,14 +14,8 @@ const sortColors = function(nums) { arr[i] = arr[j] arr[j] = tmp } - let l = 0, r = nums.length - 1, i = 0 - while(i <= r) { - if (nums[i] === 0) { - swap(nums, i++, l++) - } else if (nums[i] === 2) { - swap(nums, i, r--) - } else { - ++i - } + for(let i = 0, l = 0, r = nums.length - 1; i <= r; ++i) { + while(nums[i] === 2 && i < r) swap(nums, i, r--) + while(nums[i] === 0 && i > l) swap(nums, i, l++) } } From 1cd11c5744d42e43feb4733851e9dc0fe1e7ca76 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 19 Feb 2021 00:07:32 +0800 Subject: [PATCH 037/210] resolve array --- Week_01/001twoSum.js | 20 ++++++++------------ Week_01/011maxArea.js | 11 +++++------ Week_01/015threeSum.js | 8 +++++++- Week_01/026removeDuplicates.js | 14 +++++++------- Week_01/066plusOne.js | 18 ++++++++++-------- Week_01/070climbStairs.js | 19 ++++++++++--------- Week_01/189rotate.js | 19 +++++++++++-------- Week_01/283moveZeros.js | 20 +++++++++++--------- 8 files changed, 69 insertions(+), 60 deletions(-) diff --git a/Week_01/001twoSum.js b/Week_01/001twoSum.js index b2d7f8ed..f4b9c05a 100644 --- a/Week_01/001twoSum.js +++ b/Week_01/001twoSum.js @@ -1,22 +1,18 @@ /** - * 7. 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) - * leetcode-001 + * 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) * https://leetcode-cn.com/problems/two-sum/ - */ -/** - * 思路:类似去婚姻登记所找另一半,如果没找到匹配对象,就利用哈希表登记下;找到了就ok。 * @param {number[]} nums * @param {number} target * @return {number[]} */ -var twoSum = function (nums, target) { - var hashMap = {} - for (var i = 0; i < nums.length; ++i) { - if (hashMap[nums[i]] === undefined) { - hashMap[target - nums[i]] = i +const twoSum = function(nums, target) { + const m = new Map() + for(let i = 0; i < nums.length; ++i) { + if (m.has(nums[i])) { + return [m.get(nums[i]), i] } else { - return [hashMap[nums[i]], i] + m.set(target - nums[i], i) } } return [] -}; +} diff --git a/Week_01/011maxArea.js b/Week_01/011maxArea.js index ca2d18d7..47b6da4a 100644 --- a/Week_01/011maxArea.js +++ b/Week_01/011maxArea.js @@ -30,12 +30,11 @@ console.log(maxArea1([1,2,1])) // 解法二: O(n) const maxArea = function(a) { - if (Object.prototype.toString.apply(a) !== '[object Array]' - || a.length < 2) return 0 - let max = 0 - for(let i = 0, j = a.length - 1; i < j;) { - const minHeight = a[i] < a[j] ? a[i++] : a[j--] - const area = (j - i + 1) * minHeight + if (Object.prototype.toString.call(a) !== '[object Array]' || a.length < 2) return 0 + let max = 0, l = 0, r = a.length - 1 + while(l < r) { + const minHeight = a[l] < a[r] ? a[l++] : a[r--] + const area = minHeight * (r - l + 1) max = Math.max(max, area) } return max diff --git a/Week_01/015threeSum.js b/Week_01/015threeSum.js index da0bc15e..cb709249 100644 --- a/Week_01/015threeSum.js +++ b/Week_01/015threeSum.js @@ -34,7 +34,13 @@ let threeSum2 = function (nums) { console.log('solution 1: ', threeSum2([-1, 0, 1, 2, -1, -4])) -// 解法3 O(n^2) +/** + * 解法3 O(n^2) + * 思路: + * 1. 先排序 + * 2. 外层循环k,左右双指针夹逼。挪动去重 + */ + const threeSum = function (nums) { if (Object.prototype.toString.apply(nums) !== '[object Array]' || nums.length < 3) return [] nums.sort((a, b) => a - b) diff --git a/Week_01/026removeDuplicates.js b/Week_01/026removeDuplicates.js index ce598981..63cb5929 100644 --- a/Week_01/026removeDuplicates.js +++ b/Week_01/026removeDuplicates.js @@ -1,17 +1,17 @@ /** - * 3. 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) - * easy | leetcode-026 | array + * 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ * 思路:利用数组是有序的特性,重复元素必相邻。遍历一轮,用cnt记录重复项数量,用第i个元素覆盖i-cnt个元素 */ -var removeDuplicates = function (nums) { - var cnt = 0; - for (var i = 1; i < nums.length; ++i) { +const removeDuplicates = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return 0 + let cnt = 0 + for(let i = 1; i < nums.length; ++i) { if (nums[i] === nums[i - 1]) { - cnt++ + ++cnt } else { nums[i - cnt] = nums[i] } } return nums.length - cnt -}; +} diff --git a/Week_01/066plusOne.js b/Week_01/066plusOne.js index a8c51068..4dd1c282 100644 --- a/Week_01/066plusOne.js +++ b/Week_01/066plusOne.js @@ -8,17 +8,19 @@ * @param {number[]} digits * @return {number[]} */ -var plusOne = function(digits) { - for(var i = digits.length - 1; i >= 0; --i) { - if (digits[i] < 9){ - digits[i]++ +const plusOne = function(digits) { + if (Object.prototype.toString.call(digits) !== '[object Array]' || digits.length < 1) return [1] + + for(let i = digits.length - 1; i >= 0; --i) { + if (digits[i] < 9) { + ++digits[i] break } else { digits[i] = 0 - if(i === 0) { - digits.unshift(1) - } } } + if (digits[0] === 0) { + digits.unshift(1) + } return digits -}; +} diff --git a/Week_01/070climbStairs.js b/Week_01/070climbStairs.js index e3294dbe..a75aeb06 100644 --- a/Week_01/070climbStairs.js +++ b/Week_01/070climbStairs.js @@ -1,15 +1,16 @@ /** + * https://leetcode-cn.com/problems/climbing-stairs/ * 思路:fibnacci数列 * @param {number} n * @return {number} */ -var climbStairs = function(n) { - if (n < 3) return n - var p1 = 1, p2 = 2, p3 = 3 - while(n-- > 3) { - p1 = p2 - p2 = p3 - p3 = p1 + p2 +const climbStairs = function(n) { + if (n <= 3) return n + let a = 2, b = 3, c + for(let i = 4; i <= n; ++i) { + c = a + b + a = b + b = c } - return p3 -}; + return c +} diff --git a/Week_01/189rotate.js b/Week_01/189rotate.js index 8001483f..a1127581 100644 --- a/Week_01/189rotate.js +++ b/Week_01/189rotate.js @@ -10,16 +10,19 @@ // return nums // }; // O(1)空间复杂度解法: 反转3次 -var rotate = function(nums, k) { - var reverse = function(nums, start, end) { - while(start < end) { - var tmp = nums[start] - nums[start++] = nums[end] - nums[end--] = tmp - } +const rotate = function(nums, k) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 2) return + + const reverse = (nums, start, end) => { + while(start < end) { + const tmp = nums[start] + nums[start++] = nums[end] + nums[end--] = tmp + } } + k %= nums.length reverse(nums, 0, nums.length - 1) reverse(nums, 0, k - 1) reverse(nums, k, nums.length - 1) -}; +} diff --git a/Week_01/283moveZeros.js b/Week_01/283moveZeros.js index d6f143b1..89ef2eb9 100644 --- a/Week_01/283moveZeros.js +++ b/Week_01/283moveZeros.js @@ -1,20 +1,22 @@ /* - * leetcode-283 | * https://leetcode-cn.com/problems/move-zeroes/ * 思路: 用一个标记记录非0的位置 */ -var moveZeroes = function (nums) { - var swap = function (nums, i, j) { - var tmp = nums[i] - nums[i] = nums[j] - nums[j] = tmp +const moveZeroes = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length <= 0) return nums + + const swap = function(nums, i, j) { + if (i !== j) { + const tmp = nums[i] + nums[i] = nums[j] + nums[j] = tmp + } } - for (var i = 0, j = 0; i < nums.length; ++i) { + for(let i = 0, j = 0; i < nums.length; ++i) { if (nums[i] !== 0) { swap(nums, i, j++) } } - return nums -}; +} From 1a24cb592b4be6e63da7fd5883747bd5e006dff6 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 19 Feb 2021 17:25:10 +0800 Subject: [PATCH 038/210] fund more efficient solution of 070 & 283 --- Week_01/070climbStairs.js | 2 +- Week_01/283moveZeros.js | 21 +++++++++++++++++++++ Week_01/demo.js | 13 +++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 Week_01/demo.js diff --git a/Week_01/070climbStairs.js b/Week_01/070climbStairs.js index a75aeb06..f373f5e7 100644 --- a/Week_01/070climbStairs.js +++ b/Week_01/070climbStairs.js @@ -5,7 +5,7 @@ * @return {number} */ const climbStairs = function(n) { - if (n <= 3) return n + if (typeof n !== 'number' || n < 4) return n let a = 2, b = 3, c for(let i = 4; i <= n; ++i) { c = a + b diff --git a/Week_01/283moveZeros.js b/Week_01/283moveZeros.js index 89ef2eb9..68c32e44 100644 --- a/Week_01/283moveZeros.js +++ b/Week_01/283moveZeros.js @@ -20,3 +20,24 @@ const moveZeroes = function(nums) { } } } + +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + * 解法二:nums[pos++] = nums[i] + */ +const moveZeroes = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) { + return + } + + let pos = 0 + for(let i = 0; i < nums.length; ++i) { + if (nums[i] !== 0) { + nums[pos++] = nums[i] + } + } + while(pos < nums.length) { + nums[pos++] = 0 + } +} diff --git a/Week_01/demo.js b/Week_01/demo.js new file mode 100644 index 00000000..135594b2 --- /dev/null +++ b/Week_01/demo.js @@ -0,0 +1,13 @@ +let nums = [1,1,2,3,4] +let i = 0, j = nums.length - 1 +while (i < j && nums[i] === nums[++i]) { + console.log('circle x:', i, j) +} + +i = 0, j = nums.length - 1 +while (i < j && nums[++i] === nums[i]) { + console.log('circle y:', i, j) +} + +// ++i 一定要放到后面!!!,不然先运算 ++i,再判断,起不到效果! +// 3sum 总结 From 56eb71836273091ac14f684daa0e7890b5bf507d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 19 Feb 2021 17:39:39 +0800 Subject: [PATCH 039/210] difference between i++ & ++i --- Week_01/demo.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Week_01/demo.js b/Week_01/demo.js index 135594b2..4a2ecbc2 100644 --- a/Week_01/demo.js +++ b/Week_01/demo.js @@ -1,13 +1,24 @@ let nums = [1,1,2,3,4] let i = 0, j = nums.length - 1 while (i < j && nums[i] === nums[++i]) { - console.log('circle x:', i, j) + console.log('[circle 1]:', i, j) +} + +i = 0, j = nums.length - 1 +while (i < j && nums[i] === nums[i++]) { + console.log('[circle 2]:', i, j) } i = 0, j = nums.length - 1 while (i < j && nums[++i] === nums[i]) { - console.log('circle y:', i, j) + console.log('[circle 3]:', i, j) +} + +i = 0, j = nums.length - 1 +while (i < j && nums[i++] === nums[i]) { + console.log('[circle 4]:', i, j) } // ++i 一定要放到后面!!!,不然先运算 ++i,再判断,起不到效果! // 3sum 总结 +// https://stackoverflow.com/questions/24853/c-what-is-the-difference-between-i-and-i From 11ef726ad760755ebf2f3b989d90cdfe839e0b80 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 19 Feb 2021 18:05:15 +0800 Subject: [PATCH 040/210] refactor some array problem --- Week_01/075sortColors.js | 19 ++++++++++++------- Week_01/088merge.js | 12 +++++++----- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Week_01/075sortColors.js b/Week_01/075sortColors.js index 7b422a33..ebaf66b2 100644 --- a/Week_01/075sortColors.js +++ b/Week_01/075sortColors.js @@ -9,13 +9,18 @@ */ const sortColors = function(nums) { - const swap = function(arr, i, j) { - const tmp = arr[i] - arr[i] = arr[j] - arr[j] = tmp + if (Object.prototype.toString.call(nums) !== '[object Array]') return + + const swap = (nums, l, r) => { + if (l !== r) { + const tmp = nums[l] + nums[l] = nums[r] + nums[r] = tmp + } } - for(let i = 0, l = 0, r = nums.length - 1; i <= r; ++i) { - while(nums[i] === 2 && i < r) swap(nums, i, r--) - while(nums[i] === 0 && i > l) swap(nums, i, l++) + + for (let i = 0, l = 0, r = nums.length - 1; i < nums.length; ++i) { + while(i < r && nums[i] === 2) swap(nums, i, r--) + while(i > l && nums[i] === 0) swap(nums, i, l++) } } diff --git a/Week_01/088merge.js b/Week_01/088merge.js index 0d9302c5..22a728fd 100644 --- a/Week_01/088merge.js +++ b/Week_01/088merge.js @@ -3,9 +3,12 @@ * easy | leetcode-088 | array * https://leetcode-cn.com/problems/merge-sorted-array/ */ -var merge = function(nums1, m, nums2, n) { - var i = m - 1, j = n - 1, k = m + n - 1 - while (i >= 0 && j >= 0) { +const merge = function(nums1, m, nums2, n) { + const toS = Object.prototype.toString, ARRTYPE = '[object Array]' + if (toS.call(nums1) !== ARRTYPE || toS.call(nums2) !== ARRTYPE) return + + 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 { @@ -15,5 +18,4 @@ var merge = function(nums1, m, nums2, n) { while(j >= 0) { nums1[k--] = nums2[j--] } - return nums1 -}; +} From 3c16b861730180c8d3839673ac4a7df0d77c4940 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Feb 2021 01:11:34 +0800 Subject: [PATCH 041/210] backtracing --- Week_03/046permute.js | 34 +++++++++++++++++++++++++++++++ Week_03/077combine.js | 37 ++++++++++++++++++++++++++++++++++ Week_03/105buildTree.js | 44 +++++++++++++++++++++++++++++++++++++++++ Week_03/README.md | 8 ++++---- 4 files changed, 119 insertions(+), 4 deletions(-) diff --git a/Week_03/046permute.js b/Week_03/046permute.js index e69de29b..9be3da4d 100644 --- a/Week_03/046permute.js +++ b/Week_03/046permute.js @@ -0,0 +1,34 @@ +/** + * https://leetcode-cn.com/problems/permutations/ + * 思路1:回溯 + * 利用splice 和 slice拷贝,性能较差 + * + * @param {number[]} nums + * @return {number[][]} + */ +const permute = function(nums) { + const res = [] + + const helper = (path, part) => { + // console.log("🚀 ~ helper", path, part) + if (path.length >= nums.length) { + res.push(path.slice()) + return + } + for(let i = 0; i < part.length; ++i) { + const val = part[i] + part.splice(i, 1) + path.push(val) + helper(path.slice(), part.slice()) + path.pop() + part.splice(i, 0, val) + } + } + + helper([], nums.slice()) + return res +} + +// ---- test case ---- +console.log(permute([1,2,3])) + diff --git a/Week_03/077combine.js b/Week_03/077combine.js index e69de29b..53e8c9ea 100644 --- a/Week_03/077combine.js +++ b/Week_03/077combine.js @@ -0,0 +1,37 @@ +/** + * https://leetcode-cn.com/problems/combinations/ + * 思路:回溯 + 剪枝 + * + * + * @param {number} n + * @param {number} k + * @return {number[][]} + */ +const combine = function(n, k) { + const res = [] + /** + * 辅助函数 + * @param {*} start 枚举起点 + * @param {*} path “部分解” + */ + const helper = (start, path) => { + if (path.length === k) { + res.push(path.slice()) + return + } + for(let i = start; i <= n; ++i) { + path.push(i) // 选择 + helper(i + 1, path) + path.pop() // 撤销选择 + } + } + + helper(1, []) + return res +} + +// ---- test case ---- +console.log(combine(4, 2)) +console.log(combine(4, 3)) +console.log(combine(5, 3)) + diff --git a/Week_03/105buildTree.js b/Week_03/105buildTree.js index e69de29b..b6aaa0d1 100644 --- a/Week_03/105buildTree.js +++ b/Week_03/105buildTree.js @@ -0,0 +1,44 @@ +/** + * https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ + * 思路: + * 1. 建立辅助函数,扩充4个下标。pStart,pEnd,iStart,iEnd + * 2. 递归调用辅助函数 + * + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {number[]} preorder + * @param {number[]} inorder + * @return {TreeNode} + */ + +const buildTree = function(preorder, inorder) { + const helper = (preorder, pStart, pEnd, inorder, iStart, iEnd) => { + // terminator + if (pStart === pEnd) { + return null + } + // process [rootValue -> iRootIdx -> leftSize] + const rootValue = preorder[pStart], root = new TreeNode(rootValue) + let iRootIdx = 0 + for(let i = 0; i < inorder.length; ++i) { + if (inorder[i] === rootValue) { + iRootIdx = i + break + } + } + const leftSize = iRootIdx - iStart + // drill down + root.left = helper(preorder, pStart + 1, pStart + leftSize + 1, inorder, iStart, iRootIdx) + root.right = helper(preorder, pStart + leftSize + 1, pEnd, inorder, iRootIdx + 1, iEnd) + // revert states + return root + } + + return helper(preorder, 0, preorder.length, inorder, 0, inorder.length) +} diff --git a/Week_03/README.md b/Week_03/README.md index ccebdab2..7676fd49 100644 --- a/Week_03/README.md +++ b/Week_03/README.md @@ -4,10 +4,10 @@ **递归模版** -1. terminator -2. process -3. drill down -4. revert states +1. 递归终结条件 recursion terminator +2. 处理当前层逻辑 process logic in current level +3. 下探到下一层 drill down +4. 清理当前层 revere the current level status if needed ## 第8课:分治、回溯 From 6182f9d8d01ad56fc5e913c222892a9b5c6db4fe Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Feb 2021 01:17:03 +0800 Subject: [PATCH 042/210] refactor: needn't copy local variables --- Week_03/046permute.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Week_03/046permute.js b/Week_03/046permute.js index 9be3da4d..09d80f4d 100644 --- a/Week_03/046permute.js +++ b/Week_03/046permute.js @@ -19,7 +19,7 @@ const permute = function(nums) { const val = part[i] part.splice(i, 1) path.push(val) - helper(path.slice(), part.slice()) + helper(path, part) path.pop() part.splice(i, 0, val) } From 8519840df5ccec35a4246aee44fc7544ad9a0977 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Feb 2021 01:29:04 +0800 Subject: [PATCH 043/210] complete week03 homework --- Week_03/047permuteUnique.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Week_03/047permuteUnique.js b/Week_03/047permuteUnique.js index e69de29b..14bc9711 100644 --- a/Week_03/047permuteUnique.js +++ b/Week_03/047permuteUnique.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} nums + * @return {number[][]} + */ +const permuteUnique = function(nums) { + const res = [] + + const helper = (path, part) => { + if (path.length >= nums.length) { + res.push(path.slice()) + return + } + for(let i = 0; i < part.length; ++i) { + if (i > 0 && part[i] === part[i - 1]) continue // 去重 + const val = part[i] + path.push(val) + part.splice(i, 1) + helper(path, part) + path.pop() + part.splice(i, 0, val) + } + } + + helper([], nums.sort((x, y) => x - y).slice()) + return res +} + +// ---- test case ---- +console.log(permuteUnique([1,2,3])) +console.log(permuteUnique([1,1,2])) +console.log(permuteUnique([1,2,1])) From 08715ee880bba129c7218b4eeadfaa50f699b563 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Feb 2021 01:34:06 +0800 Subject: [PATCH 044/210] refactor: add notes --- Week_03/README.md | 3 +++ Week_03/homework.md | 15 ++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Week_03/README.md b/Week_03/README.md index 7676fd49..eccf471e 100644 --- a/Week_03/README.md +++ b/Week_03/README.md @@ -40,3 +40,6 @@ const divide_conquer = (problem, params) => { **回溯(backtracing)** +1. 走一步 +2. 递归调用 +3. 恢复 diff --git a/Week_03/homework.md b/Week_03/homework.md index b743c8e4..76a474b9 100644 --- a/Week_03/homework.md +++ b/Week_03/homework.md @@ -2,20 +2,25 @@ ## 1. 二叉树的最近公共祖先(Facebook 在半年内面试常考) -[实现代码](./236lowestCommonAncestor.js) ++ recursion ++ [实现代码](./236lowestCommonAncestor.js) ## 2. 从前序与中序遍历序列构造二叉树(字节跳动、亚马逊、微软在半年内面试中考过) -[实现代码](./105buildTree.js) ++ recursion ++ [实现代码](./105buildTree.js) ## 3. 组合(微软、亚马逊、谷歌在半年内面试中考过) -[实现代码](./077combine.js) ++ backtrack ++ [实现代码](./077combine.js) ## 4. 全排列(字节跳动在半年内面试常考) -[实现代码](./046permute.js) ++ backtrack ++ [实现代码](./046permute.js) ## 5. 全排列 II (亚马逊、字节跳动、Facebook 在半年内面试中考过) -[实现代码](./047permuteUnique.js) ++ backtrack ++ [实现代码](./047permuteUnique.js) From 9f98cdf086a377362304ae67b10e9ea204219280 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Feb 2021 12:02:22 +0800 Subject: [PATCH 045/210] divide & conquer --- Week_03/050myPow.js | 21 +++++++++++++++++---- Week_03/078subsets.js | 44 +++++++++++++++++++++++++++++++++++++++++++ Week_03/README.md | 2 +- 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 Week_03/078subsets.js diff --git a/Week_03/050myPow.js b/Week_03/050myPow.js index 54e3c61c..9ae9236b 100644 --- a/Week_03/050myPow.js +++ b/Week_03/050myPow.js @@ -1,11 +1,20 @@ /** * medium * https://leetcode-cn.com/problems/powx-n/ - * @param {number} x - * @param {number} n - * @return {number} - * 思路:自顶向下迭代,遇到奇数扩大为 x * x ^ 2, 遇到偶数扩大为 x ^ 2 */ + +// 思路1:分治(分解为子问题,再合并结果) +const myPow1 = function(x, n) { + const fastPow = (x, n) => { + if (n === 0) return 1.0 + const half = fastPow(x, Math.floor(n / 2)) + return n % 2 === 0 ? half * half : half * half * x + } + return n >= 0 ? fastPow(x, n) : 1.0 / fastPow(x, -n) +} + +// 思路2:【快速幂】 +// 自底向上迭代,遇到奇数扩大为 x * x ^ 2, 遇到偶数扩大为 x ^ 2 const myPow = function(x, n) { if (n < 0) return 1.0 / myPow(x, -n) let res = 1.0 @@ -19,6 +28,10 @@ const myPow = function(x, n) { } // ---- test case ---- +console.log(myPow1(2.0, 10)) +console.log(myPow1(2.1, 3)) +console.log(myPow1(2.0, -2)) + console.log(myPow(2.0, 10)) console.log(myPow(2.1, 3)) console.log(myPow(2.0, -2)) diff --git a/Week_03/078subsets.js b/Week_03/078subsets.js new file mode 100644 index 00000000..fcf151e6 --- /dev/null +++ b/Week_03/078subsets.js @@ -0,0 +1,44 @@ +/** + * https://leetcode-cn.com/problems/subsets/ + * 思路: + * 分治,求子问题。每一步有两种情况,选or不选 + * + * @param {number[]} nums + * @return {number[][]} + */ +const subsets = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return [] + const res = [] + + const helper = (curIdx, list) => { + if (curIdx === nums.length) { + res.push(list.slice()) + return + } + helper(curIdx + 1, list) + const listClone = list.slice() + listClone.push(nums[curIdx]) + helper(curIdx + 1, listClone) + } + helper(0, []) + return res +} + + +// ---- test case --- +console.log(subsets([1])) +console.log(subsets([1,2])) +console.log(subsets([1,2,3])) +console.log(subsets([1,2,3,4])) + + +/* +[0] +[[], [0]] + +[0, 1] +[[], [0], [1], [0,1]] + +[0, 1, 2] +[[], [0], [1], [2], [0, 1], [0, 2], [1, 2], [1,2,3]] +*/ diff --git a/Week_03/README.md b/Week_03/README.md index eccf471e..f40a9ba8 100644 --- a/Week_03/README.md +++ b/Week_03/README.md @@ -38,7 +38,7 @@ const divide_conquer = (problem, params) => { } ``` -**回溯(backtracing)** +**回溯(backtraking)** 1. 走一步 2. 递归调用 From 9c600d8fb4ca42fba623f4f398eec066fc337b8e Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Feb 2021 12:38:54 +0800 Subject: [PATCH 046/210] solve subsets --- Week_03/078subsets.js | 48 +++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/Week_03/078subsets.js b/Week_03/078subsets.js index fcf151e6..fbafbb74 100644 --- a/Week_03/078subsets.js +++ b/Week_03/078subsets.js @@ -1,35 +1,57 @@ /** * https://leetcode-cn.com/problems/subsets/ - * 思路: + * 思路1: * 分治,求子问题。每一步有两种情况,选or不选 * * @param {number[]} nums * @return {number[][]} */ const subsets = function(nums) { - if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return [] + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return [[]] const res = [] - const helper = (curIdx, list) => { - if (curIdx === nums.length) { + const dfs = (index, list) => {1 + // terminator + if (index === nums.length) { res.push(list.slice()) return } - helper(curIdx + 1, list) - const listClone = list.slice() - listClone.push(nums[curIdx]) - helper(curIdx + 1, listClone) + // process1: not pick + dfs(index + 1, list) + // process2: pick + list.push(nums[index]) + dfs(index + 1, list) + // revert states + list.pop() } - helper(0, []) + + dfs(0, []) return res } +// 思路2: 迭代 +const subsets2 = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return [[]] + + const res = [[]] + nums.forEach(num => { + res.forEach(r => { + res.push(r.concat(num)) + }) + }) + return res +} + + + // ---- test case --- -console.log(subsets([1])) -console.log(subsets([1,2])) -console.log(subsets([1,2,3])) -console.log(subsets([1,2,3,4])) +// console.log(subsets([1])) +// console.log(subsets([1,2])) +// console.log(subsets([1,2,3])) +// console.log(subsets([1,2,3,4])) +console.log(subsets2([1,2,3])) +console.log(JSON.stringify(subsets2([1,2,3]))) /* From aab6f1e7915bc5e18662dc5def498c11b2e41271 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Feb 2021 13:52:48 +0800 Subject: [PATCH 047/210] solve letterCombinations --- Week_03/017letterCombinations.js | 53 ++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 Week_03/017letterCombinations.js diff --git a/Week_03/017letterCombinations.js b/Week_03/017letterCombinations.js new file mode 100644 index 00000000..613aead7 --- /dev/null +++ b/Week_03/017letterCombinations.js @@ -0,0 +1,53 @@ +/** + * https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ + * 思路:分治 + * 1. 画递归树,构造辅助函数 + * + * @param {string} digits + * @return {string[]} + */ +const letterCombinations = function(digits) { + if (typeof digits !== 'string' || digits.length < 1) return [] + + const m = new Map([ + ['2', 'abc'], ['3', 'def'], + ['4', 'ghi'], ['5', 'jkl'], + ['6', 'mno'], ['7', 'pqrs'], + ['8', 'tuv'], ['9', 'wxyz']]), + res = [] + + const helper = (level, path) => { + if (level === digits.length) { + res.push(path.join('')) + return + } + const selectors = m.get(digits[level]) + for(let i = 0; i < selectors.length; ++i) { + path.push(selectors[i]) + helper(level + 1, path) + path.pop() + } + } + + helper(0, []) + return res +} + +console.log(letterCombinations('23')) +// console.log(letterCombinations('995')) +console.log(letterCombinations('')) + +/* +Line 41 in solution.js + throw new TypeError(__serialize__(ret) + " is not valid value for the expected return type list"); +: "" is not valid value for the expected return type list + Line 41: Char 20 in solution.js (Object.) + Line 16: Char 8 in runner.js (Object.runner) + Line 27: Char 26 in solution.js (Object.) + Line 1251: Char 30 in loader.js (Module._compile) + Line 1272: Char 10 in loader.js (Object.Module._extensions..js) + Line 1100: Char 32 in loader.js (Module.load) + Line 962: Char 14 in loader.js (Function.Module._load) + at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12) + Line 17: Char 47 in run_main_module.js +*/ From 510ff7ecf087fac70ca433b16fa44230f476ea47 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Feb 2021 14:11:59 +0800 Subject: [PATCH 048/210] more precise --- Week_03/051solveNQueens.js | 32 ++++++++++++++++++++++++++++++++ Week_03/078subsets.js | 14 +++++++------- 2 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 Week_03/051solveNQueens.js diff --git a/Week_03/051solveNQueens.js b/Week_03/051solveNQueens.js new file mode 100644 index 00000000..55fbc070 --- /dev/null +++ b/Week_03/051solveNQueens.js @@ -0,0 +1,32 @@ +/** + * https://leetcode-cn.com/problems/n-queens/ + * 分治 & 回溯 + * + * + * @param {number} n + * @return {string[][]} + */ +const solveNQueens = function(n) { + +} + + +// ---- test case ---- +console.log(solveNQueens(4)) + +/* +[ + [ + '.Q..', + '...Q', + 'Q...', + '..Q.', + ], + [ + '..Q.', + 'Q...', + '...Q', + '.Q..', + ], +] +*/ diff --git a/Week_03/078subsets.js b/Week_03/078subsets.js index fbafbb74..f2ce9a91 100644 --- a/Week_03/078subsets.js +++ b/Week_03/078subsets.js @@ -10,19 +10,19 @@ const subsets = function(nums) { if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return [[]] const res = [] - const dfs = (index, list) => {1 + const dfs = (level, path) => {1 // terminator - if (index === nums.length) { - res.push(list.slice()) + if (level === nums.length) { + res.push(path.slice()) return } // process1: not pick - dfs(index + 1, list) + dfs(level + 1, path) // process2: pick - list.push(nums[index]) - dfs(index + 1, list) + path.push(nums[level]) + dfs(level + 1, path) // revert states - list.pop() + path.pop() } dfs(0, []) From cda237d4f4266ff12c45a173f3916186d0d5ef83 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Feb 2021 14:22:09 +0800 Subject: [PATCH 049/210] refactor --- Week_03/078subsets.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Week_03/078subsets.js b/Week_03/078subsets.js index f2ce9a91..621f55c4 100644 --- a/Week_03/078subsets.js +++ b/Week_03/078subsets.js @@ -1,6 +1,6 @@ /** * https://leetcode-cn.com/problems/subsets/ - * 思路1: + * 思路1:【分治 + 回溯】 * 分治,求子问题。每一步有两种情况,选or不选 * * @param {number[]} nums @@ -8,9 +8,9 @@ */ const subsets = function(nums) { if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return [[]] - const res = [] - const dfs = (level, path) => {1 + const res = [] + const dfs = (level, path) => { // terminator if (level === nums.length) { res.push(path.slice()) @@ -30,7 +30,7 @@ const subsets = function(nums) { } -// 思路2: 迭代 +// 思路2: 【迭代】 const subsets2 = function(nums) { if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return [[]] From 2908055bf2812ced9f6dc3fef463223c08d427e6 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Feb 2021 17:30:54 +0800 Subject: [PATCH 050/210] refactor threeSum --- Week_01/015threeSum.js | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/Week_01/015threeSum.js b/Week_01/015threeSum.js index cb709249..018552c9 100644 --- a/Week_01/015threeSum.js +++ b/Week_01/015threeSum.js @@ -41,25 +41,24 @@ console.log('solution 1: ', threeSum2([-1, 0, 1, 2, -1, -4])) * 2. 外层循环k,左右双指针夹逼。挪动去重 */ -const threeSum = function (nums) { - if (Object.prototype.toString.apply(nums) !== '[object Array]' || nums.length < 3) return [] - nums.sort((a, b) => a - b) +const threeSum = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 3) return [] + nums.sort((x, y) => x - y) // O(nlogn) const res = [] - for (let k = 0; k < nums.length - 2; ++k) { - if (nums[k] > 0) break - if (k > 0 && nums[k] === nums[k - 1]) continue - let i = k + 1, - j = nums.length - 1 - while (i < j) { - const sum = nums[k] + nums[i] + nums[j] + for(let k = 0; k < nums.length - 2; ++k) { + if (nums[k] > 0) break // prun + if (k > 0 && nums[k] === nums[k-1]) continue // unique + let l = k + 1, r = nums.length - 1 + while(l < r) { + const sum = nums[k] + nums[l] + nums[r] if (sum < 0) { - while (i < j && nums[i] === nums[++i]) {} + while(l < r && nums[l] === nums[++l]) {} // unique } else if (sum > 0) { - while (i < j && nums[j] === nums[--j]) {} + while(l < r && nums[r] === nums[--r]) {} // unique } else { - res.push([nums[k], nums[i], nums[j]]) - while (i < j && nums[i] === nums[++i]) {} // 指针移动顺便去重 - while (i < j && nums[j] === nums[--j]) {} // 指针移动顺便去重 + res.push([nums[k], nums[l], nums[r]]) + while(l < r && nums[l] === nums[++l]) {} // unique + while(l < r && nums[r] === nums[--r]) {} // unique } } } From de4c2df7c4519eeb51c169e18ddcddf04b43ea25 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Feb 2021 17:42:45 +0800 Subject: [PATCH 051/210] refactor permute --- Week_03/046permute.js | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Week_03/046permute.js b/Week_03/046permute.js index 09d80f4d..e5cf9843 100644 --- a/Week_03/046permute.js +++ b/Week_03/046permute.js @@ -1,31 +1,27 @@ /** * https://leetcode-cn.com/problems/permutations/ - * 思路1:回溯 - * 利用splice 和 slice拷贝,性能较差 + * 思路:分治 + 回溯 * * @param {number[]} nums * @return {number[][]} */ const permute = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return [] const res = [] - - const helper = (path, part) => { - // console.log("🚀 ~ helper", path, part) - if (path.length >= nums.length) { + const dfs = (path, list) => { + if (path.length >= nums.length) { // terminator res.push(path.slice()) return } - for(let i = 0; i < part.length; ++i) { - const val = part[i] - part.splice(i, 1) + for(let i = 0; i < list.length; ++i) { + const [val] = list.splice(i, 1) path.push(val) - helper(path, part) - path.pop() - part.splice(i, 0, val) + dfs(path, list) // process & dirll down + path.pop() // revert states + list.splice(i, 0, val) } } - - helper([], nums.slice()) + dfs([], nums.slice()) return res } From d628a8e0de171ce6e6f8fe1838595b075132580a Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Feb 2021 00:55:17 +0800 Subject: [PATCH 052/210] solve 297 use dfs --- Week_03/051solveNQueens.js | 39 ++++++++++++++++++++++++++++++++++++++ Week_03/297serialize.js | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 Week_03/297serialize.js diff --git a/Week_03/051solveNQueens.js b/Week_03/051solveNQueens.js index 55fbc070..8e6b0f77 100644 --- a/Week_03/051solveNQueens.js +++ b/Week_03/051solveNQueens.js @@ -7,14 +7,53 @@ * @return {string[][]} */ const solveNQueens = function(n) { + if (n < 1 || n > 4) return [[]] + // 把 result 转换成题目要求的格式 + const generateResult = (result) => { + const board = [] + result.forEach(res => { + const matrix = [] + res.forEach(i => { + const line = '.'.repeat(i) + 'Q' + '.'.repeat(n - i - 1) + matrix.push(line) + }) + board.push(matrix) + }) + return board + } + + const result = { + 1: [ + [0] + ], + 2: [], + 3: [], + 4: [ + [1, 3, 0, 2], + [2, 0, 3, 1], + ] + } + return generateResult(result[n]) } // ---- test case ---- +console.log(solveNQueens(0)) +console.log(solveNQueens(1)) +console.log(solveNQueens(2)) +console.log(solveNQueens(3)) console.log(solveNQueens(4)) /* +输入: n = 4 +中间结果result: +[ + [1, 3, 0, 2], + [2, 0, 3, 1], +] + +输出结果: [ [ '.Q..', diff --git a/Week_03/297serialize.js b/Week_03/297serialize.js new file mode 100644 index 00000000..e87cf6b9 --- /dev/null +++ b/Week_03/297serialize.js @@ -0,0 +1,36 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ + + // 解法一:DFS (递归写法) +const serialize = function(root) { + if (root == null) { + return 'X'; + } + const left = serialize(root.left) + const right = serialize(root.right) + return root.val + ',' + left + ','+ right +} + +const deserialize = function(data) { + const treeVals = data.split(',') + + const buildTree = (list) => { + const rootVal = list.shift() + if (rootVal === 'X') return null + const root = new TreeNode(rootVal) + root.left = buildTree(list) + root.right = buildTree(list) + return root + } + + return buildTree(treeVals) +} + + +// 1,2,X,X,3,4,X,X,5,X,X + From 2a8483fb0cf9df359cedf89b2c943d659d0f2c2d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Feb 2021 11:06:25 +0800 Subject: [PATCH 053/210] solve m17.09 --- Week_01/m17.09getKthMagicNumber.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Week_01/m17.09getKthMagicNumber.js diff --git a/Week_01/m17.09getKthMagicNumber.js b/Week_01/m17.09getKthMagicNumber.js new file mode 100644 index 00000000..27b2ff29 --- /dev/null +++ b/Week_01/m17.09getKthMagicNumber.js @@ -0,0 +1,27 @@ +/** + * https://leetcode-cn.com/problems/get-kth-magic-number-lcci/ + * + * 1, 3, 5, 7, 9, 15, 21, 35, 49, + * + * 推导公式:f(n) = min(3f(p3), 5f(p5), 7f(p7)) + * + */ +const getKthMagicNumber = function(k) { + if (k < 2) return k + let p3 = p5 = p7 = 0, nums = [1] + for(let i = 1; i < k; ++i) { + const x = 3 * nums[p3], y = 5 * nums[p5], z = 7 * nums[p7] + nums[i] = Math.min(x, y, z) + if (nums[i] === x) ++p3 + if (nums[i] === y) ++p5 + if (nums[i] === z) ++p7 + } + + console.log("🚀🚀🚀🚀", p3, p5, p7) + return nums[k - 1] +} + +// test case +new Array(20).fill(0).forEach((item, idx) => { + console.log(`${idx + 1}: ` + getKthMagicNumber(idx + 1)) +}) From 9fecdf6910db4cd45586e5240b26f4b6080cdc7a Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Feb 2021 11:41:04 +0800 Subject: [PATCH 054/210] solve N queens --- Week_01/m17.09getKthMagicNumber.js | 4 ++- Week_03/051solveNQueens.js | 55 +++++++++++++++++++----------- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/Week_01/m17.09getKthMagicNumber.js b/Week_01/m17.09getKthMagicNumber.js index 27b2ff29..e1015fe6 100644 --- a/Week_01/m17.09getKthMagicNumber.js +++ b/Week_01/m17.09getKthMagicNumber.js @@ -1,6 +1,8 @@ /** * https://leetcode-cn.com/problems/get-kth-magic-number-lcci/ * + * 思路:三指针法 + * * 1, 3, 5, 7, 9, 15, 21, 35, 49, * * 推导公式:f(n) = min(3f(p3), 5f(p5), 7f(p7)) @@ -21,7 +23,7 @@ const getKthMagicNumber = function(k) { return nums[k - 1] } -// test case +// ---- test case ---- new Array(20).fill(0).forEach((item, idx) => { console.log(`${idx + 1}: ` + getKthMagicNumber(idx + 1)) }) diff --git a/Week_03/051solveNQueens.js b/Week_03/051solveNQueens.js index 8e6b0f77..f53489c7 100644 --- a/Week_03/051solveNQueens.js +++ b/Week_03/051solveNQueens.js @@ -1,13 +1,40 @@ /** * https://leetcode-cn.com/problems/n-queens/ - * 分治 & 回溯 + * 【DFS 递归搜索 + 剪枝】 * * * @param {number} n * @return {string[][]} */ const solveNQueens = function(n) { - if (n < 1 || n > 4) return [[]] + if (n < 1) return [[]] + + const result = [], + cols = new Set(), + pie = new Set(), // 撇 + na = new Set() // 捺 + + const dfs = (i, curState) => { + // terminator + if (i >= n) { + result.push(curState) + return + } + // process + for(let j = 0; j < n; ++j) { + if (cols.has(j) || pie.has(i + j) || na.has(i - j)) + continue + // drill down + cols.add(j) + pie.add(i + j) + na.add(i - j) + dfs(i + 1, curState.concat([j])) + // revert states + cols.delete(j) + pie.delete(i + j) + na.delete(i - j) + } + } // 把 result 转换成题目要求的格式 const generateResult = (result) => { @@ -23,27 +50,17 @@ const solveNQueens = function(n) { return board } - const result = { - 1: [ - [0] - ], - 2: [], - 3: [], - 4: [ - [1, 3, 0, 2], - [2, 0, 3, 1], - ] - } - return generateResult(result[n]) + dfs(0, []) + return generateResult(result) } // ---- test case ---- -console.log(solveNQueens(0)) -console.log(solveNQueens(1)) -console.log(solveNQueens(2)) -console.log(solveNQueens(3)) -console.log(solveNQueens(4)) +new Array(10).fill(0).forEach((item, idx) => { + const g = solveNQueens(idx) + console.log(`---- ${idx}, 共${g.length}种解法 ----`) + // console.log(g) +}) /* 输入: n = 4 From 894ae0e8c7c18186457323426531625defff48c6 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Feb 2021 13:06:46 +0800 Subject: [PATCH 055/210] learn dfs & bfs --- Week_03/051solveNQueens.js | 6 +-- Week_03/README.md | 2 +- Week_04/022generateParenthesis.js | 7 ++++ Week_04/102levelOrder.js | 8 ++++ Week_04/433minMutation.js | 11 ++++++ Week_04/515largestValues.js | 8 ++++ Week_04/README.md | 57 ++++++++++++++++++++++++++- Week_04/demotree.js | 64 +++++++++++++++++++++++++++++++ 8 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 Week_04/022generateParenthesis.js create mode 100644 Week_04/102levelOrder.js create mode 100644 Week_04/433minMutation.js create mode 100644 Week_04/515largestValues.js create mode 100644 Week_04/demotree.js diff --git a/Week_03/051solveNQueens.js b/Week_03/051solveNQueens.js index f53489c7..26ef02d5 100644 --- a/Week_03/051solveNQueens.js +++ b/Week_03/051solveNQueens.js @@ -1,11 +1,10 @@ /** * https://leetcode-cn.com/problems/n-queens/ - * 【DFS 递归搜索 + 剪枝】 - * - * * @param {number} n * @return {string[][]} */ + +// 解法一:【DFS 递归搜索 + 剪枝】 const solveNQueens = function(n) { if (n < 1) return [[]] @@ -54,6 +53,7 @@ const solveNQueens = function(n) { return generateResult(result) } +// TODO 解法二:位运算 // ---- test case ---- new Array(10).fill(0).forEach((item, idx) => { diff --git a/Week_03/README.md b/Week_03/README.md index f40a9ba8..8ca4691b 100644 --- a/Week_03/README.md +++ b/Week_03/README.md @@ -1,4 +1,4 @@ -## 学习笔记 +# 学习笔记 ## 第7课:泛型递归、树的递归 diff --git a/Week_04/022generateParenthesis.js b/Week_04/022generateParenthesis.js new file mode 100644 index 00000000..a6e03080 --- /dev/null +++ b/Week_04/022generateParenthesis.js @@ -0,0 +1,7 @@ +/** + * https://leetcode-cn.com/problems/generate-parentheses/ + * + */ +const generateParenthesis = function(n) { + +} diff --git a/Week_04/102levelOrder.js b/Week_04/102levelOrder.js new file mode 100644 index 00000000..b85329e2 --- /dev/null +++ b/Week_04/102levelOrder.js @@ -0,0 +1,8 @@ +/** + * https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ + * + */ + +const levelOrder = function(root) { + +} diff --git a/Week_04/433minMutation.js b/Week_04/433minMutation.js new file mode 100644 index 00000000..d782bc1b --- /dev/null +++ b/Week_04/433minMutation.js @@ -0,0 +1,11 @@ +/** + * https://leetcode-cn.com/problems/minimum-genetic-mutation/ + * + * @param {string} start + * @param {string} end + * @param {string[]} bank + * @return {number} + */ +const minMutation = function(start, end, bank) { + +} diff --git a/Week_04/515largestValues.js b/Week_04/515largestValues.js new file mode 100644 index 00000000..26c2d0e6 --- /dev/null +++ b/Week_04/515largestValues.js @@ -0,0 +1,8 @@ +/** + * https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/ + * + */ + +const largestValues = function(root) { + +} diff --git a/Week_04/README.md b/Week_04/README.md index 50de3041..d9548b91 100644 --- a/Week_04/README.md +++ b/Week_04/README.md @@ -1 +1,56 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 第9课:深度优先搜索和广度优先搜索 + +***DFS(递归版)** + +```js +const res = [] +const dfs = (root) => { + if (root == null) return + res.push(root.val) + dfs(root.left) + dfs(root.right) +} +``` + +***DFS(非递归版)** + ++ 手动维护stack + +```js +const dfs = (root) => { + if (root == null) return [] + + const res = [], stack = [root] + while(stack.length > 0) { + const p = stack.pop() + res.push(p.val) + stack.push(p.left) + stack.push(p.right) + } + return res +} +``` + +***BFS** + ++ 手动维护queue + +```js +const bfs = (root) => { + if (root == null) return [] + + const res = [], queue = [root] + while(queue.length > 0) { + const p = queue.pop() + res.push(p.val) + res.unshift(p.left) + res.unshift(p.right) + } +} +``` + +## 第10课:贪心算法 + +## 第11课:二分查找 diff --git a/Week_04/demotree.js b/Week_04/demotree.js new file mode 100644 index 00000000..0db2c5d9 --- /dev/null +++ b/Week_04/demotree.js @@ -0,0 +1,64 @@ +const dfs = (root) => { + const res = [], stack = [root] + while(stack.length > 0) { + const p = stack.pop() + if (p == null) continue + res.push(p.val) + stack.push(p.right) + stack.push(p.left) + } + return res +} + +const bfs = (root) => { + const res = [], queue = [root] + while(queue.length > 0) { + const p = queue.pop() + if (p == null) continue + + res.push(p.val) + + queue.unshift(p.left) + queue.unshift(p.right) + } + return res +} + + +// ---- test case ---- +function TreeNode(val, left, right) { + this.val = (val===undefined ? 0 : val) + this.left = (left===undefined ? null : left) + this.right = (right===undefined ? null : right) +} + +const buildTree = function(preorder, inorder) { + const helper = (preorder, pStart, pEnd, inorder, iStart, iEnd) => { + // terminator + if (pStart === pEnd) { + return null + } + // process [rootValue -> iRootIdx -> leftSize] + const rootValue = preorder[pStart], root = new TreeNode(rootValue) + let iRootIdx = 0 + for(let i = 0; i < inorder.length; ++i) { + if (inorder[i] === rootValue) { + iRootIdx = i + break + } + } + const leftSize = iRootIdx - iStart + // drill down + root.left = helper(preorder, pStart + 1, pStart + leftSize + 1, inorder, iStart, iRootIdx) + root.right = helper(preorder, pStart + leftSize + 1, pEnd, inorder, iRootIdx + 1, iEnd) + // revert states + return root + } + + return helper(preorder, 0, preorder.length, inorder, 0, inorder.length) +} + +const t = buildTree([3,9,20,15,7], [9,3,15,20,7]) +console.log(JSON.stringify(t, null, 2)) +console.log(bfs(t)) +console.log(dfs(t)) From d544589081d3c6eb741aa740b27b30db5d382f38 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Feb 2021 13:22:40 +0800 Subject: [PATCH 056/210] bfs & dfs code template --- Week_03/297serialize.js | 3 ++ Week_04/README.md | 29 ++++++++++-------- Week_04/demotree.js | 68 +++++++++++++++++++++++------------------ 3 files changed, 57 insertions(+), 43 deletions(-) diff --git a/Week_03/297serialize.js b/Week_03/297serialize.js index e87cf6b9..a905ba8c 100644 --- a/Week_03/297serialize.js +++ b/Week_03/297serialize.js @@ -1,4 +1,7 @@ /** + * https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/ + * hard + * * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; diff --git a/Week_04/README.md b/Week_04/README.md index d9548b91..930c0f74 100644 --- a/Week_04/README.md +++ b/Week_04/README.md @@ -5,12 +5,16 @@ ***DFS(递归版)** ```js -const res = [] -const dfs = (root) => { - if (root == null) return - res.push(root.val) - dfs(root.left) - dfs(root.right) +const dfs_wrap = (root) => { + const dfs_recur = (root) => { + if (root == null) return + res.push(root.val) + dfs_recur(root.left) + dfs_recur(root.right) + } + const res = [] + dfs_recur(root) + return res } ``` @@ -20,14 +24,13 @@ const dfs = (root) => { ```js const dfs = (root) => { - if (root == null) return [] - const res = [], stack = [root] while(stack.length > 0) { const p = stack.pop() + if (p == null) continue res.push(p.val) - stack.push(p.left) stack.push(p.right) + stack.push(p.left) } return res } @@ -39,15 +42,15 @@ const dfs = (root) => { ```js const bfs = (root) => { - if (root == null) return [] - const res = [], queue = [root] while(queue.length > 0) { const p = queue.pop() + if (p == null) continue res.push(p.val) - res.unshift(p.left) - res.unshift(p.right) + queue.unshift(p.left) + queue.unshift(p.right) } + return res } ``` diff --git a/Week_04/demotree.js b/Week_04/demotree.js index 0db2c5d9..f4ff3350 100644 --- a/Week_04/demotree.js +++ b/Week_04/demotree.js @@ -1,3 +1,15 @@ +const dfs_wrap = (root) => { + const dfs_recur = (root) => { + if (root == null) return + res.push(root.val) + dfs_recur(root.left) + dfs_recur(root.right) + } + const res = [] + dfs_recur(root) + return res +} + const dfs = (root) => { const res = [], stack = [root] while(stack.length > 0) { @@ -15,9 +27,7 @@ const bfs = (root) => { while(queue.length > 0) { const p = queue.pop() if (p == null) continue - res.push(p.val) - queue.unshift(p.left) queue.unshift(p.right) } @@ -26,39 +36,37 @@ const bfs = (root) => { // ---- test case ---- -function TreeNode(val, left, right) { - this.val = (val===undefined ? 0 : val) - this.left = (left===undefined ? null : left) - this.right = (right===undefined ? null : right) +function TreeNode(val) { + this.val = val + this.left = null + this.right = null } -const buildTree = function(preorder, inorder) { - const helper = (preorder, pStart, pEnd, inorder, iStart, iEnd) => { - // terminator - if (pStart === pEnd) { - return null - } - // process [rootValue -> iRootIdx -> leftSize] - const rootValue = preorder[pStart], root = new TreeNode(rootValue) - let iRootIdx = 0 - for(let i = 0; i < inorder.length; ++i) { - if (inorder[i] === rootValue) { - iRootIdx = i - break - } - } - const leftSize = iRootIdx - iStart - // drill down - root.left = helper(preorder, pStart + 1, pStart + leftSize + 1, inorder, iStart, iRootIdx) - root.right = helper(preorder, pStart + leftSize + 1, pEnd, inorder, iRootIdx + 1, iEnd) - // revert states +const deserialize = function(data) { + const treeVals = data.split(',') + + const buildTree = (list) => { + const rootVal = list.shift() + if (rootVal === 'X') return null + const root = new TreeNode(rootVal) + root.left = buildTree(list) + root.right = buildTree(list) return root } - - return helper(preorder, 0, preorder.length, inorder, 0, inorder.length) + return buildTree(treeVals) } -const t = buildTree([3,9,20,15,7], [9,3,15,20,7]) +/* + 1 + / \ + 2 5 + / \ / +3 4 6 + / \ + 8 9 +*/ +const t = deserialize('1,2,3,X,X,4,8,X,X,9,X,X,5,6,X,X,X') console.log(JSON.stringify(t, null, 2)) -console.log(bfs(t)) +console.log(dfs_wrap(t)) console.log(dfs(t)) +console.log(bfs(t)) From 83f9076d49c14e0c20af47e39744e410cfbecc20 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Feb 2021 17:31:28 +0800 Subject: [PATCH 057/210] add code template for Week04 Homework --- Week_04/033search.js | 10 +++++ Week_04/045jump.js | 10 +++++ Week_04/055canJump.js | 10 +++++ Week_04/074searchMatrix.js | 10 +++++ Week_04/122maxProfit.js | 9 +++++ Week_04/126findLadders.js | 12 ++++++ Week_04/127ladderLength.js | 12 ++++++ Week_04/153findMin.js | 10 +++++ Week_04/200numIslands.js | 10 +++++ Week_04/455findContentChildren.js | 10 +++++ Week_04/529updateBoard.js | 11 ++++++ Week_04/860lemonadeChange.js | 9 +++++ Week_04/874robotSim.js | 11 ++++++ Week_04/README.md | 6 +-- Week_04/homework.md | 66 +++++++++++++++++++++++++++++++ 15 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 Week_04/033search.js create mode 100644 Week_04/045jump.js create mode 100644 Week_04/055canJump.js create mode 100644 Week_04/074searchMatrix.js create mode 100644 Week_04/122maxProfit.js create mode 100644 Week_04/126findLadders.js create mode 100644 Week_04/127ladderLength.js create mode 100644 Week_04/153findMin.js create mode 100644 Week_04/200numIslands.js create mode 100644 Week_04/455findContentChildren.js create mode 100644 Week_04/529updateBoard.js create mode 100644 Week_04/860lemonadeChange.js create mode 100644 Week_04/874robotSim.js create mode 100644 Week_04/homework.md diff --git a/Week_04/033search.js b/Week_04/033search.js new file mode 100644 index 00000000..7d882e13 --- /dev/null +++ b/Week_04/033search.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ + * + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +const search = function(nums, target) { + +} diff --git a/Week_04/045jump.js b/Week_04/045jump.js new file mode 100644 index 00000000..30b488cf --- /dev/null +++ b/Week_04/045jump.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/jump-game-ii/ + * + * @param {number[]} nums + * @return {number} + */ + +const jump = function(nums) { + +} diff --git a/Week_04/055canJump.js b/Week_04/055canJump.js new file mode 100644 index 00000000..2d857d06 --- /dev/null +++ b/Week_04/055canJump.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/jump-game/ + * + * @param {number[]} nums + * @return {boolean} + */ + +const canJump = function(nums) { + +} diff --git a/Week_04/074searchMatrix.js b/Week_04/074searchMatrix.js new file mode 100644 index 00000000..98472552 --- /dev/null +++ b/Week_04/074searchMatrix.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/search-a-2d-matrix/ + * + * @param {number[][]} matrix + * @param {number} target + * @return {boolean} + */ +const searchMatrix = function(matrix, target) { + +} diff --git a/Week_04/122maxProfit.js b/Week_04/122maxProfit.js new file mode 100644 index 00000000..1fa072b3 --- /dev/null +++ b/Week_04/122maxProfit.js @@ -0,0 +1,9 @@ +/** + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ + * + * @param {number[]} prices + * @return {number} + */ +const maxProfit = function(prices) { + +} diff --git a/Week_04/126findLadders.js b/Week_04/126findLadders.js new file mode 100644 index 00000000..d563f68b --- /dev/null +++ b/Week_04/126findLadders.js @@ -0,0 +1,12 @@ +/** + * https://leetcode-cn.com/problems/word-ladder-ii/description/ + * hard + * + * @param {string} beginWord + * @param {string} endWord + * @param {string[]} wordList + * @return {string[][]} + */ +const findLadders = function(beginWord, endWord, wordList) { + +} diff --git a/Week_04/127ladderLength.js b/Week_04/127ladderLength.js new file mode 100644 index 00000000..6be5288d --- /dev/null +++ b/Week_04/127ladderLength.js @@ -0,0 +1,12 @@ +/** + * https://leetcode-cn.com/problems/word-ladder/description/ + * hard + * + * @param {string} beginWord + * @param {string} endWord + * @param {string[]} wordList + * @return {number} + */ +const ladderLength = function(beginWord, endWord, wordList) { + +} diff --git a/Week_04/153findMin.js b/Week_04/153findMin.js new file mode 100644 index 00000000..f1b26ea6 --- /dev/null +++ b/Week_04/153findMin.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ + * + * @param {number[]} nums + * @return {number} + */ + +const findMin = function(nums) { + +} diff --git a/Week_04/200numIslands.js b/Week_04/200numIslands.js new file mode 100644 index 00000000..59f1a217 --- /dev/null +++ b/Week_04/200numIslands.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/number-of-islands/ + * medium + * + * @param {character[][]} grid + * @return {number} + */ +const numIslands = function(grid) { + +} diff --git a/Week_04/455findContentChildren.js b/Week_04/455findContentChildren.js new file mode 100644 index 00000000..15217952 --- /dev/null +++ b/Week_04/455findContentChildren.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/assign-cookies/ + * + * @param {number[]} g + * @param {number[]} s + * @return {number} + */ +var findContentChildren = function(g, s) { + +}; diff --git a/Week_04/529updateBoard.js b/Week_04/529updateBoard.js new file mode 100644 index 00000000..b8d793e8 --- /dev/null +++ b/Week_04/529updateBoard.js @@ -0,0 +1,11 @@ +/** + * https://leetcode-cn.com/problems/minesweeper/ + * medium + * + * @param {character[][]} board + * @param {number[]} click + * @return {character[][]} + */ +const updateBoard = function(board, click) { + +} diff --git a/Week_04/860lemonadeChange.js b/Week_04/860lemonadeChange.js new file mode 100644 index 00000000..589169e1 --- /dev/null +++ b/Week_04/860lemonadeChange.js @@ -0,0 +1,9 @@ +/** + * https://leetcode-cn.com/problems/lemonade-change/ + * + * @param {number[]} bills + * @return {boolean} + */ +const lemonadeChange = function(bills) { + +} diff --git a/Week_04/874robotSim.js b/Week_04/874robotSim.js new file mode 100644 index 00000000..f41683d7 --- /dev/null +++ b/Week_04/874robotSim.js @@ -0,0 +1,11 @@ +/** + * https://leetcode-cn.com/problems/walking-robot-simulation/ + * + * @param {number[]} commands + * @param {number[][]} obstacles + * @return {number} + */ + +const robotSim = function(commands, obstacles) { + +} diff --git a/Week_04/README.md b/Week_04/README.md index 930c0f74..9a790d2e 100644 --- a/Week_04/README.md +++ b/Week_04/README.md @@ -2,7 +2,7 @@ ## 第9课:深度优先搜索和广度优先搜索 -***DFS(递归版)** +**DFS(递归版)** ```js const dfs_wrap = (root) => { @@ -18,7 +18,7 @@ const dfs_wrap = (root) => { } ``` -***DFS(非递归版)** +**DFS(非递归版)** + 手动维护stack @@ -36,7 +36,7 @@ const dfs = (root) => { } ``` -***BFS** +**BFS** + 手动维护queue diff --git a/Week_04/homework.md b/Week_04/homework.md new file mode 100644 index 00000000..6270fb52 --- /dev/null +++ b/Week_04/homework.md @@ -0,0 +1,66 @@ +# 作业 + +## 1. 单词接龙(亚马逊在半年内面试常考) + ++ dfs & bfs ++ [实现代码](./127ladderLength.js) + +## 2. 单词接龙 II (微软、亚马逊、Facebook 在半年内面试中考过) + ++ dfs & bfs ++ [实现代码](./126findLadders.js) + +## 3. 岛屿数量(近半年内,亚马逊在面试中考查此题达到 350 次) + ++ dfs & bfs ++ [实现代码](./200numIslands.js) + +## 4. 扫雷游戏(亚马逊、Facebook 在半年内面试中考过) + ++ dfs & bfs ++ [实现代码](./529updateBoard.js) + +## 6. 柠檬水找零(亚马逊在半年内面试中考过) + ++ greedy ++ [实现代码](./860lemonadeChange.js) + +## 7. 买卖股票的最佳时机 II (亚马逊、字节跳动、微软在半年内面试中考过) + ++ greedy ++ [实现代码](./122maxProfit.js) + +## 8. 分发饼干(亚马逊在半年内面试中考过) + ++ greedy ++ [实现代码](./455findContentChildren.js) + +## 9. 模拟行走机器人 + ++ greedy ++ [实现代码](./874robotSim.js) + +## 10. 跳跃游戏 (亚马逊、华为、Facebook 在半年内面试中考过) + ++ greedy ++ [实现代码](./055canJump.js) + +## 11. 跳跃游戏 II (亚马逊、华为、字节跳动在半年内面试中考过) + ++ greedy ++ [实现代码](./045jump.js) + +## 12. 搜索旋转排序数组(Facebook、字节跳动、亚马逊在半年内面试常考) + ++ binarySearch ++ [实现代码](./033search.js) + +## 13. 搜索二维矩阵(亚马逊、微软、Facebook 在半年内面试中考过) + ++ binarySearch ++ [实现代码](./074searchMatrix.js) + +## 14. 寻找旋转排序数组中的最小值(亚马逊、微软、字节跳动在半年内面试中考过) + ++ binarySearch ++ [实现代码](./153findMin.js) From 2de0f19fc3affb4faa3fa8cc584b110966b1f5dd Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Feb 2021 21:00:11 +0800 Subject: [PATCH 058/210] rewrite bfs --- Week_04/102levelOrder.js | 17 ++++++++++++++++- Week_04/README.md | 17 +++++++++++------ Week_04/demotree.js | 32 +++++++++++++++++++++----------- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/Week_04/102levelOrder.js b/Week_04/102levelOrder.js index b85329e2..de4e6578 100644 --- a/Week_04/102levelOrder.js +++ b/Week_04/102levelOrder.js @@ -1,8 +1,23 @@ /** * https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ * + * 思路:【BFS】 + * 手动维护queue (push + unshift) + * 内层维护一个循环,循环当前queue的size,为一层(null不要加入queue) */ const levelOrder = function(root) { - + if (root == null) return [] + const res = [], queue = [root] + while(queue.length) { + const n = queue.length, line = [] + for(let i = 0; i < n; ++i) { // 循环n次为一层结果 + const p = queue.pop() + if (p.left != null) queue.unshift(p.left) + if (p.right != null) queue.unshift(p.right) + line.push(p.val) + } + res.push(line) + } + return res } diff --git a/Week_04/README.md b/Week_04/README.md index 9a790d2e..d8fa74cf 100644 --- a/Week_04/README.md +++ b/Week_04/README.md @@ -23,14 +23,19 @@ const dfs_wrap = (root) => { + 手动维护stack ```js +/** + * 非递归的深搜,手动维护stack (push / pop) + * 因为stack的 FILO 特点,要注意先入右子,再入左子 + * + */ const dfs = (root) => { + if (root == null) return [] const res = [], stack = [root] while(stack.length > 0) { const p = stack.pop() - if (p == null) continue + if(p.right != null) stack.push(p.right) + if(p.left != null) stack.push(p.left) res.push(p.val) - stack.push(p.right) - stack.push(p.left) } return res } @@ -42,13 +47,13 @@ const dfs = (root) => { ```js const bfs = (root) => { + if (root == null) return [] const res = [], queue = [root] while(queue.length > 0) { const p = queue.pop() - if (p == null) continue + if(p.left != null) queue.unshift(p.left) + if(p.right != null) queue.unshift(p.right) res.push(p.val) - queue.unshift(p.left) - queue.unshift(p.right) } return res } diff --git a/Week_04/demotree.js b/Week_04/demotree.js index f4ff3350..24e4d39c 100644 --- a/Week_04/demotree.js +++ b/Week_04/demotree.js @@ -10,26 +10,31 @@ const dfs_wrap = (root) => { return res } +/** + * 非递归的深搜,手动维护stack (push / pop) + * 因为stack的 FILO 特点,要注意先入右子,再入左子 + * + */ const dfs = (root) => { + if (root == null) return [] const res = [], stack = [root] while(stack.length > 0) { const p = stack.pop() - if (p == null) continue + if(p.right != null) stack.push(p.right) + if(p.left != null) stack.push(p.left) res.push(p.val) - stack.push(p.right) - stack.push(p.left) } return res } const bfs = (root) => { + if (root == null) return [] const res = [], queue = [root] while(queue.length > 0) { const p = queue.pop() - if (p == null) continue + if(p.left != null) queue.unshift(p.left) + if(p.right != null) queue.unshift(p.right) res.push(p.val) - queue.unshift(p.left) - queue.unshift(p.right) } return res } @@ -65,8 +70,13 @@ const deserialize = function(data) { / \ 8 9 */ -const t = deserialize('1,2,3,X,X,4,8,X,X,9,X,X,5,6,X,X,X') -console.log(JSON.stringify(t, null, 2)) -console.log(dfs_wrap(t)) -console.log(dfs(t)) -console.log(bfs(t)) +const t1 = deserialize('1,2,3,X,X,4,8,X,X,9,X,X,5,6,X,X,X') +console.log(JSON.stringify(t1, null, 2)) +console.log(dfs_wrap(t1)) +console.log(dfs(t1)) +console.log(bfs(t1)) + +const t2 = null +console.log(dfs_wrap(t2)) +console.log(dfs(t2)) +console.log(bfs(t2)) From 3fbad4dcc4317ea7c7e8942159320e34c58a55ed Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Feb 2021 22:52:27 +0800 Subject: [PATCH 059/210] solve link list & stack --- Week_01/001twoSum.js | 7 ++-- Week_01/011maxArea.js | 3 +- Week_01/015threeSum.js | 4 +- Week_01/020isValid.js | 31 +++++++++++++++ Week_01/021mergeTwoLists.js | 15 ++------ Week_01/024swapPairs.js | 27 +++---------- Week_01/026removeDuplicates.js | 5 ++- Week_01/042trap.js | 4 +- Week_01/066plusOne.js | 9 ++--- Week_01/070climbStairs.js | 6 +-- Week_01/075sortColors.js | 9 ++--- Week_01/088merge.js | 3 +- Week_01/155MinStack.js | 69 ++++++++++++++++++++++++++++++++++ Week_01/189rotate.js | 8 +--- Week_01/206reverseList.js | 18 +++++++++ Week_01/641MyCircularDeque.js | 2 +- 16 files changed, 155 insertions(+), 65 deletions(-) create mode 100644 Week_01/020isValid.js create mode 100644 Week_01/155MinStack.js create mode 100644 Week_01/206reverseList.js diff --git a/Week_01/001twoSum.js b/Week_01/001twoSum.js index f4b9c05a..a9adadfb 100644 --- a/Week_01/001twoSum.js +++ b/Week_01/001twoSum.js @@ -1,10 +1,9 @@ /** - * 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) * https://leetcode-cn.com/problems/two-sum/ - * @param {number[]} nums - * @param {number} target - * @return {number[]} + * 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) + * */ + const twoSum = function(nums, target) { const m = new Map() for(let i = 0; i < nums.length; ++i) { diff --git a/Week_01/011maxArea.js b/Week_01/011maxArea.js index 47b6da4a..e7ca408a 100644 --- a/Week_01/011maxArea.js +++ b/Week_01/011maxArea.js @@ -1,6 +1,7 @@ /** - * 011 盛水最多的容器 medium * https://leetcode-cn.com/problems/container-with-most-water/ + * 011 盛水最多的容器 medium + * * 思路: * 1. 暴力枚举 O(n^2) * 2. 双指针,矮的挪位置 diff --git a/Week_01/015threeSum.js b/Week_01/015threeSum.js index 018552c9..d652aa6a 100644 --- a/Week_01/015threeSum.js +++ b/Week_01/015threeSum.js @@ -1,11 +1,13 @@ /** - * 015 三数之和 medium * https://leetcode.com/problems/3sum/ + * 015 三数之和 medium + * * 思路: * 1. 暴力,三重循环(O(n^3)超时) * 2. hash,两重暴力 + hash * 3. 夹逼,因为不需要给下标,先排序后夹逼 */ + // 解法2 O(n^2) // trick: 用set 和 JSON.stringify 去重 let threeSum2 = function (nums) { diff --git a/Week_01/020isValid.js b/Week_01/020isValid.js new file mode 100644 index 00000000..41dfd949 --- /dev/null +++ b/Week_01/020isValid.js @@ -0,0 +1,31 @@ +/** + * https://leetcode-cn.com/problems/valid-parentheses/ + * 【stack】 + * + */ + +const isValid = function(s) { + const stack = [], + m = new Map([ + [')', '('], + [']', '['], + ['}', '{'] + ]) + + let res = true + for(let i = 0; i < s.length; ++i) { + const ch = s[i] + if (!m.has(ch)) { + stack.push(ch) + } else { + if (stack.length > 0 && stack[stack.length - 1] === m.get(ch)) { + stack.pop() + } else { + res = false + break + } + } + } + + return stack.length ? false : res +} diff --git a/Week_01/021mergeTwoLists.js b/Week_01/021mergeTwoLists.js index 1aa864ff..b6644621 100644 --- a/Week_01/021mergeTwoLists.js +++ b/Week_01/021mergeTwoLists.js @@ -1,20 +1,11 @@ /** - * easy | leetcode-021 | link-list * https://leetcode-cn.com/problems/merge-two-sorted-lists/ - * 思路: 类似归并排序的归并过程 - */ -/** - * Definition for singly-linked list. - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } + * easy | leetcode-021 | link-list */ + /** - * @param {ListNode} l1 - * @param {ListNode} l2 - * @return {ListNode} * 21. 合并两个有序链表 + * 思路: 类似归并排序的归并过程 * 思路: 声明一个空指针头,遍历l1 和 l2,谁的值比较小就把谁拼接在后面 */ var mergeTwoLists = function (l1, l2) { diff --git a/Week_01/024swapPairs.js b/Week_01/024swapPairs.js index 33c2a7f8..c027d0f8 100644 --- a/Week_01/024swapPairs.js +++ b/Week_01/024swapPairs.js @@ -1,16 +1,10 @@ -/** - * Definition for singly-linked list. - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ /** + * https://leetcode-cn.com/problems/swap-nodes-in-pairs/ * 24. 两两交换链表中的节点 - * 思路1: 递归 - * @param {ListNode} head - * @return {ListNode} + * */ + +// 思路1: 递归 var swapPairs = function(head) { if (!head || !head.next) { return head @@ -21,18 +15,7 @@ var swapPairs = function(head) { return newHead }; - -/** - * Definition for singly-linked list. - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -/** 思路2: 空指针头画图 - * @param {ListNode} head - * @return {ListNode} - */ +// 思路2: 非递归(空指针头) var swapPairs = function(head) { var dummy = { val: -1, next: head }, cur = dummy while(cur.next && cur.next.next) { diff --git a/Week_01/026removeDuplicates.js b/Week_01/026removeDuplicates.js index 63cb5929..cb469433 100644 --- a/Week_01/026removeDuplicates.js +++ b/Week_01/026removeDuplicates.js @@ -1,8 +1,11 @@ /** - * 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ + * 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) + * * 思路:利用数组是有序的特性,重复元素必相邻。遍历一轮,用cnt记录重复项数量,用第i个元素覆盖i-cnt个元素 + * */ + const removeDuplicates = function(nums) { if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return 0 let cnt = 0 diff --git a/Week_01/042trap.js b/Week_01/042trap.js index adbc435b..37f4835e 100644 --- a/Week_01/042trap.js +++ b/Week_01/042trap.js @@ -1,9 +1,11 @@ /** + * https://leetcode.com/problems/trapping-rain-water/ * 11. 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) * hard | leetcode-042 | array - * https://leetcode.com/problems/trapping-rain-water/ + * * 思路: maxLeft、maxRight 记录左右最高柱子 */ + var trap = function (A) { var left = 0, right = A.length - 1 var res = 0, maxLeft = 0, maxRight = 0 diff --git a/Week_01/066plusOne.js b/Week_01/066plusOne.js index 4dd1c282..34954f29 100644 --- a/Week_01/066plusOne.js +++ b/Week_01/066plusOne.js @@ -1,13 +1,10 @@ /** + * https://leetcode-cn.com/problems/plus-one/ * 9. 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) * easy | leetcode-066 | array - * https://leetcode-cn.com/problems/plus-one/ - */ -/** - * 思路:从右往左遍历,遇9进位 - * @param {number[]} digits - * @return {number[]} */ + +// 思路:从右往左遍历,遇9进位 const plusOne = function(digits) { if (Object.prototype.toString.call(digits) !== '[object Array]' || digits.length < 1) return [1] diff --git a/Week_01/070climbStairs.js b/Week_01/070climbStairs.js index f373f5e7..2766d353 100644 --- a/Week_01/070climbStairs.js +++ b/Week_01/070climbStairs.js @@ -1,9 +1,9 @@ /** * https://leetcode-cn.com/problems/climbing-stairs/ - * 思路:fibnacci数列 - * @param {number} n - * @return {number} + * */ + +// 思路:fibnacci数列 const climbStairs = function(n) { if (typeof n !== 'number' || n < 4) return n let a = 2, b = 3, c diff --git a/Week_01/075sortColors.js b/Week_01/075sortColors.js index ebaf66b2..528df518 100644 --- a/Week_01/075sortColors.js +++ b/Week_01/075sortColors.js @@ -1,13 +1,10 @@ /** - * @param {number[]} nums - * @return {void} Do not return anything, modify nums in-place instead. - */ -/** - * medium * https://leetcode-cn.com/problems/sort-colors/ - * 思路:双指针夹逼,维护l指针左边全是0,r指针右边全是2 + * medium + * */ +// 思路:双指针夹逼,维护l指针左边全是0,r指针右边全是2 const sortColors = function(nums) { if (Object.prototype.toString.call(nums) !== '[object Array]') return diff --git a/Week_01/088merge.js b/Week_01/088merge.js index 22a728fd..0025b534 100644 --- a/Week_01/088merge.js +++ b/Week_01/088merge.js @@ -1,8 +1,9 @@ /** + * https://leetcode-cn.com/problems/merge-sorted-array/ * 6. 合并两个有序数组(Facebook 在半年内面试常考) * easy | leetcode-088 | array - * https://leetcode-cn.com/problems/merge-sorted-array/ */ + const merge = function(nums1, m, nums2, n) { const toS = Object.prototype.toString, ARRTYPE = '[object Array]' if (toS.call(nums1) !== ARRTYPE || toS.call(nums2) !== ARRTYPE) return diff --git a/Week_01/155MinStack.js b/Week_01/155MinStack.js new file mode 100644 index 00000000..83a0a9bd --- /dev/null +++ b/Week_01/155MinStack.js @@ -0,0 +1,69 @@ +/** + * https://leetcode-cn.com/problems/min-stack/ + * + * 思路: + * 多维护一个辅助栈 min_stack,记录每个元素对应的 min + */ +var MinStack = function() { + this._stack = [] + this._min_stack = [] +}; + +/** + * @param {number} x + * @return {void} + */ +MinStack.prototype.push = function(x) { + this._stack.push(x) + const n = this._min_stack.length + if (n > 0) { + const top = this._min_stack[n - 1] + this._min_stack.push(Math.min(top, x)) + } else { + this._min_stack.push(x) + } +}; + +/** + * @return {void} + */ +MinStack.prototype.pop = function() { + this._min_stack.pop() + return this._stack.pop() +}; + +/** + * @return {number} + */ +MinStack.prototype.top = function() { + const n = this._stack.length + return this._stack[n - 1] +}; + +/** + * @return {number} + */ +MinStack.prototype.getMin = function() { + const n = this._min_stack.length + return this._min_stack[n - 1] +}; + +/** + * Your MinStack object will be instantiated and called as such: + * var obj = new MinStack() + * obj.push(x) + * obj.pop() + * var param_3 = obj.top() + * var param_4 = obj.getMin() + */ + + +// ---- test case ---- +var ms = new MinStack() +console.log(ms.push(-2)) +console.log(ms.push(0)) +console.log(ms.push(-3)) +console.log(ms.getMin()) +console.log(ms.pop()) +console.log(ms.top()) +console.log(ms.getMin()) diff --git a/Week_01/189rotate.js b/Week_01/189rotate.js index a1127581..2056d079 100644 --- a/Week_01/189rotate.js +++ b/Week_01/189rotate.js @@ -1,14 +1,10 @@ /** + * https://leetcode-cn.com/problems/rotate-array/ * 4. 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) * medium | leetcode-189 | array - * https://leetcode-cn.com/problems/rotate-array/ * 思路:反转三次,时间复杂度O(n), 空间复杂度O(1) */ -// var rotate = function(nums, k) { -// var gap = nums.length - k -// nums = nums.slice(gap).concat(nums.slice(0, gap)) -// return nums -// }; + // O(1)空间复杂度解法: 反转3次 const rotate = function(nums, k) { if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 2) return diff --git a/Week_01/206reverseList.js b/Week_01/206reverseList.js new file mode 100644 index 00000000..011ef00a --- /dev/null +++ b/Week_01/206reverseList.js @@ -0,0 +1,18 @@ +/** + * https://leetcode-cn.com/problems/reverse-linked-list/ + * 思路:维护好 prev,cur + * + * @param {ListNode} head + * @return {ListNode} + */ + +const reverseList = function(head) { + let prev = null + while(head) { + const cur = head + head = head.next + cur.next = prev + prev = cur + } + return prev +} diff --git a/Week_01/641MyCircularDeque.js b/Week_01/641MyCircularDeque.js index e3904892..d30cde42 100644 --- a/Week_01/641MyCircularDeque.js +++ b/Week_01/641MyCircularDeque.js @@ -1,7 +1,7 @@ /** + * https://leetcode-cn.com/problems/design-circular-deque/?utm_source=LCUS&utm_medium=ip_redirect&utm_campaign=transfer2china * 10. 设计循环双端队列(Facebook 在 1 年内面试中考过) * medium | leetcode-641 | deque - * https://leetcode-cn.com/problems/design-circular-deque/?utm_source=LCUS&utm_medium=ip_redirect&utm_campaign=transfer2china * 思路: js的array完全是超集,约束下 length 可以很简单实现 */ From d1a09fa9592d6efa6cc5aebd92bdb8639158df04 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 22 Feb 2021 01:15:16 +0800 Subject: [PATCH 060/210] re learn week02 --- Week_01/001twoSum.js | 1 + Week_02/049groupAnagram.js | 31 ++++++ Week_02/094inorderTraversal.js | 32 ++++++ Week_02/104.js | 11 +- Week_02/144preorderTraversal.js | 30 ++++++ Week_02/242isAnagram.js | 23 ++++ Week_02/429levelOrder.js | 20 ++++ Week_02/589preorder.js | 32 ++++++ Week_02/590postorder.js | 33 ++++++ Week_02/README.md | 6 ++ Week_02/homework.js | 179 -------------------------------- Week_02/homework.md | 61 +++++++++++ 12 files changed, 270 insertions(+), 189 deletions(-) create mode 100644 Week_02/049groupAnagram.js create mode 100644 Week_02/094inorderTraversal.js create mode 100644 Week_02/144preorderTraversal.js create mode 100644 Week_02/242isAnagram.js create mode 100644 Week_02/429levelOrder.js create mode 100644 Week_02/589preorder.js create mode 100644 Week_02/590postorder.js create mode 100644 Week_02/homework.md diff --git a/Week_01/001twoSum.js b/Week_01/001twoSum.js index a9adadfb..991d7454 100644 --- a/Week_01/001twoSum.js +++ b/Week_01/001twoSum.js @@ -5,6 +5,7 @@ */ const twoSum = function(nums, target) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 2) return [] const m = new Map() for(let i = 0; i < nums.length; ++i) { if (m.has(nums[i])) { diff --git a/Week_02/049groupAnagram.js b/Week_02/049groupAnagram.js new file mode 100644 index 00000000..314529dc --- /dev/null +++ b/Week_02/049groupAnagram.js @@ -0,0 +1,31 @@ +/** + * https://leetcode-cn.com/problems/group-anagrams/ + * 字母异位词分组 + * + * 【map】 + * + */ + +const groupAnagrams = function(strs) { + if (!Object.prototype.toString.apply(strs) === '[object Array]' + || strs.length < 1 + ) return [] + const m = {}, startCodePoint = 'a'.codePointAt(0) + strs.forEach(str => { + const cntArr = new Array(26).fill(0) + for(let i = 0; i < str.length; ++i) { + ++cntArr[str.codePointAt(i) - startCodePoint] + } + const key = cntArr.toString() + if (m[key] === void(0)) { + m[key] = [str] + } else { + m[key].push(str) + } + }) + return Object.values(m) +} + + +// ---- test case ---- +console.log(groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"])) diff --git a/Week_02/094inorderTraversal.js b/Week_02/094inorderTraversal.js new file mode 100644 index 00000000..74f93dae --- /dev/null +++ b/Week_02/094inorderTraversal.js @@ -0,0 +1,32 @@ +/** + * https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + */ + +// 1. 递归DFS +const inorderTraversal1 = function(root) { + if (root == null) return [] + const res = [] + const dfs = (p) => { + if(p.left) dfs(p.left) + res.push(p.val) + if(p.right) dfs(p.right) + } + dfs(root) + return res +} + +// 2. 非递归,手动维护stack +const inorderTraversal = function(root) { + if (root == null) return [] + const res = [], stack = [] + while(root || stack.length) { + while (root) { // 往左一直寻找,压栈 + stack.push(root) + root = root.left + } + root = stack.pop() + res.push(root.val) + root = root.right + } + return res +} diff --git a/Week_02/104.js b/Week_02/104.js index a2450452..d794ba94 100644 --- a/Week_02/104.js +++ b/Week_02/104.js @@ -1,17 +1,8 @@ /** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } - */ -/** - * @param {TreeNode} root - * @return {number} * https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/submissions/ * 思路:递归遍历左右子树 */ + var maxDepth = function(root) { if (!root) return 0 const left = maxDepth(root.left) diff --git a/Week_02/144preorderTraversal.js b/Week_02/144preorderTraversal.js new file mode 100644 index 00000000..069f1f11 --- /dev/null +++ b/Week_02/144preorderTraversal.js @@ -0,0 +1,30 @@ +/** + * https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ + * 【dfs】 + */ + +// 1. 递归解法 +const preorderTraversal1 = function(root) { + if (root == null) return [] + const res = [] + const dfs = (root) => { + res.push(root.val) + if (root.left) dfs(root.left) + if (root.right) dfs(root.right) + } + dfs(root) + return res +} + +// 2. 非递归解法 +const preorderTraversal = function(root) { + if (root == null) return [] + const res = [], stack = [root] + while(stack.length) { + const p = stack.pop() + if(p.right) stack.push(p.right) + if(p.left) stack.push(p.left) + res.push(p.val) + } + return res +} diff --git a/Week_02/242isAnagram.js b/Week_02/242isAnagram.js new file mode 100644 index 00000000..23bf8403 --- /dev/null +++ b/Week_02/242isAnagram.js @@ -0,0 +1,23 @@ +/** + * https://leetcode-cn.com/problems/valid-anagram/ + * 思路:map统计 + * + */ + +const isAnagram = function(s, t) { + if ( typeof s != 'string' + || typeof t != 'string' + || s.length !== t.length + ) return false + const arr = new Array(26).fill(0), + startCodePoint = 'a'.codePointAt(0) + for(let i = 0; i < s.length; ++i) { + const idx = s[i].codePointAt(0) - startCodePoint + ++arr[idx] + } + for(let i = 0; i < t.length; ++i) { + const idx = t[i].codePointAt(0) - startCodePoint + --arr[idx] + } + return arr.filter(item => item != 0).length === 0 +} diff --git a/Week_02/429levelOrder.js b/Week_02/429levelOrder.js new file mode 100644 index 00000000..40b8f28e --- /dev/null +++ b/Week_02/429levelOrder.js @@ -0,0 +1,20 @@ +/** + * https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/ + * 【BFS】 + */ + +const levelOrder = function(root) { + if (root == null) return [] + const res = [], queue = [root] + while(queue.length) { + const line = [], n = queue.length + for(let i = 0; i < n; ++i) { + const root = queue.pop() + if (root.children.length) + root.children.forEach(child => queue.unshift(child)) + line.push(root.val) + } + res.push(line) + } + return res +} diff --git a/Week_02/589preorder.js b/Week_02/589preorder.js new file mode 100644 index 00000000..5b267287 --- /dev/null +++ b/Week_02/589preorder.js @@ -0,0 +1,32 @@ +/** + * https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/ + * + */ + +// 1. 递归版 dfs +const preorder1 = function(root) { + if (root == null) return [] + const res = [] + const dfs = (p) => { + res.push(p.val) + p.children && p.children.forEach(child => { + if (child) dfs(child) + }) + } + dfs(root) + return res +} + +// !! 2. 非递归版 +const preorder = function(root) { + if (root == null) return [] + const res = [], stack = [root] + while (stack.length) { + const p = stack.pop() + if (p.children) + for(let i = p.children.length - 1; i >= 0; --i) + stack.push(p.children[i]) + res.push(p.val) + } + return res +} diff --git a/Week_02/590postorder.js b/Week_02/590postorder.js new file mode 100644 index 00000000..553320e5 --- /dev/null +++ b/Week_02/590postorder.js @@ -0,0 +1,33 @@ +/** + * https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/ + * + */ + +// 1. 递归版 dfs +const postorder = function(root) { + if (root == null) return [] + const res = [] + const dfs = (p) => { + p.children && p.children.forEach(child => { + if (child) dfs(child) + }) + res.push(p.val) + } + dfs(root) + return res +} + +// !! 2. 非递归版 【反转】 +// trick 孩子从左往右压栈,出来则是从右往左遍历。最后再翻转 +const postorder = function(root) { + if (root == null) return [] + const res = [], stack = [root] + while (stack.length) { + root = stack.pop() + if (root) res.push(root.val) + root.children.forEach(child => { + stack.push(child) + }) + } + return res.reverse() +} diff --git a/Week_02/README.md b/Week_02/README.md index 0b3f6b80..e33257ed 100644 --- a/Week_02/README.md +++ b/Week_02/README.md @@ -59,3 +59,9 @@ ## 第6课:堆和二叉堆、图 +**[heap](https://www.geeksforgeeks.org/heap-sort/)** + ++ 时间复杂度 O(nlogn), 稳定的原地排序 ++ https://time.geekbang.org/column/article/69913 ++ Step1: 建堆 ++ Step2: 排序 diff --git a/Week_02/homework.js b/Week_02/homework.js index c95682b6..bc6faee0 100644 --- a/Week_02/homework.js +++ b/Week_02/homework.js @@ -1,182 +1,3 @@ -/** - * 2. 有效字母的异位词(亚马逊、Facebook、谷歌在半年内面试中考过) - * leetcode-242 | easy - * https://leetcode-cn.com/problems/valid-anagram/submissions/ - * 思路1: 排序 O(nlogn) - */ -var isAnagram = function (s, t) { - if (s.length !== t.length) return false; - var stringSort = function (str) { - return str.split("").sort().join(""); - }; - return stringSort(s) === stringSort(t); -}; -/** 思路2: 用hashmap统计,计数 */ -var isAnagram = function (s, t) { - if (s.length !== t.length) return false; - var map = {}; - for (var i = 0; i < s.length; ++i) { - if (map[s[i]] === void 0) { - map[s[i]] = 1; - } else { - ++map[s[i]]; - } - } - for (var i = 0; i < t.length; ++i) { - if (map[t[i]] === void 0 || map[t[i]] <= 0) { - return false; - } else { - --map[t[i]]; - } - } - for (key in map) { - if (map[key] !== 0) { - return false; - } - } - return true; -}; -/** 思路3: 数组记录,增减记数(O(n))trick: charCodeAt */ -var isAnagram = function (s, t) { - if (s.length !== t.length) return false; - var arr = Array(26).fill(0); - for (var i = 0; i < s.length; ++i) { - ++arr[s[i].charCodeAt(0) - "a".charCodeAt(0)]; - } - for (var i = 0; i < t.length; ++i) { - --arr[t[i].charCodeAt(0) - "a".charCodeAt(0)]; - } - return arr.filter((item) => item !== 0).length === 0; -}; - -/** - * 3. 两数之和(近半年内,亚马逊考查此题达到 216 次、字节跳动 147 次、谷歌 104 次,Facebook、苹果、微软、腾讯也在近半年内面试常考) - * https://leetcode-cn.com/problems/two-sum/ - */ -var twoSum = function (nums, target) { - var hashMap = {}; - for (var i = 0; i < nums.length; ++i) { - if (hashMap[nums[i]] === void 0) { - hashMap[target - nums[i]] = i; - } else { - return [hashMap[nums[i]], i]; - } - } - return []; -}; - -/** - * 4. N 叉树的前序遍历(亚马逊在半年内面试中考过) - * https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/ - * leetcode-589 - * 思路1: 递归 + 闭包函数 - */ -/** - * @param {Node} root - * @return {number[]} - */ -var preorder = function (root) { - var res = []; - (function (root) { - if (root !== null) { - res.push(root.val) - root.children.forEach(child => { - arguments.callee(child) - }) - } - })(root) - return res -}; - -/** - * 5. HeapSort - * 自学 https://www.geeksforgeeks.org/heap-sort/ - * 时间复杂度 O(nlogn), 稳定的原地排序 - * https://time.geekbang.org/column/article/69913 - * Step1: 建堆 - * Step2: 排序 - */ - -/** - * 6. 字母异位词分组(亚马逊在半年内面试中常考) - * https://leetcode-cn.com/problems/group-anagrams/ - * medium | leetcode 049 - * 思路:记录到哈希表中,key值为统计数组toString,value值为字符串数组。最后返回 map 所有的values - */ -var groupAnagrams = function(strs) { - if (!Object.prototype.toString.apply(strs) === '[object Array]' - || strs.length < 1 - ) { - return [] - } - - var map = {} - strs.forEach(str => { - var arr = Array(26).fill(0) - str.split('').forEach(ch => { - ++arr[ch.charCodeAt(0) - 'a'.charCodeAt(0)] - }) - if (map[arr.toString()] === void(0)) { - map[arr.toString()] = [str] - } else { - map[arr.toString()].push(str) - } - }) - return Object.values(map) -}; - -/** - * 7. 二叉树的中序遍历(亚马逊、字节跳动、微软在半年内面试中考过) - * https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ - * leetcode-94 - */ -var inorderTraversal = function (root) { - var res = []; - (function (root) { - if (root !== null) { - arguments.callee(root.left) - res.push(root.val) - arguments.callee(root.right) - } - })(root) - return res -}; - -/** - * 8. 二叉树的前序遍历(字节跳动、谷歌、腾讯在半年内面试中考过) - * https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ - * leetcode-144 - */ -var preorderTraversal = function (root) { - var res = []; - (function (root) { - if (root !== null) { - res.push(root.val) - arguments.callee(root.left) - arguments.callee(root.right) - } - })(root) - return res -}; - -/** - * 9. N 叉树的层序遍历(亚马逊在半年内面试中考过) - * https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/submissions/ - * easy | leetcode-590 - */ -var postorder = function (root) { - var res = []; - (function (root) { - if (root !== null) { - root.children.forEach(child => { - arguments.callee(child) - }) - res.push(root.val) - } - })(root) - return res -}; - /** * 10. 丑数(字节跳动在半年内面试中考过) * https://leetcode-cn.com/problems/ugly-number/ diff --git a/Week_02/homework.md b/Week_02/homework.md new file mode 100644 index 00000000..7cf5c4a3 --- /dev/null +++ b/Week_02/homework.md @@ -0,0 +1,61 @@ +# 作业 + +## 第5课:哈希表、映射、集合 + +### 1. 有效的字母异位词(亚马逊、Facebook、谷歌在半年内面试中考过) + ++ map ++ [实现代码](./242isAnagram.js) + +### 2. 字母异位词分组(亚马逊在半年内面试中常考) + ++ map ++ [实现代码](./049groupAnagram.js) + +### 3. 两数之和(近半年内,亚马逊考查此题达到 216 次、字节跳动 147 次、谷歌 104 次,Facebook、苹果、微软、腾讯也在近半年内面试常考) + ++ map ++ [实现代码](../Week_01/001twoSum.js) + + + + + +## 第6课:树、二叉树、二叉搜索树 + +### 4. 二叉树的前序遍历(字节跳动、谷歌、腾讯在半年内面试中考过) + ++ tree ++ [实现代码](./144preorderTraversal.js) + +### 5. 二叉树的中序遍历(亚马逊、字节跳动、微软在半年内面试中考过) + ++ tree ++ [实现代码](./094inorderTraversal.js) + +### 6. N 叉树的前序遍历(亚马逊在半年内面试中考过) + ++ tree ++ [实现代码](./589preorder.js) + +### 7. N 叉树的后序遍历 + ++ tree ++ [实现代码](./590postorder.js) + +### 8. N 叉树的层序遍历(亚马逊在半年内面试中考过) + ++ tree ++ [实现代码](./429levelOrder.js) + + + + + +## 第6课:堆和二叉堆、图 + +### 9. 丑数(字节跳动在半年内面试中考过) + + +### 10. 前 K 个高频元素(亚马逊在半年内面试中常考) + From 7ae12ea94eb0d77653eaf0ad7d655b8f5f001597 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 22 Feb 2021 15:50:59 +0800 Subject: [PATCH 061/210] solve ugly number * 6 --- Week_02/1201nthUglyNumber.js | 83 ++++++++++++++++++++++++++++++++ Week_02/263isUgly.js | 16 ++++++ Week_02/264nthUglyNumber.js | 26 ++++++++++ Week_02/313nthSuperUglyNumber.js | 29 +++++++++++ Week_02/homework.js | 15 ------ Week_02/homework.md | 9 ++++ 6 files changed, 163 insertions(+), 15 deletions(-) create mode 100644 Week_02/1201nthUglyNumber.js create mode 100644 Week_02/263isUgly.js create mode 100644 Week_02/264nthUglyNumber.js create mode 100644 Week_02/313nthSuperUglyNumber.js diff --git a/Week_02/1201nthUglyNumber.js b/Week_02/1201nthUglyNumber.js new file mode 100644 index 00000000..d75f259c --- /dev/null +++ b/Week_02/1201nthUglyNumber.js @@ -0,0 +1,83 @@ +/** + * https://leetcode-cn.com/problems/ugly-number-iii/ + * + * 解法: + * 1. 二分 + * 2. 容斥原理,计算个数 + */ + +// 最大公约数(greatest common divisor) +const gcd = (x, y) => x % y ? gcd(y, x % y) : y +// 最小公倍数(least common multiple) +const lcm = (x, y) => x * y / gcd(x, y) + +// 解法一 +const nthUglyNumber1 = function(n, a, b, c) { + const ab = lcm(a, b), + ac = lcm(a, c), + bc = lcm(b, c), + abc = lcm(ab, c) + let left = 0, right = n * Math.min(a, b, c) + while(left <= right) { + const mid = Math.floor((left + right) / 2) + const num = Math.floor(mid / a) + + Math.floor(mid / b) + + Math.floor(mid / c) + - Math.floor(mid / ab) + - Math.floor(mid / ac) + - Math.floor(mid / bc) + + Math.floor(mid / abc) + if (num >= n) { + right = mid - 1 + } else { + left = mid + 1 + } + } + return left +} + +// 解法二:【优化】位运算提速(但需要用bigInt类型,防止越界) +const nthUglyNumber = function(n, a, b, c) { + let left = 0n, + right = BigInt(n) * BigInt(Math.min(a, b, c)) + a = BigInt(a) + b = BigInt(b) + c = BigInt(c) + const ab = lcm(a, b), + ac = lcm(a, c), + bc = lcm(b, c), + abc = lcm(ab, c) + while(left <= right) { + const mid = (left + right) >> 1n + const cnt = ((mid / a ) >> 0n) + + ((mid / b ) >> 0n) + + ((mid / c ) >> 0n) + - ((mid / ab ) >> 0n) + - ((mid / ac ) >> 0n) + - ((mid / bc ) >> 0n) + + ((mid / abc) >> 0n) + + if (cnt >= n) { + right = mid - 1n + } else { + left = mid + 1n + } + } + return left +} + +// ---- test case ---- +console.log(nthUglyNumber1(3, 2, 3, 5)) +console.log(nthUglyNumber1(4, 2, 3, 4)) +console.log(nthUglyNumber1(5, 2, 11, 13)) +console.log(nthUglyNumber1(5, 2, 3, 3)) +console.log(nthUglyNumber1(1000000000, 2, 217983653, 336916467)) + +console.log(nthUglyNumber(3, 2, 3, 5)) +console.log(nthUglyNumber(4, 2, 3, 4)) +console.log(nthUglyNumber(5, 2, 11, 13)) +console.log(nthUglyNumber(5, 2, 3, 3)) +console.log(nthUglyNumber(1000000000, 2, 217983653, 336916467)) + + + diff --git a/Week_02/263isUgly.js b/Week_02/263isUgly.js new file mode 100644 index 00000000..ea07555c --- /dev/null +++ b/Week_02/263isUgly.js @@ -0,0 +1,16 @@ +/** + * https://leetcode-cn.com/problems/ugly-number/ + * 思路: 判断不断整除2、3、5后是否等于1 + */ + +const isUgly = function(num) { + for(let factor of [2, 3, 5]) { + while(num && num % factor === 0) num /= factor + } + return num === 1 +} + +// ---- test case ---- +void [6, 8, 14].forEach(num => { + console.log(isUgly(num)) +}) diff --git a/Week_02/264nthUglyNumber.js b/Week_02/264nthUglyNumber.js new file mode 100644 index 00000000..3c828232 --- /dev/null +++ b/Week_02/264nthUglyNumber.js @@ -0,0 +1,26 @@ +/** + * https://leetcode-cn.com/problems/ugly-number-ii/ + * + * 相同题目: + * 【剑指 Offer 49. 丑数】 https://leetcode-cn.com/problems/chou-shu-lcof/ + * 【面试题 17.09. 第 k 个数】 https://leetcode-cn.com/problems/get-kth-magic-number-lcci/ + */ + +// 解法: 三指针法递推 +const nthUglyNumber = function(n) { + if (n < 7) return n + let p2 = p3 = p5 = 0, nums = [1] + for (let i = 1; i < n; ++i) { + const x = 2 * nums[p2], y = 3 * nums[p3], z = 5 * nums[p5] + nums[i] = Math.min(x, y, z) + if (nums[i] === x) ++p2 + if (nums[i] === y) ++p3 + if (nums[i] === z) ++p5 + } + return nums[n - 1] +} + +// ---- test case ---- +for(let i = 1; i <= 100; ++i) { + console.log(`${i}: ${nthUglyNumber(i)}`) +} diff --git a/Week_02/313nthSuperUglyNumber.js b/Week_02/313nthSuperUglyNumber.js new file mode 100644 index 00000000..03825bd0 --- /dev/null +++ b/Week_02/313nthSuperUglyNumber.js @@ -0,0 +1,29 @@ +/** + * https://leetcode-cn.com/problems/super-ugly-number/ + * + */ + +// 思路:此题采用丑数的定义一,用递推法求解 +const nthSuperUglyNumber = function(n, primes) { + const size = primes.length, + idxs = new Array(size).fill(0), + arr = [1] + + for(let i = 1; i < n; ++i) { + const nexts = [] + for(let j = 0; j < size; ++j) { + nexts[j] = primes[j] * arr[idxs[j]] + } + arr[i] = Math.min(...nexts) + nexts.forEach((next, idx) => { + if (arr[i] === next) { + ++idxs[idx] + } + }) + // console.log("🚀", i, primes, idxs, nexts) + } + return arr[n - 1] +} + +// ---- test case ---- +console.log(nthSuperUglyNumber(12, [2,7,13,19])) diff --git a/Week_02/homework.js b/Week_02/homework.js index bc6faee0..632161b0 100644 --- a/Week_02/homework.js +++ b/Week_02/homework.js @@ -1,18 +1,3 @@ -/** - * 10. 丑数(字节跳动在半年内面试中考过) - * https://leetcode-cn.com/problems/ugly-number/ - * easy | leetcode-263 - * 思路: 两重循环,一直判断是否整除2、3、5无余数。最后判断是否得到1 - */ -var isUgly = function(num) { - for(var p of [2, 3, 5]) { - while(num && num % p === 0) { - num /= p - } - } - return num === 1 -}; - /** * 11. 前 K 个高频元素(亚马逊在半年内面试中常考) * https://leetcode-cn.com/problems/top-k-frequent-elements/ diff --git a/Week_02/homework.md b/Week_02/homework.md index 7cf5c4a3..ac421579 100644 --- a/Week_02/homework.md +++ b/Week_02/homework.md @@ -56,6 +56,15 @@ ### 9. 丑数(字节跳动在半年内面试中考过) ++ [丑数](./263isUgly.js) ++ [丑数II](./264nthUglyNumber.js) ++ [丑数III](./1201nthUglyNumber.js) ++ [超级丑数](./313nthSuperUglyNumber.js) + +**丑数有两种定义** + +1. 定义一:质因数只包含 a,b,c,... -> 多指针递推法 +2. 定义二:能被 a,b,c,... 整除的 -> 容斥原理 + 二分法 ### 10. 前 K 个高频元素(亚马逊在半年内面试中常考) From 2114381a6dd6c0d174ae27e42b56b4cf1efed811 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 22 Feb 2021 16:43:33 +0800 Subject: [PATCH 062/210] solve topKFrequent use heaq --- Week_02/347topKFrequent.js | 119 +++++++++++++++++++++++++++++++++++++ Week_02/homework.js | 32 ---------- Week_02/homework.md | 2 + 3 files changed, 121 insertions(+), 32 deletions(-) create mode 100644 Week_02/347topKFrequent.js delete mode 100644 Week_02/homework.js diff --git a/Week_02/347topKFrequent.js b/Week_02/347topKFrequent.js new file mode 100644 index 00000000..68b4aa62 --- /dev/null +++ b/Week_02/347topKFrequent.js @@ -0,0 +1,119 @@ +/** + * https://leetcode-cn.com/problems/top-k-frequent-elements/ + * + */ + +// 解法一:用map统计,再排序,取前k项 O(nlogn) +const topKFrequent1 = function(nums, k) { + const m = {} + for(let i = 0; i < nums.length; ++i) { + if (m[nums[i]] !== void(0)) { + ++m[nums[i]] + } else { + m[nums[i]] = 1 + } + } + const sortedM = Object.entries(m).sort(([_k1, v1], [_k2, v2]) => v2 - v1) // 按 value 逆序 + return sortedM.map(m => Number(m[0])).slice(0, k) +} + + +const top = 0 +const parent = i => ((i+1) >>> 1) - 1 +const left = i => (i << 1) + 1 +const right = i => (i + 1) << 1 + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this._heap = []; + this._comparator = comparator; + } + size() { + return this._heap.length; + } + isEmpty() { + return this.size() == 0; + } + peek() { + return this._heap[top]; + } + push(...values) { + values.forEach(value => { + this._heap.push(value); + this._siftUp(); + }); + return this.size(); + } + pop() { + const poppedValue = this.peek(); + const bottom = this.size() - 1; + if (bottom > top) { + this._swap(top, bottom); + } + this._heap.pop(); + this._siftDown(); + return poppedValue; + } + replace(value) { + const replacedValue = this.peek(); + this._heap[top] = value; + this._siftDown(); + return replacedValue; + } + _greater(i, j) { + return this._comparator(this._heap[i], this._heap[j]); + } + _swap(i, j) { + [this._heap[i], this._heap[j]] = [this._heap[j], this._heap[i]]; + } + _siftUp() { + let node = this.size() - 1; + while (node > top && this._greater(node, parent(node))) { + this._swap(node, parent(node)); + node = parent(node); + } + } + _siftDown() { + let node = top; + while ( + (left(node) < this.size() && this._greater(left(node), node)) || + (right(node) < this.size() && this._greater(right(node), node)) + ) { + let maxChild = (right(node) < this.size() && this._greater(right(node), left(node))) ? right(node) : left(node); + this._swap(node, maxChild); + node = maxChild; + } + } +} + +// 解法二:利用heap O(nlogk) +const topKFrequent = function(nums, k) { + const m = {}, res = [] + for(let i = 0; i < nums.length; ++i) { + if (m[nums[i]] !== void(0)) { + ++m[nums[i]] + } else { + m[nums[i]] = 1 + } + } + const mEntries = Object.entries(m) + const pq = new PriorityQueue( + ([_k1, v1], [_k2, v2]) => {return v1 - v2 > 0} + ) + mEntries.forEach(entry => { + pq.push(entry) + // console.log(pq) + }) + for(let i = 0; i < k; ++i) { + // console.log(pq.peek()) + res.push(pq.pop()) + } + return res.map(m => Number(m[0])) +} + + +// ---- test case ---- +console.log(topKFrequent1([2,2,1,1,1,2,2,3], 2)) +console.log(topKFrequent([2,2,1,1,1,2,2,3], 2)) + + diff --git a/Week_02/homework.js b/Week_02/homework.js deleted file mode 100644 index 632161b0..00000000 --- a/Week_02/homework.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * 11. 前 K 个高频元素(亚马逊在半年内面试中常考) - * https://leetcode-cn.com/problems/top-k-frequent-elements/ - * medium | leetcode-347 - * 思路1: - * Step1: map统计 O(n) - * Step2: 放入数组 - * Step3: 按照 v 排序 O(nlogn) - * Step4: 取出前k个 - */ -var topKFrequent = function(nums, k) { - var map = {} - nums.forEach(num => { - if (map[num] === void(0)) { - map[num] = 1 - } else { - ++map[num] - } - }) - var arr = [] - for(var key in map) { - arr.push([key, map[key]]) - } - arr.sort(function(a, b) { - return b[1] - a[1] - }) - var res = [] - for(var i = 0; i < k; ++i) { - res.push(arr[i][0]) - } - return res -}; diff --git a/Week_02/homework.md b/Week_02/homework.md index ac421579..35dfd76a 100644 --- a/Week_02/homework.md +++ b/Week_02/homework.md @@ -68,3 +68,5 @@ ### 10. 前 K 个高频元素(亚马逊在半年内面试中常考) ++ heap ++ [实现代码](./347topKFrequent.js) From 7c44934125b8ea0dbd2cb9027cbafdb028bfbe19 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 22 Feb 2021 16:48:10 +0800 Subject: [PATCH 063/210] solve topKFrequent use heaq --- Week_02/347topKFrequent.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Week_02/347topKFrequent.js b/Week_02/347topKFrequent.js index 68b4aa62..ab03c249 100644 --- a/Week_02/347topKFrequent.js +++ b/Week_02/347topKFrequent.js @@ -88,6 +88,7 @@ class PriorityQueue { // 解法二:利用heap O(nlogk) const topKFrequent = function(nums, k) { + // 1. 统计 const m = {}, res = [] for(let i = 0; i < nums.length; ++i) { if (m[nums[i]] !== void(0)) { @@ -96,18 +97,19 @@ const topKFrequent = function(nums, k) { m[nums[i]] = 1 } } - const mEntries = Object.entries(m) + // 2. 建堆,比较函数 v1 - v2 > 0(按次数降序) const pq = new PriorityQueue( ([_k1, v1], [_k2, v2]) => {return v1 - v2 > 0} ) - mEntries.forEach(entry => { + // 3. 入堆 + Object.entries(m).forEach(entry => { pq.push(entry) - // console.log(pq) }) + // 4. 取堆顶 k 次 for(let i = 0; i < k; ++i) { - // console.log(pq.peek()) res.push(pq.pop()) } + // 5. 取 key 构造结果 return res.map(m => Number(m[0])) } From 1069db51b80a72da06589128df30c8ebb37f8004 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 22 Feb 2021 17:07:00 +0800 Subject: [PATCH 064/210] add some template --- Week_02/347topKFrequent.js | 1 + Week_05/README.md | 4 +++- Week_06/README.md | 5 ++++- Week_06/homework.md | 39 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 Week_06/homework.md diff --git a/Week_02/347topKFrequent.js b/Week_02/347topKFrequent.js index ab03c249..c8f45500 100644 --- a/Week_02/347topKFrequent.js +++ b/Week_02/347topKFrequent.js @@ -113,6 +113,7 @@ const topKFrequent = function(nums, k) { return res.map(m => Number(m[0])) } +// TODO 解法三:快排思想 // ---- test case ---- console.log(topKFrequent1([2,2,1,1,1,2,2,3], 2)) diff --git a/Week_05/README.md b/Week_05/README.md index 50de3041..93c95ca1 100644 --- a/Week_05/README.md +++ b/Week_05/README.md @@ -1 +1,3 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +期中考试 diff --git a/Week_06/README.md b/Week_06/README.md index 50de3041..85f8a488 100644 --- a/Week_06/README.md +++ b/Week_06/README.md @@ -1 +1,4 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 第12课:动态规划 + diff --git a/Week_06/homework.md b/Week_06/homework.md new file mode 100644 index 00000000..564e5fef --- /dev/null +++ b/Week_06/homework.md @@ -0,0 +1,39 @@ +# 动态规划作业 + +## 1. 最小路径和(亚马逊、高盛集团、谷歌在半年内面试中考过) + + +## 2. 解码方法(亚马逊、Facebook、字节跳动在半年内面试中考过) + + +## 3. 最大正方形(华为、谷歌、字节跳动在半年内面试中考过) + + +## 4. 任务调度器(Facebook 在半年内面试中常考) + + +## 5. 回文子串(Facebook、苹果、字节跳动在半年内面试中考过) + + +## 6. 最长有效括号(字节跳动、亚马逊、微软在半年内面试中考过) + + +## 7. 编辑距离(字节跳动、亚马逊、谷歌在半年内面试中考过) + + +## 8. 矩形区域不超过 K 的最大数值和(谷歌在半年内面试中考过) + + +## 9. 青蛙过河(亚马逊、苹果、字节跳动在半年内面试中考过) + + +## 10. 分割数组的最大值(谷歌、亚马逊、Facebook 在半年内面试中考过) + + +## 11. 学生出勤记录 II (谷歌在半年内面试中考过) + + +## 12. 最小覆盖子串(Facebook 在半年内面试中常考) + + +## 13. 戳气球(亚马逊在半年内面试中考过) From a4cd19462bae1b83b415b292d7d7dfbbdb5ce46d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 22 Feb 2021 23:08:38 +0800 Subject: [PATCH 065/210] re solve 046 use dfs + backtraking --- Week_03/046permute.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Week_03/046permute.js b/Week_03/046permute.js index e5cf9843..886df171 100644 --- a/Week_03/046permute.js +++ b/Week_03/046permute.js @@ -7,24 +7,27 @@ */ const permute = function(nums) { if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return [] - const res = [] - const dfs = (path, list) => { - if (path.length >= nums.length) { // terminator + const dfs = (path, remain) => { + // terminator + if (remain.length === 0) { res.push(path.slice()) return } - for(let i = 0; i < list.length; ++i) { - const [val] = list.splice(i, 1) + for(let i = 0; i < remain.length; ++i) { + // process (choose one element of 【remain】 add into 【path】) + const [ val ] = remain.splice(i, 1) path.push(val) - dfs(path, list) // process & dirll down - path.pop() // revert states - list.splice(i, 0, val) + // drill down + dfs(path, remain) + // revere states + path.pop() + remain.splice(i, 0, val) } } - dfs([], nums.slice()) + const res = [] + dfs([], nums) return res } // ---- test case ---- console.log(permute([1,2,3])) - From c222eaf1735570dbb5e01fd6c44f9dd43c2ab742 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 23 Feb 2021 22:39:40 +0800 Subject: [PATCH 066/210] greedy algo --- Week_04/045jump.js | 20 ++++++++++++++++---- Week_04/122maxProfit.js | 9 --------- Week_04/122maxProfitII.js | 18 ++++++++++++++++++ Week_04/455findContentChildren.js | 29 ++++++++++++++++++++++++----- Week_04/README.md | 2 ++ Week_04/homework.md | 2 +- 6 files changed, 61 insertions(+), 19 deletions(-) delete mode 100644 Week_04/122maxProfit.js create mode 100644 Week_04/122maxProfitII.js diff --git a/Week_04/045jump.js b/Week_04/045jump.js index 30b488cf..ecca5b3d 100644 --- a/Week_04/045jump.js +++ b/Week_04/045jump.js @@ -1,10 +1,22 @@ /** * https://leetcode-cn.com/problems/jump-game-ii/ * - * @param {number[]} nums - * @return {number} + * 55. 跳跃游戏 + * + * 思路: 从后往前贪心,依次判断第i个元素是否能到标记节点,能则记录更新 endReachable */ -const jump = function(nums) { - +const canJump = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]') return false + let endReachable = nums.length - 1 + for(let i = nums.length - 2; i >= 0; --i) { + if (nums[i] + i >= endReachable) { + endReachable = i + } + } + return endReachable === 0 } + +// ---- test case ---- +console.log(canJump([])) +console.log(canJump([0])) diff --git a/Week_04/122maxProfit.js b/Week_04/122maxProfit.js deleted file mode 100644 index 1fa072b3..00000000 --- a/Week_04/122maxProfit.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ - * - * @param {number[]} prices - * @return {number} - */ -const maxProfit = function(prices) { - -} diff --git a/Week_04/122maxProfitII.js b/Week_04/122maxProfitII.js new file mode 100644 index 00000000..31190881 --- /dev/null +++ b/Week_04/122maxProfitII.js @@ -0,0 +1,18 @@ +/** + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ + * + * 122. 买卖股票的最佳时机 II + * + * 买入卖出无限制,可以用贪心法 + */ + +const maxProfit = function(prices) { + let res = 0 + for(let i = 0; i < prices.length - 1; ++i) { + const profit = prices[i + 1] - prices[i] + if (profit > 0) { + res += profit + } + } + return res +} diff --git a/Week_04/455findContentChildren.js b/Week_04/455findContentChildren.js index 15217952..4eaa965a 100644 --- a/Week_04/455findContentChildren.js +++ b/Week_04/455findContentChildren.js @@ -1,10 +1,29 @@ /** * https://leetcode-cn.com/problems/assign-cookies/ * - * @param {number[]} g - * @param {number[]} s - * @return {number} + * greedy + * 1. 排序 + * 2. 循环,小胃口👬匹配小饼干🍪 */ -var findContentChildren = function(g, s) { -}; +const findContentChildren = function(g, s) { + const toStr = Object.prototype.toString, + ARR_TYPE = '[object Array]' + if (toStr.call(g) !== ARR_TYPE + || toStr.call(s) !== ARR_TYPE + || g.length < 1 + || s.length < 1 + ) return 0 + g.sort((x, y) => x - y) + s.sort((x, y) => x - y) + + let i = 0, j = 0, cnt = 0 + while (i < g.length && j < s.length) { + g[i++] <= s[j++] ? ++cnt : --i + } + return cnt +} + +// ---- test case ---- +console.log(findContentChildren([1, 2, 3], [1, 1])) +console.log(findContentChildren([1, 2], [1, 2, 3])) diff --git a/Week_04/README.md b/Week_04/README.md index d8fa74cf..c43531dc 100644 --- a/Week_04/README.md +++ b/Week_04/README.md @@ -61,4 +61,6 @@ const bfs = (root) => { ## 第10课:贪心算法 +适用场景:问题能分解成子问题,子问题的最优解能递推到最终问题的最优解。【最优子结构】 + ## 第11课:二分查找 diff --git a/Week_04/homework.md b/Week_04/homework.md index 6270fb52..56fa09f9 100644 --- a/Week_04/homework.md +++ b/Week_04/homework.md @@ -28,7 +28,7 @@ ## 7. 买卖股票的最佳时机 II (亚马逊、字节跳动、微软在半年内面试中考过) + greedy -+ [实现代码](./122maxProfit.js) ++ [实现代码](./122maxProfitII.js) ## 8. 分发饼干(亚马逊在半年内面试中考过) From de6f05794490cbab9e0689fc2fa3e24a2240da2d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 23 Feb 2021 22:42:40 +0800 Subject: [PATCH 067/210] clear 045 & add 055 --- Week_04/045jump.js | 18 +++++------------- Week_04/055canJump.js | 20 ++++++++++++++++---- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Week_04/045jump.js b/Week_04/045jump.js index ecca5b3d..59c99e9c 100644 --- a/Week_04/045jump.js +++ b/Week_04/045jump.js @@ -1,22 +1,14 @@ /** * https://leetcode-cn.com/problems/jump-game-ii/ * - * 55. 跳跃游戏 + * 45. 跳跃游戏 II * - * 思路: 从后往前贪心,依次判断第i个元素是否能到标记节点,能则记录更新 endReachable */ -const canJump = function(nums) { - if (Object.prototype.toString.call(nums) !== '[object Array]') return false - let endReachable = nums.length - 1 - for(let i = nums.length - 2; i >= 0; --i) { - if (nums[i] + i >= endReachable) { - endReachable = i - } - } - return endReachable === 0 +const jump = function(nums) { + } // ---- test case ---- -console.log(canJump([])) -console.log(canJump([0])) +console.log(jump([])) +console.log(jump([2,3,1,1,4])) diff --git a/Week_04/055canJump.js b/Week_04/055canJump.js index 2d857d06..ecca5b3d 100644 --- a/Week_04/055canJump.js +++ b/Week_04/055canJump.js @@ -1,10 +1,22 @@ /** - * https://leetcode-cn.com/problems/jump-game/ + * https://leetcode-cn.com/problems/jump-game-ii/ * - * @param {number[]} nums - * @return {boolean} + * 55. 跳跃游戏 + * + * 思路: 从后往前贪心,依次判断第i个元素是否能到标记节点,能则记录更新 endReachable */ const canJump = function(nums) { - + if (Object.prototype.toString.call(nums) !== '[object Array]') return false + let endReachable = nums.length - 1 + for(let i = nums.length - 2; i >= 0; --i) { + if (nums[i] + i >= endReachable) { + endReachable = i + } + } + return endReachable === 0 } + +// ---- test case ---- +console.log(canJump([])) +console.log(canJump([0])) From c68a084f4207a2451f65bedf2d9565f6116fd066 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 24 Feb 2021 22:58:57 +0800 Subject: [PATCH 068/210] solve 2 linklist --- Week_01/092reverseBetween.js | 48 ++++++++++++++++++++++++++++++++++++ Week_01/541reverseStr.js | 26 +++++++++++++++++++ Week_04/homework.md | 39 ++++++++++++++++++----------- 3 files changed, 99 insertions(+), 14 deletions(-) create mode 100644 Week_01/092reverseBetween.js create mode 100644 Week_01/541reverseStr.js diff --git a/Week_01/092reverseBetween.js b/Week_01/092reverseBetween.js new file mode 100644 index 00000000..2cfb13dd --- /dev/null +++ b/Week_01/092reverseBetween.js @@ -0,0 +1,48 @@ +/** +反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。 + +说明: +1 ≤ m ≤ n ≤ 链表长度。 + +示例: + +输入: 1->2->3->4->5->NULL, m = 2, n = 4 +输出: 1->4->3->2->5->NULL + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/reverse-linked-list-ii +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + +思路: 4点: dummy,pre,start,then( 每次只挪动then ) + */ + +const reverseBetween = function(head, m, n) { + if (head == null || m === n) return head + const dummy = new ListNode(-1, head) + let prev = dummy + for (let i = 0; i < m - 1; ++i) prev = prev.next + let start = prev.next, then = start.next + /* 1 -> 2 -> 3 ->4->5->NULL, m = 2, n = 4 + prev -> start -> then + + _________________ + | ! + 1 2 <- 3 4 -> 5 + |_________________^ + prev start then + + + __________________________ + | ! + 1 2 <- 3 <- 4 5 + |__________________________^ + prev start then + */ + for(let i = 0; i < n - m; ++i) { + start.next = then.next + then.next = prev.next + prev.next = then + then = start.next // then 右移 + } + return dummy.next +} diff --git a/Week_01/541reverseStr.js b/Week_01/541reverseStr.js new file mode 100644 index 00000000..0213f74b --- /dev/null +++ b/Week_01/541reverseStr.js @@ -0,0 +1,26 @@ +/** + * https://leetcode-cn.com/problems/reverse-string-ii/ + */ + +const reverseStr = function(s, k) { + const swap = function (arr, i, j) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp + } + const arr = s.split('') + for(let i = 0; i < arr.length; i += 2 * k) { + let start = i, end = Math.min(i + k - 1, arr.length - 1) + // console.log("🚀", start, end) + while(start < end) { + swap(arr, start++, end--) + } + } + return arr.join('') +} + +// test case +console.log(reverseStr('abcdefg', 2)) +console.log(reverseStr("abcdefg", 8)) + + diff --git a/Week_04/homework.md b/Week_04/homework.md index 56fa09f9..87672a26 100644 --- a/Week_04/homework.md +++ b/Week_04/homework.md @@ -1,66 +1,77 @@ # 作业 - -## 1. 单词接龙(亚马逊在半年内面试常考) +## 第9课:深度优先搜索和广度优先搜索 +### 1. 单词接龙(亚马逊在半年内面试常考) + dfs & bfs + [实现代码](./127ladderLength.js) -## 2. 单词接龙 II (微软、亚马逊、Facebook 在半年内面试中考过) +### 2. 单词接龙 II (微软、亚马逊、Facebook 在半年内面试中考过) + dfs & bfs + [实现代码](./126findLadders.js) -## 3. 岛屿数量(近半年内,亚马逊在面试中考查此题达到 350 次) +### 3. 岛屿数量(近半年内,亚马逊在面试中考查此题达到 350 次) + dfs & bfs + [实现代码](./200numIslands.js) -## 4. 扫雷游戏(亚马逊、Facebook 在半年内面试中考过) +### 4. 扫雷游戏(亚马逊、Facebook 在半年内面试中考过) + dfs & bfs + [实现代码](./529updateBoard.js) -## 6. 柠檬水找零(亚马逊在半年内面试中考过) + + + +## 第10课:贪心算法 + +### 6. 柠檬水找零(亚马逊在半年内面试中考过) + greedy + [实现代码](./860lemonadeChange.js) -## 7. 买卖股票的最佳时机 II (亚马逊、字节跳动、微软在半年内面试中考过) +### 7. 买卖股票的最佳时机 II (亚马逊、字节跳动、微软在半年内面试中考过) + greedy + [实现代码](./122maxProfitII.js) -## 8. 分发饼干(亚马逊在半年内面试中考过) +### 8. 分发饼干(亚马逊在半年内面试中考过) + greedy + [实现代码](./455findContentChildren.js) -## 9. 模拟行走机器人 +### 9. 模拟行走机器人 + greedy + [实现代码](./874robotSim.js) -## 10. 跳跃游戏 (亚马逊、华为、Facebook 在半年内面试中考过) +### 10. 跳跃游戏 (亚马逊、华为、Facebook 在半年内面试中考过) + greedy + [实现代码](./055canJump.js) -## 11. 跳跃游戏 II (亚马逊、华为、字节跳动在半年内面试中考过) +### 11. 跳跃游戏 II (亚马逊、华为、字节跳动在半年内面试中考过) + greedy + [实现代码](./045jump.js) -## 12. 搜索旋转排序数组(Facebook、字节跳动、亚马逊在半年内面试常考) + + + + + +## 第11课:二分查找 +### 12. 搜索旋转排序数组(Facebook、字节跳动、亚马逊在半年内面试常考) + binarySearch + [实现代码](./033search.js) -## 13. 搜索二维矩阵(亚马逊、微软、Facebook 在半年内面试中考过) +### 13. 搜索二维矩阵(亚马逊、微软、Facebook 在半年内面试中考过) + binarySearch + [实现代码](./074searchMatrix.js) -## 14. 寻找旋转排序数组中的最小值(亚马逊、微软、字节跳动在半年内面试中考过) +### 14. 寻找旋转排序数组中的最小值(亚马逊、微软、字节跳动在半年内面试中考过) + binarySearch + [实现代码](./153findMin.js) From 846624f4414130bd81b812dc2455e27dd52fca9d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 24 Feb 2021 23:32:52 +0800 Subject: [PATCH 069/210] re solve 024swapPairs --- Week_01/024swapPairs.js | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/Week_01/024swapPairs.js b/Week_01/024swapPairs.js index c027d0f8..e9dd1750 100644 --- a/Week_01/024swapPairs.js +++ b/Week_01/024swapPairs.js @@ -5,25 +5,28 @@ */ // 思路1: 递归 -var swapPairs = function(head) { - if (!head || !head.next) { - return head - } - var newHead = head.next, hnn = head.next.next - newHead.next = head +const swapPairs = function(head) { + // terminator + if (!head || !head.next) return head + // process & drill down + let hn = head.next, hnn = hn.next head.next = swapPairs(hnn) - return newHead -}; + hn.next = head + // reverse status + return hn +} // 思路2: 非递归(空指针头) -var swapPairs = function(head) { - var dummy = { val: -1, next: head }, cur = dummy - while(cur.next && cur.next.next) { - var p1 = cur.next - var p2 = cur.next.next - p1.next = p2.next - cur.next = p2 - p2.next = p1 +const swapPairs = function(head) { + const dummy = new ListNode(-1, head) + let prev = dummy + while (prev.next && prev.next.next) { + const curr = prev.next, + then = curr.next + curr.next = then.next + then.next = curr + prev.next = then + prev = curr } return dummy.next -}; +} From 96c4473e00ef7a802527e0803d3f4c65e368943f Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 24 Feb 2021 23:46:33 +0800 Subject: [PATCH 070/210] cycle linklist --- Week_01/141hasCycle.js | 15 +++++++++++++++ Week_01/142detectCycle.js | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 Week_01/141hasCycle.js create mode 100644 Week_01/142detectCycle.js diff --git a/Week_01/141hasCycle.js b/Week_01/141hasCycle.js new file mode 100644 index 00000000..1f03569a --- /dev/null +++ b/Week_01/141hasCycle.js @@ -0,0 +1,15 @@ +/** + * https://leetcode-cn.com/problems/linked-list-cycle/ + */ + +const hasCycle = function(head) { + let fast = slow = head + while(fast && fast.next && slow) { + fast = fast.next.next + slow = slow.next + if (fast === slow) { + return true + } + } + return false +} diff --git a/Week_01/142detectCycle.js b/Week_01/142detectCycle.js new file mode 100644 index 00000000..66565dca --- /dev/null +++ b/Week_01/142detectCycle.js @@ -0,0 +1,24 @@ +/** + * https://leetcode-cn.com/problems/linked-list-cycle-ii/ + */ + +const detectCycle = function(head) { + let fast = slow = head, hasCycle = false + while (fast && fast.next && slow) { + fast = fast.next.next + slow = slow.next + if (fast === slow) { + hasCycle = true + break + } + } + if (hasCycle) { + fast = head + while (fast && slow && fast !== slow) { + fast = fast.next + slow = slow.next + } + return fast + } + return null +} From c6bec40cd7276feec1040d535dfb3e9048b26c6c Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 25 Feb 2021 00:19:26 +0800 Subject: [PATCH 071/210] solve 860 lemonadechange --- Week_04/860lemonadeChange.js | 29 ++++++++++++++++++++++++++--- Week_04/README.md | 19 +++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/Week_04/860lemonadeChange.js b/Week_04/860lemonadeChange.js index 589169e1..a21ec0d9 100644 --- a/Week_04/860lemonadeChange.js +++ b/Week_04/860lemonadeChange.js @@ -1,9 +1,32 @@ /** * https://leetcode-cn.com/problems/lemonade-change/ * - * @param {number[]} bills - * @return {boolean} + * 860. 柠檬水找零 + * greedy algorithm */ -const lemonadeChange = function(bills) { +const lemonadeChange = function(bills) { + if (Object.prototype.toString.call(bills) !== '[object Array]' || bills.length < 1) return true + let five = 0, ten = 0 + for (const bill of bills) { + if (bill === 5) { + ++five + } else if (bill === 10) { + if (five === 0) { + return false + } + --five + ++ten + } else { + if (five > 0 && ten > 0) { + --five + --ten + } else if (five >= 3) { + five -= 3 + } else { + return false + } + } + } + return true } diff --git a/Week_04/README.md b/Week_04/README.md index c43531dc..f4cb3183 100644 --- a/Week_04/README.md +++ b/Week_04/README.md @@ -64,3 +64,22 @@ const bfs = (root) => { 适用场景:问题能分解成子问题,子问题的最优解能递推到最终问题的最优解。【最优子结构】 ## 第11课:二分查找 + ++ 适用于有序数组 + +```js +const binarySearch = function (arr, target) { + let l = 0, r = arr.length - 1 + while (l <= r) { + const mid = (r - l) >> 1 + l + if (arr[mid] === target) { + return mid + } else if (arr[mid] < target) { + l = mid + 1 + } else { + r = mid - 1 + } + } + return -1 +} +``` From 3bc4c58142fcd4ba7c124b248d5ae5582aeb6c31 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 26 Feb 2021 20:01:04 +0800 Subject: [PATCH 072/210] binarySearch --- Week_04/033search.js | 32 ++++++++++++++++++++--- Week_04/069sqrtx.js | 49 +++++++++++++++++++++++++++++++++++ Week_04/367isPerfectSquare.js | 46 ++++++++++++++++++++++++++++++++ Week_04/README.md | 5 +++- 4 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 Week_04/069sqrtx.js create mode 100644 Week_04/367isPerfectSquare.js diff --git a/Week_04/033search.js b/Week_04/033search.js index 7d882e13..3ab06741 100644 --- a/Week_04/033search.js +++ b/Week_04/033search.js @@ -1,10 +1,34 @@ /** * https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ * - * @param {number[]} nums - * @param {number} target - * @return {number} + * 33. 搜索旋转排序数组 + * + * binarySearch */ const search = function(nums, target) { - + let l = 0, r = nums.length - 1 + while (l <= r) { + const mid = l + ((r - l) >> 1) + if (nums[mid] === target) return mid + if (nums[l] <= nums[mid]) { // 逆序在右边 + if (nums[l] <= target && target < nums[mid]) { + r = mid - 1 + } else { + l = mid + 1 + } + } else { // 逆序在左边 + if (nums[mid] < target && target <= nums[r]) { + l = mid + 1 + } else { + r = mid - 1 + } + } + } + return -1 } + + +// ---- test case ---- +console.log(search([4, 5, 6, 7, 0, 1, 2], 0)) +console.log(search([4, 5, 6, 7, 0, 1, 2], 3)) +console.log(search([1], 0)) diff --git a/Week_04/069sqrtx.js b/Week_04/069sqrtx.js new file mode 100644 index 00000000..bd59854f --- /dev/null +++ b/Week_04/069sqrtx.js @@ -0,0 +1,49 @@ +/** + * https://leetcode-cn.com/problems/sqrtx/ + * + * 069 x的平方根 + * + */ + +// 方法1. 二分查找 +// y = x ^ 2, (x > 0): 是单调递增的抛物线 +const mySqrt = function(x) { + if (x === 0 || x === 1) return x + let l = 1, r = x + while (l <= r) { + const mid = l + ((r - l) >> 1) + if (mid * mid > x) { + r = mid - 1 + } else { + l = mid + 1 + } + } + return r +} + +// 方法2: 牛顿迭代法 +// r = (r + x / r) / 2 +const mySqrt2 = function(x) { + let r = x + while (r * r > x) { + r = Math.floor(x / r + (r - x / r) / 2) + } + return r +} + + +// ---- test case ---- +console.log(mySqrt(0)) +console.log(mySqrt(1)) +console.log(mySqrt(4)) +console.log(mySqrt(8)) +console.log(mySqrt(9)) +console.log(mySqrt(2147483647)) +console.log(mySqrt(2147395600)) + + +console.log(mySqrt2(4)) +console.log(mySqrt2(8)) +console.log(mySqrt2(9)) +console.log(mySqrt2(2147483647)) +console.log(mySqrt2(2147395600)) diff --git a/Week_04/367isPerfectSquare.js b/Week_04/367isPerfectSquare.js new file mode 100644 index 00000000..220af91f --- /dev/null +++ b/Week_04/367isPerfectSquare.js @@ -0,0 +1,46 @@ + +/** + * https://leetcode-cn.com/problems/valid-perfect-square/ + * + * 367. 有效的完全平方数 + */ + +// 解法一:binarySearch +const isPerfectSquare = function(n) { + if (n === 0 || n === 1) return true + let l = 1, r = n + while (l <= r) { + const mid = r + ((l - r) >> 1) + if (mid * mid > n) { + r = mid - 1 + } else { + l = mid + 1 + } + } + return r * r === n +} + +// 解法二: 找规律,递推 +/** + * 1 + * 4 = 1 + 3 + * 9 = 1 + 3 + 5 + * 16 = 1 + 3 + 5 + 7 + * 25 = 1 + 3 + 5 + 7 + 9 + * ... + */ +const isPerfectSquare2 = function(n) { + let x = 1 + while (n > 0) { + n -= x + x += 2 + } + return n == 0 +} + +// ---- test case ---- +console.log(isPerfectSquare(14)) +console.log(isPerfectSquare(16)) +console.log(isPerfectSquare2(14)) +console.log(isPerfectSquare2(16)) + diff --git a/Week_04/README.md b/Week_04/README.md index f4cb3183..7a6e7b3e 100644 --- a/Week_04/README.md +++ b/Week_04/README.md @@ -65,7 +65,10 @@ const bfs = (root) => { ## 第11课:二分查找 -+ 适用于有序数组 +**前提** +1. 单调性 +2. 存在上下界 +3. 能通过索引访问 ```js const binarySearch = function (arr, target) { From d958634a2644161451f6608d7a08840e00526bb4 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 26 Feb 2021 20:17:16 +0800 Subject: [PATCH 073/210] solve 074 with binarySearch --- Week_04/074searchMatrix.js | 41 ++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/Week_04/074searchMatrix.js b/Week_04/074searchMatrix.js index 98472552..9f21bfe0 100644 --- a/Week_04/074searchMatrix.js +++ b/Week_04/074searchMatrix.js @@ -1,10 +1,43 @@ /** * https://leetcode-cn.com/problems/search-a-2d-matrix/ * - * @param {number[][]} matrix - * @param {number} target - * @return {boolean} + * 74. 搜索二维矩阵 + * + * 0 1 2 3 4 5 6 7 8 9 10 11 + * 00 01 02 03, 10 11 12 13, 20 21 22 23 + * m = 3, n = 4 + * + * x -> i, j + * + * i = Math.floor(x / n), j = x % n */ -const searchMatrix = function(matrix, target) { +const searchMatrix = function(matrix, target) { + const _getVal = (x) => { + const i = Math.floor(x/n) + const j = x % n + return matrix[i][j] + } + const m = matrix.length, n = matrix[0].length + let l = 0, r = m * n - 1 + while (l <= r) { + const mid = l + ((r - l) >> 1), + val = _getVal(mid) + if (val === target) return true + if (val > target) { + r = mid - 1 + } else { + l = mid + 1 + } + } + return false } + +// ---- test case ---- +const matrix = [ + [ 1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 60], +] +console.log(searchMatrix(matrix, 3)) +console.log(searchMatrix(matrix, 13)) From 5849939025c66233b09150c25400335dead6103d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 27 Feb 2021 01:03:52 +0800 Subject: [PATCH 074/210] bfs & binarySearch --- Week_03/047permuteUnique.js | 6 +++-- Week_04/153findMin.js | 22 ++++++++++++++++-- Week_04/200numIslands.js | 45 ++++++++++++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/Week_03/047permuteUnique.js b/Week_03/047permuteUnique.js index 14bc9711..72729d9c 100644 --- a/Week_03/047permuteUnique.js +++ b/Week_03/047permuteUnique.js @@ -1,7 +1,9 @@ /** - * @param {number[]} nums - * @return {number[][]} + * https://leetcode-cn.com/problems/permutations-ii/ + * + * 47. 全排列 II */ + const permuteUnique = function(nums) { const res = [] diff --git a/Week_04/153findMin.js b/Week_04/153findMin.js index f1b26ea6..0d5ac85b 100644 --- a/Week_04/153findMin.js +++ b/Week_04/153findMin.js @@ -1,10 +1,28 @@ /** * https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ * - * @param {number[]} nums - * @return {number} + * 153. 寻找旋转排序数组中的最小值 + * binarySearch */ const findMin = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return null + let l = 0, r = nums.length - 1 + while (l < r) { + if (nums[l] < nums[r]) return nums[l] + const mid = l + ((r - l) >> 1) + if (nums[mid] >= nums[l]) { + l = mid + 1 + } else { + r = mid + } + } + + return nums[l] } + +// ---- test case ---- +console.log(findMin([3, 4, 5, 1, 2])) +console.log(findMin([4, 5, 6, 7, 0, 1, 2])) +console.log(findMin([1])) diff --git a/Week_04/200numIslands.js b/Week_04/200numIslands.js index 59f1a217..72e381c0 100644 --- a/Week_04/200numIslands.js +++ b/Week_04/200numIslands.js @@ -1,10 +1,49 @@ /** * https://leetcode-cn.com/problems/number-of-islands/ + * 200. 岛屿数量 * medium - * - * @param {character[][]} grid - * @return {number} */ + const numIslands = function(grid) { + // 传染给其他的元素,标记为零 + const dfsMarking = function(i, j) { + if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] !== '1') return + grid[i][j] = '0' + dfsMarking(i + 1, j) + dfsMarking(i - 1, j) + dfsMarking(i, j + 1) + dfsMarking(i, j - 1) + } + + let cnt = 0, + m = grid.length, + n = grid[0].length + for (let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + if (grid[i][j] === '1') { + dfsMarking(i, j) + ++cnt + } + } + } + return cnt } + + +// ---- test case ---- +const grid1 = [ + ['1', '1', '1', '1', '0'], + ['1', '1', '0', '1', '0'], + ['1', '1', '0', '0', '0'], + ['0', '0', '0', '0', '0'], +] +const grid2 = [ + ['1', '1', '0', '0', '0'], + ['1', '1', '0', '0', '0'], + ['0', '0', '1', '0', '0'], + ['0', '0', '0', '1', '1'], +] +console.log(numIslands(grid1)) +console.log(numIslands(grid2)) +console.log(numIslands([[]])) From 0c49d16416c6059fe4a88818b08abe0ce0871014 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 27 Feb 2021 20:40:17 +0800 Subject: [PATCH 075/210] solove isPerfectSquare with binary Search --- Week_04/367isPerfectSquare.js | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Week_04/367isPerfectSquare.js b/Week_04/367isPerfectSquare.js index 220af91f..af648b6f 100644 --- a/Week_04/367isPerfectSquare.js +++ b/Week_04/367isPerfectSquare.js @@ -1,26 +1,27 @@ /** - * https://leetcode-cn.com/problems/valid-perfect-square/ + * https://leetcode-cn.csom/problems/valid-perfect-square/ * * 367. 有效的完全平方数 */ -// 解法一:binarySearch +// 解法一:binarySearch O(logn) 效果优于解法二 const isPerfectSquare = function(n) { - if (n === 0 || n === 1) return true - let l = 1, r = n + let l = 0, r = n while (l <= r) { - const mid = r + ((l - r) >> 1) - if (mid * mid > n) { + const mid = l + ((r - l) >> 1), val = mid * mid + if (val === n) { + return true + } else if (val > n) { r = mid - 1 } else { l = mid + 1 } } - return r * r === n -} + return false +} -// 解法二: 找规律,递推 +// 解法二: 找规律,循环减去一个奇数 O(sqrt(n)) /** * 1 * 4 = 1 + 3 @@ -35,12 +36,15 @@ const isPerfectSquare2 = function(n) { n -= x x += 2 } - return n == 0 + return n === 0 } // ---- test case ---- +console.log(isPerfectSquare(0)) +console.log(isPerfectSquare(1)) console.log(isPerfectSquare(14)) console.log(isPerfectSquare(16)) +console.log(isPerfectSquare2(0)) +console.log(isPerfectSquare2(1)) console.log(isPerfectSquare2(14)) console.log(isPerfectSquare2(16)) - From c6e0a007579fddc00d2179d6b1c5fa64a4e37a67 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 27 Feb 2021 22:54:09 +0800 Subject: [PATCH 076/210] =?UTF-8?q?BFS=20=E6=90=9C=E7=B4=A2=E6=B1=82?= =?UTF-8?q?=E8=A7=A3=20=E6=9C=80=E5=B0=8F=E5=9F=BA=E5=9B=A0=E5=8F=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_04/127ladderLength.js | 7 ++----- Week_04/433minMutation.js | 34 +++++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Week_04/127ladderLength.js b/Week_04/127ladderLength.js index 6be5288d..e2a16338 100644 --- a/Week_04/127ladderLength.js +++ b/Week_04/127ladderLength.js @@ -1,12 +1,9 @@ /** * https://leetcode-cn.com/problems/word-ladder/description/ * hard - * - * @param {string} beginWord - * @param {string} endWord - * @param {string[]} wordList - * @return {number} + * 127. 单词接龙 */ + const ladderLength = function(beginWord, endWord, wordList) { } diff --git a/Week_04/433minMutation.js b/Week_04/433minMutation.js index d782bc1b..77c5aef4 100644 --- a/Week_04/433minMutation.js +++ b/Week_04/433minMutation.js @@ -1,11 +1,35 @@ /** * https://leetcode-cn.com/problems/minimum-genetic-mutation/ * - * @param {string} start - * @param {string} end - * @param {string[]} bank - * @return {number} + * 433. 最小基因变化 + * medium + * */ -const minMutation = function(start, end, bank) { +// 思路:BFS暴力搜索 +// lastStep记录上一步的基因🧬和步数,bankSet用于可遍历的基因库 +// 复杂度 O(单条基因长度 * 基因元素数 * 基因库包含基因数) +const minMutation = function(start, end, bank) { + const lastStep = [[start, 0]], bankSet = new Set(bank) + while(lastStep.length) { + const [curr, step] = lastStep.pop() + if (curr === end) return step + for(let i = 0; i < curr.length; ++i) { + for(const ch of ['A', 'C', 'G', 'T']) { + // 突变后的基因(暴力穷举) + const mutation = curr.slice(0, i) + ch + curr.slice(i+1) + // console.log(mutation, lastStep, bankSet) + if (bankSet.has(mutation)) { + bankSet.delete(mutation) + lastStep.unshift([mutation, step + 1]) + } + } + } + } + return -1 } + +// ---- test case ---- +// console.log(minMutation('AACCGGTT', 'AACCGGTA', ['AACCGGTA'])) +// console.log(minMutation('AACCGGTT', 'AAACGGTA', ['AACCGGTA', 'AACCGCTA', 'AAACGGTA'])) +console.log(minMutation('AAAAACCC', 'AACCCCCC', ['AAAACCCC', 'AAACCCCC', 'AACCCCCC'])) From 5b2681ac4c4aef69bb110acce4b7809bceeaee05 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 27 Feb 2021 23:31:37 +0800 Subject: [PATCH 077/210] solve 022 with recur & iter --- Week_03/022generateParenthesis.js | 36 ++++++++++--------------------- Week_04/022generateParenthesis.js | 34 +++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/Week_03/022generateParenthesis.js b/Week_03/022generateParenthesis.js index a4f638b3..a06019b6 100644 --- a/Week_03/022generateParenthesis.js +++ b/Week_03/022generateParenthesis.js @@ -1,39 +1,25 @@ /** * medium * https://leetcode-cn.com/problems/generate-parentheses/ - * @param {number} n - * @return {string[]} + * * 思路:递归、辅助函数、剪枝 */ + +// 解法一:递归 const generateParenthesis = function(n) { - /** - * 辅助函数 - * @param {Number} left 当前左括号的个数 - * @param {Number} right 当前右括号的个数 - * @param {Number} n 括号配额 - * @param {String} s 当前子问题的生成结果 - */ - const _generate = function(left, right, n, s) { - // terminator - if (left === n && right === n) { - res.push(s) - return null - } - // process - // drill down - if (left < n) { - _generate(left + 1, right, n, s + '(') - } - if (right < left) { - _generate(left, right + 1, n, s + ')') + const _generate = (cntL, cntR, curStr) => { + if (cntL === n && cntR === n) { + res.push(curStr) + return } - // reverse states + if (cntL < n) _generate(cntL + 1, cntR, curStr + '(') + if (cntR < cntL) _generate(cntL, cntR + 1, curStr + ')') } const res = [] - _generate(0, 0, n, '') + _generate(0, 0, '') return res -}; +} // ---- test case ---- console.log(generateParenthesis(3)) diff --git a/Week_04/022generateParenthesis.js b/Week_04/022generateParenthesis.js index a6e03080..ac9c26aa 100644 --- a/Week_04/022generateParenthesis.js +++ b/Week_04/022generateParenthesis.js @@ -1,7 +1,37 @@ /** * https://leetcode-cn.com/problems/generate-parentheses/ - * + * 22. 括号生成 + * medium */ -const generateParenthesis = function(n) { +// 解法一:递归 + 剪枝 +const generateParenthesis1 = function(n) { + const _generate = (cntL, cntR, curStr) => { + if (cntL === n && cntR === n) { + res.push(curStr) + return + } + if (cntL < n) _generate(cntL + 1, cntR, curStr + '(') + if (cntR < cntL) _generate(cntL, cntR + 1, curStr + ')') + } + + const res = [] + _generate(0, 0, '') + return res +} + +// 解法二:非递归(自己维护栈) + 剪枝 +const generateParenthesis2 = function(n) { + const res = [], stack = [['(', 1, 0]] + while (stack.length) { + const [curStr, cntL, cntR] = stack.pop() + if (cntL === n && cntR === n) res.push(curStr) + if (cntR < cntL) stack.push([curStr + ')', cntL, cntR + 1]) + if (cntL < n) stack.push([curStr + '(', cntL + 1, cntR]) + } + return res } + + +console.log(generateParenthesis1(3)) +console.log(generateParenthesis2(3)) From c14e480e73ea60922b7ef18721ae1c0b7334ea57 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 27 Feb 2021 23:41:47 +0800 Subject: [PATCH 078/210] solve 515 with binaryTree levelOrderTraversal --- Week_04/515largestValues.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Week_04/515largestValues.js b/Week_04/515largestValues.js index 26c2d0e6..7a4d6dec 100644 --- a/Week_04/515largestValues.js +++ b/Week_04/515largestValues.js @@ -1,8 +1,35 @@ /** * https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/ * + * 515. 在每个树行中找最大值 + * medium + * */ +/* + 1 + / \ + 3 2 + / \ \ +5 3 9 + +[1, 3, 9] +*/ + +// 二叉树的层序遍历 const largestValues = function(root) { - + if (root == null) return [] + const res = [], queue = [root] + while (queue.length) { + const n = queue.length + let max = -Infinity + for(let i = 0; i < n; ++i) { + const p = queue.pop() + max = Math.max(max, p.val) + if (p.left != null) queue.unshift(p.left) + if (p.right != null) queue.unshift(p.right) + } + res.push(max) + } + return res } From 80f3e33dc02c2b44d14864deb8b8c526cb836380 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 28 Feb 2021 00:54:36 +0800 Subject: [PATCH 079/210] solve robotSim --- Week_04/874robotSim.js | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/Week_04/874robotSim.js b/Week_04/874robotSim.js index f41683d7..c5e31d8e 100644 --- a/Week_04/874robotSim.js +++ b/Week_04/874robotSim.js @@ -1,11 +1,42 @@ /** * https://leetcode-cn.com/problems/walking-robot-simulation/ * - * @param {number[]} commands - * @param {number[][]} obstacles - * @return {number} + * 874. 模拟行走机器人 + * easy + * 注意审题,求到过的最远距离 😓 */ +// 思路:用 set 存储障碍坐标,每次走一步,遇到障碍则停下来 +// direct: 0 top | 1 right | 2 down | 3 left const robotSim = function(commands, obstacles) { - + let x = 0, y = 0, direct = 0, maxDist = 0 + const obsSet = new Set(obstacles.map(item => item.join())), + dx = [0, 1, 0, -1], + dy = [1, 0, -1, 0] + for(const command of commands) { + if (command === -1) { + direct = (direct + 1) % 4 + } else if (command === -2) { + direct = (direct + 3) % 4 + } else { + // 模拟每一步行走 + for (let i = 0; i < command; ++i) { + const px = x + dx[direct] + const py = y + dy[direct] + if (obsSet.has(`${px},${py}`)) { // 遇到障碍物 + break + } else { + x = px + y = py + maxDist = Math.max(maxDist, x * x + y * y) + } + } + console.log(x, y, direct) + } + } + return maxDist } + +console.log(robotSim([4, -1, 3], [])) +console.log(robotSim([4, -1, 4, -2, 4], [[2,4]])) +// console.log(robotSim([1,2,-2,5,-1,-2,-1,8,3,-1,9,4,-2,3,2,4,3,9,2,-1,-1,-2,1,3,-2,4,1,4,-1,1,9,-1,-2,5,-1,5,5,-2,6,6,7,7,2,8,9,-1,7,4,6,9,9,9,-1,5,1,3,3,-1,5,9,7,4,8,-1,-2,1,3,2,9,3,-1,-2,8,8,7,5,-2,6,8,4,6,2,7,2,-1,7,-2,3,3,2,-2,6,9,8,1,-2,-1,1,4,7], [[-57,-58],[-72,91],[-55,35],[-20,29],[51,70],[-61,88],[-62,99],[52,17],[-75,-32],[91,-22],[54,33],[-45,-59],[47,-48],[53,-98],[-91,83],[81,12],[-34,-90],[-79,-82],[-15,-86],[-24,66],[-35,35],[3,31],[87,93],[2,-19],[87,-93],[24,-10],[84,-53],[86,87],[-88,-18],[-51,89],[96,66],[-77,-94],[-39,-1],[89,51],[-23,-72],[27,24],[53,-80],[52,-33],[32,4],[78,-55],[-25,18],[-23,47],[79,-5],[-23,-22],[14,-25],[-11,69],[63,36],[35,-99],[-24,82],[-29,-98],[-50,-70],[72,95],[80,80],[-68,-40],[65,70],[-92,78],[-45,-63],[1,34],[81,50],[14,91],[-77,-54],[13,-88],[24,37],[-12,59],[-48,-62],[57,-22],[-8,85],[48,71],[12,1],[-20,36],[-32,-14],[39,46],[-41,75],[13,-23],[98,10],[-88,64],[50,37],[-95,-32],[46,-91],[10,79],[-11,43],[-94,98],[79,42],[51,71],[4,-30],[2,74],[4,10],[61,98],[57,98],[46,43],[-16,72],[53,-69],[54,-96],[22,0],[-7,92],[-69,80],[68,-73],[-24,-92],[-21,82],[32,-1],[-6,16],[15,-29],[70,-66],[-85,80],[50,-3],[6,13],[-30,-98],[-30,59],[-67,40],[17,72],[79,82],[89,-100],[2,79],[-95,-46],[17,68],[-46,81],[-5,-57],[7,58],[-42,68],[19,-95],[-17,-76],[81,-86],[79,78],[-82,-67],[6,0],[35,-16],[98,83],[-81,100],[-11,46],[-21,-38],[-30,-41],[86,18],[-68,6],[80,75],[-96,-44],[-19,66],[21,84],[-56,-64],[39,-15],[0,45],[-81,-54],[-66,-93],[-4,2],[-42,-67],[-15,-33],[1,-32],[-74,-24],[7,18],[-62,84],[19,61],[39,79],[60,-98],[-76,45],[58,-98],[33,26],[-74,-95],[22,30],[-68,-62],[-59,4],[-62,35],[-78,80],[-82,54],[-42,81],[56,-15],[32,-19],[34,93],[57,-100],[-1,-87],[68,-26],[18,86],[-55,-19],[-68,-99],[-9,47],[24,94],[92,97],[5,67],[97,-71],[63,-57],[-52,-14],[-86,-78],[-17,92],[-61,-83],[-84,-10],[20,13],[-68,-47],[7,28],[66,89],[-41,-17],[-14,-46],[-72,-91],[4,52],[-17,-59],[-85,-46],[-94,-23],[-48,-3],[-64,-37],[2,26],[76,88],[-8,-46],[-19,-68]])) From e684a95a418191e4f729eed81e3a765c567ded5a Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 28 Feb 2021 16:40:33 +0800 Subject: [PATCH 080/210] Majority Voting Algorithm --- Week_03/169majorityElement.js | 30 ++++++++++---- Week_03/229majorityElement.js | 78 +++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 Week_03/229majorityElement.js diff --git a/Week_03/169majorityElement.js b/Week_03/169majorityElement.js index b5fe3f20..829a11b5 100644 --- a/Week_03/169majorityElement.js +++ b/Week_03/169majorityElement.js @@ -1,14 +1,24 @@ /** * https://leetcode-cn.com/problems/majority-element/ - * 思路: 计数法 + * 169. 多数元素 (easy) + * 摩尔投票法 O(n) 【Majority Voting Algorithm】 * - * @param {number[]} nums - * @return {number} + * 难度升级 -> [./229majorityElement.js] */ -var majorityElement = function(nums) { - if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return 0 - let res = nums[0], cnt = 1 - for(let i = 1; i < nums.length; ++i) { + +const majorityElement = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]') return null + + let res = null, cnt = 0 + for(let i = 0; i < nums.length; ++i) { + // 写法一 + // if (cnt > 0 && nums[i] !== res) { + // --cnt + // } else { + // res = nums[i] + // ++cnt + // } + // 写法二:更好理解一些 if (nums[i] === res) { ++cnt } else { @@ -20,4 +30,8 @@ var majorityElement = function(nums) { } } return res -}; +} + +// ---- test case ---- +console.log(majorityElement([3, 2, 3])) +console.log(majorityElement([3, 2, 2])) diff --git a/Week_03/229majorityElement.js b/Week_03/229majorityElement.js new file mode 100644 index 00000000..58fdb930 --- /dev/null +++ b/Week_03/229majorityElement.js @@ -0,0 +1,78 @@ +/** + * https://leetcode-cn.com/problems/majority-element-ii/ + * + * 229. 求众数 II + * medium + * + * + */ + +// 解法一:扩展摩尔投票法 O(n) 推荐! +const majorityElement = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 2) return nums + + const cnt = new Array(2).fill(0), + res = new Array(2).fill(null) + for(const num of nums) { + if (num === res[0]) { + ++cnt[0] + } else if (num === res[1]) { + ++cnt[1] + } else if (cnt[0] === 0) { + res[0] = num + ++cnt[0] + } else if (cnt[1] === 0) { + res[1] = num + ++cnt[1] + } else { + --cnt[0] + --cnt[1] + } + } + + const minCnt = Math.floor(nums.length / 3) + const realCnt = new Array(2).fill(0) + nums.forEach(num => { + if (num === res[0]) { + ++realCnt[0] + } else if (num === res[1]) { + ++realCnt[1] + } + }) + + return res.filter((_, idx) => realCnt[idx] > minCnt) +} + +// 解法二:哈希表统计 O(n) 但是空间复杂度不符合题目要求!! +const majorityElement2 = function(nums) { + if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 2) return nums + + const map = new Map(), + minCnt = Math.floor(nums.length / 3), + res = [] + for(const num of nums) { + if (map.has(num)) { + map.set(num, map.get(num) + 1) + } else { + map.set(num, 1) + } + } + for(let [key, val] of map) { + if (val > minCnt) { + res.push(key) + } + } + return res +} + + +// ---- test case ---- +// console.log(majorityElement([3])) +// console.log(majorityElement([1, 2, 3])) +// console.log(majorityElement([3, 2, 3])) +// console.log(majorityElement([1, 1, 1, 3, 3, 2, 2, 2])) + +// console.log(majorityElement2([3])) +// console.log(majorityElement2([1, 2, 3])) +console.log(majorityElement2([3, 2, 3])) +console.log(majorityElement2([1, 1, 1, 3, 3, 2, 2, 2])) From ce7a6eed0fde26e26720a474a627c38f3b092520 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 28 Feb 2021 17:36:00 +0800 Subject: [PATCH 081/210] bfs & dfs solve minesweeper --- Week_04/529updateBoard.js | 116 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 5 deletions(-) diff --git a/Week_04/529updateBoard.js b/Week_04/529updateBoard.js index b8d793e8..08bd3893 100644 --- a/Week_04/529updateBoard.js +++ b/Week_04/529updateBoard.js @@ -1,11 +1,117 @@ /** * https://leetcode-cn.com/problems/minesweeper/ + * 529. 扫雷游戏 * medium - * - * @param {character[][]} board - * @param {number[]} click - * @return {character[][]} */ -const updateBoard = function(board, click) { +/* +1. 玩家未知区域 + + M 地雷 + + E 未点击的空地 +2. 玩家已知区域 + + B 此次和周围都无地雷 + + X 此处为地雷 + + Digit 此处无地雷,且周围有地雷 + +分析 +1. 踩中地雷(M): M -> X, 停止 +2. 未踩中地雷(E): + 1. 周围有地雷: E -> Digit, 停止搜索 (等待玩家点击) + 2. 周围无地雷: E -> B,搜索周围8个点,遇到 E,递归搜索 +*/ + +// 解法一:DFS (递归) +const updateBoard1 = function(board, click) { + const m = board.length, n = board[0].length + const [x, y] = click + if (board[x][y] === 'M') { + board[x][y] = 'X' + } else { + // cnt 统计周围8个点的地雷数 + let cnt = 0 + for (let i = -1; i <= 1; ++i) { + for(let j = -1; j <= 1; ++j) { + if (i === 0 && j === 0) continue + const r = x + i, c = y + j + if (r < 0 || r >= m || c < 0 || c >= n) continue + if (board[r][c] === 'M' || board[r][c] === 'X') ++cnt + } + } + if (cnt > 0) { + board[x][y] = String(cnt) + } else { + board[x][y] = 'B' + for(let i = -1; i <= 1; ++i) { + for(let j = -1; j <= 1; ++j) { + if (i === 0 && j === 0) continue + const r = x + i, c = y + j + if (r < 0 || r >= m || c < 0 || c >= n) continue + if (board[r][c] === 'E') updateBoard1(board, [r, c]) + } + } + } + } + + return board } + +// 解法二:BFS (非递归,手动维护队列) +const updateBoard2 = function(board, click) { + const m = board.length, + n = board[0].length, + queue = [click] + + while (queue.length) { + const [x, y] = queue.pop() + if (board[x][y] === 'M') { + board[x][y] = 'X' + } else { + let cnt = 0 + for (let i = -1; i <= 1; ++i) { + for (let j = -1; j <= 1; ++j) { + if (i === 0 && j === 0) continue + const r = x + i, c = y + j + if (r < 0 || r >= m || c < 0 || c >= n) continue + if (board[r][c] === 'M' || board[r][c] === 'X') ++cnt + } + } + if (cnt > 0) { + board[x][y] = String(cnt) + } else { + board[x][y] = 'B' + for (let i = -1; i <= 1; ++i) { + for (let j = -1; j <= 1; ++j) { + if (i === 0 && j === 0) continue + const r = x + i, c = y + j + if (r < 0 || r >= m || c < 0 || c >= n) continue + if (board[r][c] === 'E') { + queue.unshift([r, c]) + board[r][c] = 'B' // 避免被重复加入queue + } + } + } + } + } + } + return board +} + +// ---- test cases ---- +const board1 = [ + ['E', 'E', 'E', 'E', 'E'], + ['E', 'E', 'M', 'E', 'E'], + ['E', 'E', 'E', 'E', 'E'], + ['E', 'E', 'E', 'E', 'E'], +] +const board2 = [ + ['B', '1', 'E', '1', 'B'], + ['B', '1', 'M', '1', 'B'], + ['B', '1', '1', '1', 'B'], + ['B', 'B', 'B', 'B', 'B'], +] + +// console.log(updateBoard1(board1, [3, 0])) +// console.log(updateBoard1(board2, [1, 2])) + +console.log(updateBoard2(board1, [3, 0])) +console.log(updateBoard2(board2, [1, 2])) From b1a0b524484c00fad37d744ec141169e586a5e9b Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 1 Mar 2021 00:00:29 +0800 Subject: [PATCH 082/210] word ladder --- Week_04/126findLadders.js | 34 +++++++++++++++++++++++++++++++++- Week_04/127ladderLength.js | 24 +++++++++++++++++++++++- Week_04/homework.md | 2 +- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/Week_04/126findLadders.js b/Week_04/126findLadders.js index d563f68b..1034d4a1 100644 --- a/Week_04/126findLadders.js +++ b/Week_04/126findLadders.js @@ -1,12 +1,44 @@ /** - * https://leetcode-cn.com/problems/word-ladder-ii/description/ + * https://leetcode-cn.com/problems/word-ladder-ii * hard + * 126. 单词接龙 II * * @param {string} beginWord * @param {string} endWord * @param {string[]} wordList * @return {string[][]} */ + +// BFS const findLadders = function(beginWord, endWord, wordList) { + const res = [], + queue = [[1, [beginWord]]], + wordsSet = new Set(wordList), + alphabets = 'abcdefghijklmnopqrstuvwxyz'.split('') + while (queue.length) { + // console.log("🚀", queue) + const [level, path] = queue.pop(), + word = path[path.length - 1] + + if (word === endWord) { + res.push(path.slice()) + } else { + for (let i = 0; i < word.length; ++i) { + for (const ch of alphabets) { + const nextWord = word.slice(0, i) + ch + word.slice(i + 1) + if (wordsSet.has(nextWord)) { + wordsSet.delete(nextWord) + queue.unshift([level + 1, path.concat([nextWord])]) + } + } + + } + } + } + return res } + +// ---- test case ---- +console.log(findLadders("hit", "cog", ["hot","dot","dog","lot","log","cog"])) +// console.log(findLadders("hit", "cog", ["hot","dot","dog","lot","log"])) diff --git a/Week_04/127ladderLength.js b/Week_04/127ladderLength.js index e2a16338..bb7e4f18 100644 --- a/Week_04/127ladderLength.js +++ b/Week_04/127ladderLength.js @@ -4,6 +4,28 @@ * 127. 单词接龙 */ +// BFS, 搜索所有可能的单词是否在词库中 +// 复杂度:O(单词个数 * 单词长度 * 26) const ladderLength = function(beginWord, endWord, wordList) { - + const wordsSet = new Set(wordList), + queue = [[beginWord, 1]], + alphbets = 'abcdefghijklmnopqrstuvwxyz'.split('') + while (queue.length) { + const [word, level] = queue.pop() + if (word === endWord) return level + for (let i = 0; i < word.length; ++i) { + for (const ch of alphbets) { + const nextWord = word.slice(0, i) + ch + word.slice(i + 1) + if (wordsSet.has(nextWord)) { + wordsSet.delete(nextWord) + queue.unshift([nextWord, level + 1]) + } + } + } + } + return 0 } + +// ---- test case ---- +console.log(ladderLength('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log', 'cog'])) +console.log(ladderLength('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log'])) diff --git a/Week_04/homework.md b/Week_04/homework.md index 87672a26..db1c9eac 100644 --- a/Week_04/homework.md +++ b/Week_04/homework.md @@ -50,7 +50,7 @@ + greedy + [实现代码](./055canJump.js) -### 11. 跳跃游戏 II (亚马逊、华为、字节跳动在半年内面试中考过) +### TODO 11. 跳跃游戏 II (亚马逊、华为、字节跳动在半年内面试中考过) + greedy + [实现代码](./045jump.js) From e3c81832a85ac97adc8c88a6d4bf3e47d6a4dfc8 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 1 Mar 2021 00:17:55 +0800 Subject: [PATCH 083/210] exceed time --- Week_04/126findLadders.js | 20 ++++++++++---------- Week_04/homework.md | 3 +-- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Week_04/126findLadders.js b/Week_04/126findLadders.js index 1034d4a1..863276ab 100644 --- a/Week_04/126findLadders.js +++ b/Week_04/126findLadders.js @@ -9,36 +9,36 @@ * @return {string[][]} */ -// BFS +// BFS (不会写回溯就先用copy, 会超时。。。) const findLadders = function(beginWord, endWord, wordList) { const res = [], - queue = [[1, [beginWord]]], - wordsSet = new Set(wordList), + queue = [[1, [beginWord], new Set(wordList)]], alphabets = 'abcdefghijklmnopqrstuvwxyz'.split('') + let minLevel = Infinity // 最短转换序列的长度 while (queue.length) { - // console.log("🚀", queue) - const [level, path] = queue.pop(), + const [level, path, wordsSet] = queue.pop(), word = path[path.length - 1] + // console.log("🚀", path) if (word === endWord) { res.push(path.slice()) + minLevel = Math.min(minLevel, level) } else { for (let i = 0; i < word.length; ++i) { for (const ch of alphabets) { const nextWord = word.slice(0, i) + ch + word.slice(i + 1) if (wordsSet.has(nextWord)) { wordsSet.delete(nextWord) - queue.unshift([level + 1, path.concat([nextWord])]) + queue.unshift([level + 1, path.concat([nextWord]), new Set(wordsSet)]) } } - } - } } - return res + return res.filter(path => path.length === minLevel) } // ---- test case ---- console.log(findLadders("hit", "cog", ["hot","dot","dog","lot","log","cog"])) -// console.log(findLadders("hit", "cog", ["hot","dot","dog","lot","log"])) +console.log(findLadders("hit", "cog", ["hot","dot","dog","lot","log"])) +console.log(findLadders("qa", "sq", ["si","go","se","cm","so","ph","mt","db","mb","sb","kr","ln","tm","le","av","sm","ar","ci","ca","br","ti","ba","to","ra","fa","yo","ow","sn","ya","cr","po","fe","ho","ma","re","or","rn","au","ur","rh","sr","tc","lt","lo","as","fr","nb","yb","if","pb","ge","th","pm","rb","sh","co","ga","li","ha","hz","no","bi","di","hi","qa","pi","os","uh","wm","an","me","mo","na","la","st","er","sc","ne","mn","mi","am","ex","pt","io","be","fm","ta","tb","ni","mr","pa","he","lr","sq","ye"])) diff --git a/Week_04/homework.md b/Week_04/homework.md index db1c9eac..b071f96d 100644 --- a/Week_04/homework.md +++ b/Week_04/homework.md @@ -5,11 +5,10 @@ + dfs & bfs + [实现代码](./127ladderLength.js) -### 2. 单词接龙 II (微软、亚马逊、Facebook 在半年内面试中考过) +### TODO 2. 单词接龙 II (微软、亚马逊、Facebook 在半年内面试中考过) + dfs & bfs + [实现代码](./126findLadders.js) - ### 3. 岛屿数量(近半年内,亚马逊在面试中考查此题达到 350 次) + dfs & bfs From 48781a23f08218af0a4810f56a7e1979a31548ff Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 1 Mar 2021 01:12:54 +0800 Subject: [PATCH 084/210] jump II --- Week_04/045jump.js | 24 +++++++++- Week_04/055canJump.js | 10 ++--- Week_04/126findLadders.js | 92 +++++++++++++++++++++++++++++++++++---- Week_04/homework.md | 4 +- 4 files changed, 112 insertions(+), 18 deletions(-) diff --git a/Week_04/045jump.js b/Week_04/045jump.js index 59c99e9c..24d0cd15 100644 --- a/Week_04/045jump.js +++ b/Week_04/045jump.js @@ -2,13 +2,33 @@ * https://leetcode-cn.com/problems/jump-game-ii/ * * 45. 跳跃游戏 II - * + * hard */ +/* + [2, 3, 1, 1, 4] + l 0 2 + r 2 4 +*/ + const jump = function(nums) { - + if (!Array.isArray(nums) || nums.length <= 1) return 0 + let l = 0, r = nums[0], times = 1 + while (r < nums.length - 1) { + ++times + let next = -Infinity + for(let i = l; i <= r; ++i) { + next = Math.max(next, nums[i] + i) + } + if (next <= r) return -1 // 没增加最远距离,则无法更远 + l = r + r = next + } + return times } // ---- test case ---- console.log(jump([])) console.log(jump([2,3,1,1,4])) +console.log(jump([2,1,1,1,1,4])) +console.log(jump([2,1,1,0,1,4])) diff --git a/Week_04/055canJump.js b/Week_04/055canJump.js index ecca5b3d..d0381603 100644 --- a/Week_04/055canJump.js +++ b/Week_04/055canJump.js @@ -1,5 +1,5 @@ /** - * https://leetcode-cn.com/problems/jump-game-ii/ + * https://leetcode-cn.com/problems/jump-game/ * * 55. 跳跃游戏 * @@ -7,12 +7,10 @@ */ const canJump = function(nums) { - if (Object.prototype.toString.call(nums) !== '[object Array]') return false + if (!Array.isArray(nums)) return false let endReachable = nums.length - 1 - for(let i = nums.length - 2; i >= 0; --i) { - if (nums[i] + i >= endReachable) { - endReachable = i - } + for (let i = nums.length - 2; i >= 0; --i) { + if (nums[i] + i >= endReachable) endReachable = i } return endReachable === 0 } diff --git a/Week_04/126findLadders.js b/Week_04/126findLadders.js index 863276ab..709cd96e 100644 --- a/Week_04/126findLadders.js +++ b/Week_04/126findLadders.js @@ -9,16 +9,18 @@ * @return {string[][]} */ -// BFS (不会写回溯就先用copy, 会超时。。。) -const findLadders = function(beginWord, endWord, wordList) { +// 解法一:BFS (不会写回溯就先用copy参数, 会超时。。。) +const findLadders1 = function (beginWord, endWord, wordList) { const res = [], - queue = [[1, [beginWord], new Set(wordList)]], - alphabets = 'abcdefghijklmnopqrstuvwxyz'.split('') + queue = [ + [1, [beginWord], new Set(wordList)] + ], + alphabets = 'abcdefghijklmnopqrstuvwxyz'.split('') let minLevel = Infinity // 最短转换序列的长度 while (queue.length) { const [level, path, wordsSet] = queue.pop(), - word = path[path.length - 1] - + word = path[path.length - 1] + // console.log("🚀", path) if (word === endWord) { res.push(path.slice()) @@ -38,7 +40,79 @@ const findLadders = function(beginWord, endWord, wordList) { return res.filter(path => path.length === minLevel) } + + + + +// 解法二:构建图 +var findLadders = function (beginWord, endWord, wordList) { + if (wordList.indexOf(endWord) < 0) return []; + if (wordList.indexOf(beginWord) == -1) wordList.push(beginWord); + + let allCombDict = new Map(); + let wordLevel = new Map(); + let wordConnection = new Map(); + let L = beginWord.length; + // 建图 + for (let word of wordList) { + for (let i = 0; i < L; ++i) { + let key = word.slice(0, i) + "*" + word.slice(i + 1); + if (allCombDict.has(key)) allCombDict.get(key).push(word); + else allCombDict.set(key, [word]); + } + } + let queue = [beginWord]; + let wordUsed = new Set(); + let step = 1; + let flag = 1; + //帮助我们判断是否能从beginWord到endWord,如果可以则转为0,这可以帮助我们提前结束循环,并且如果不能到达endWord,则不需要再进行DFS 直接返回[]; + //BFS + while (queue.length && flag) { + let len = queue.length; + for (let t = 0; t < len; ++t) { + let word = queue.shift(); + if (!wordUsed.has(word)) { + wordUsed.add(word); + wordLevel.set(word, step); + if (word == endWord) flag = 0; + for (let i = 0; i < L; ++i) { + let key = word.slice(0, i) + "*" + word.slice(i + 1); + if (allCombDict.has(key)) { + let connected = allCombDict.get(key).filter((d) => d != word);//这里要去除自身,两个原因:1.connected里面要保存的是该节点的邻居节点,自身不属于;2.如果将自身这个节点加进去会产生重复; + if (wordConnection.has(word)) + wordConnection.get(word).push(...connected); + else wordConnection.set(word, [...connected]); + queue.push(...connected); + } + } + } + } + step++; + } + if (flag) return []; + let res = []; + //DFS + function dfs(list, word, connection, level) { + let lev = level.get(word); + if (lev == 1) { + res.push([...list]); + return; + } + for (let node of connection.get(word)) { + if (level.get(node) == lev - 1) { + list.unshift(node); + dfs(list, node, connection, level); + list.shift(); + } + } + } + dfs([endWord], endWord, wordConnection, wordLevel); + return res; +}; + + + // ---- test case ---- -console.log(findLadders("hit", "cog", ["hot","dot","dog","lot","log","cog"])) -console.log(findLadders("hit", "cog", ["hot","dot","dog","lot","log"])) -console.log(findLadders("qa", "sq", ["si","go","se","cm","so","ph","mt","db","mb","sb","kr","ln","tm","le","av","sm","ar","ci","ca","br","ti","ba","to","ra","fa","yo","ow","sn","ya","cr","po","fe","ho","ma","re","or","rn","au","ur","rh","sr","tc","lt","lo","as","fr","nb","yb","if","pb","ge","th","pm","rb","sh","co","ga","li","ha","hz","no","bi","di","hi","qa","pi","os","uh","wm","an","me","mo","na","la","st","er","sc","ne","mn","mi","am","ex","pt","io","be","fm","ta","tb","ni","mr","pa","he","lr","sq","ye"])) +// console.log(findLadders("hit", "cog", ["hot", "dot", "dog", "lot", "log", "cog"])) +// console.log(findLadders("hit", "cog", ["hot", "dot", "dog", "lot", "log"])) +console.log(findLadders("qa", "sq", ["si", "go", "se", "cm", "so", "ph", "mt", "db", "mb", "sb", "kr", "ln", "tm", "le", "av", "sm", "ar", "ci", "ca", "br", "ti", "ba", "to", "ra", "fa", "yo", "ow", "sn", "ya", "cr", "po", "fe", "ho", "ma", "re", "or", "rn", "au", "ur", "rh", "sr", "tc", "lt", "lo", "as", "fr", "nb", "yb", "if", "pb", "ge", "th", "pm", "rb", "sh", "co", "ga", "li", "ha", "hz", "no", "bi", "di", "hi", "qa", "pi", "os", "uh", "wm", "an", "me", "mo", "na", "la", "st", "er", "sc", "ne", "mn", "mi", "am", "ex", "pt", "io", "be", "fm", "ta", "tb", "ni", "mr", "pa", "he", "lr", "sq", "ye"])) diff --git a/Week_04/homework.md b/Week_04/homework.md index b071f96d..bddaa0fe 100644 --- a/Week_04/homework.md +++ b/Week_04/homework.md @@ -9,6 +9,8 @@ + dfs & bfs + [实现代码](./126findLadders.js) ++ 有点难,自己写的BFS解法无法通过全部测试用例,会超时 ++ 网上图论的方法不是很懂 ### 3. 岛屿数量(近半年内,亚马逊在面试中考查此题达到 350 次) + dfs & bfs @@ -49,7 +51,7 @@ + greedy + [实现代码](./055canJump.js) -### TODO 11. 跳跃游戏 II (亚马逊、华为、字节跳动在半年内面试中考过) +### 11. 跳跃游戏 II (亚马逊、华为、字节跳动在半年内面试中考过) + greedy + [实现代码](./045jump.js) From bc5b2b39f8d79ef3d25accda9ae2945224fe54ed Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 2 Mar 2021 00:06:33 +0800 Subject: [PATCH 085/210] =?UTF-8?q?=E5=8D=95=E8=AF=8D=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=EF=BC=8Cbfs=20&=20dfs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_04/127ladderLength.js | 55 ++++++++++++++++++++++++++++++-------- Week_04/homework.md | 1 + 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/Week_04/127ladderLength.js b/Week_04/127ladderLength.js index bb7e4f18..d83f6f0d 100644 --- a/Week_04/127ladderLength.js +++ b/Week_04/127ladderLength.js @@ -6,19 +6,20 @@ // BFS, 搜索所有可能的单词是否在词库中 // 复杂度:O(单词个数 * 单词长度 * 26) -const ladderLength = function(beginWord, endWord, wordList) { - const wordsSet = new Set(wordList), - queue = [[beginWord, 1]], - alphbets = 'abcdefghijklmnopqrstuvwxyz'.split('') +const ladderLength = function (beginWord, endWord, wordList) { + const s = new Set(wordList), + queue = [[1, beginWord]], + alphs = [...'abcdefghijklmnopqrstuvwxyz'] while (queue.length) { - const [word, level] = queue.pop() + const [level, word] = queue.pop() + // console.log("🚀", level, word, s) if (word === endWord) return level for (let i = 0; i < word.length; ++i) { - for (const ch of alphbets) { + for (const ch of alphs) { const nextWord = word.slice(0, i) + ch + word.slice(i + 1) - if (wordsSet.has(nextWord)) { - wordsSet.delete(nextWord) - queue.unshift([nextWord, level + 1]) + if (s.has(nextWord)) { + s.delete(nextWord) + queue.unshift([level + 1, nextWord]) } } } @@ -26,6 +27,38 @@ const ladderLength = function(beginWord, endWord, wordList) { return 0 } +// DFS (递归,部分案例会超时!) +const ladderLength2 = function (beginWord, endWord, wordList) { + const s = new Set(wordList), + alphs = [...'abcdefghijklmnopqrstuvwxyz'] + let res = Infinity + const dfs = (level, word) => { + // console.log("🚀", level, res, word, s) + if (word === endWord) { + res = Math.min(res, level) + } + for (let i = 0; i < word.length; ++i) { + for (const ch of alphs) { + const nextWord = word.slice(0, i) + ch + word.slice(i + 1) + if (s.has(nextWord)) { + s.delete(nextWord) + dfs(level + 1, nextWord) + s.add(nextWord) + } + } + } + } + dfs(1, beginWord) + return res === Infinity ? 0 : res +} + // ---- test case ---- -console.log(ladderLength('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log', 'cog'])) -console.log(ladderLength('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log'])) +// console.log(ladderLength('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log', 'cog'])) +// console.log(ladderLength('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log'])) + +// console.log(ladderLength2('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log', 'cog'])) +// console.log(ladderLength2('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log'])) + +console.log(ladderLength("qa","sq",["si","go","se","cm","so","ph","mt","db","mb","sb","kr","ln","tm","le","av","sm","ar","ci","ca","br","ti","ba","to","ra","fa","yo","ow","sn","ya","cr","po","fe","ho","ma","re","or","rn","au","ur","rh","sr","tc","lt","lo","as","fr","nb","yb","if","pb","ge","th","pm","rb","sh","co","ga","li","ha","hz","no","bi","di","hi","qa","pi","os","uh","wm","an","me","mo","na","la","st","er","sc","ne","mn","mi","am","ex","pt","io","be","fm","ta","tb","ni","mr","pa","he","lr","sq","ye"])) + +console.log(ladderLength2("qa","sq",["si","go","se","cm","so","ph","mt","db","mb","sb","kr","ln","tm","le","av","sm","ar","ci","ca","br","ti","ba","to","ra","fa","yo","ow","sn","ya","cr","po","fe","ho","ma","re","or","rn","au","ur","rh","sr","tc","lt","lo","as","fr","nb","yb","if","pb","ge","th","pm","rb","sh","co","ga","li","ha","hz","no","bi","di","hi","qa","pi","os","uh","wm","an","me","mo","na","la","st","er","sc","ne","mn","mi","am","ex","pt","io","be","fm","ta","tb","ni","mr","pa","he","lr","sq","ye"])) diff --git a/Week_04/homework.md b/Week_04/homework.md index bddaa0fe..0a7567bc 100644 --- a/Week_04/homework.md +++ b/Week_04/homework.md @@ -11,6 +11,7 @@ + [实现代码](./126findLadders.js) + 有点难,自己写的BFS解法无法通过全部测试用例,会超时 + 网上图论的方法不是很懂 + ### 3. 岛屿数量(近半年内,亚马逊在面试中考查此题达到 350 次) + dfs & bfs From 3c902fe8055f8e340b2a69af6ffbf17e532a3a28 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 2 Mar 2021 00:55:07 +0800 Subject: [PATCH 086/210] =?UTF-8?q?=E5=8D=95=E8=AF=8D=E6=8E=A5=E9=BE=99II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_04/126findLadders.js | 18 +++++++++++------- Week_04/127ladderLength.js | 32 +++++++++++++++----------------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/Week_04/126findLadders.js b/Week_04/126findLadders.js index 709cd96e..545f4292 100644 --- a/Week_04/126findLadders.js +++ b/Week_04/126findLadders.js @@ -9,23 +9,25 @@ * @return {string[][]} */ -// 解法一:BFS (不会写回溯就先用copy参数, 会超时。。。) +// 解法一:BFS (要搜寻的情况太多,会超时!!!) +// 难点在于要找到 “所有的最短路径” +// 某测试用例中共有 51 条最短,全部搜出来很耗性能!! 164708.968ms const findLadders1 = function (beginWord, endWord, wordList) { const res = [], queue = [ [1, [beginWord], new Set(wordList)] ], alphabets = 'abcdefghijklmnopqrstuvwxyz'.split('') - let minLevel = Infinity // 最短转换序列的长度 + let minLevel = Infinity while (queue.length) { const [level, path, wordsSet] = queue.pop(), word = path[path.length - 1] - // console.log("🚀", path) - if (word === endWord) { + if (word === endWord && (minLevel === Infinity || level === minLevel)) { res.push(path.slice()) - minLevel = Math.min(minLevel, level) + minLevel = level } else { + if (level >= minLevel) continue for (let i = 0; i < word.length; ++i) { for (const ch of alphabets) { const nextWord = word.slice(0, i) + ch + word.slice(i + 1) @@ -37,7 +39,7 @@ const findLadders1 = function (beginWord, endWord, wordList) { } } } - return res.filter(path => path.length === minLevel) + return res } @@ -115,4 +117,6 @@ var findLadders = function (beginWord, endWord, wordList) { // ---- test case ---- // console.log(findLadders("hit", "cog", ["hot", "dot", "dog", "lot", "log", "cog"])) // console.log(findLadders("hit", "cog", ["hot", "dot", "dog", "lot", "log"])) -console.log(findLadders("qa", "sq", ["si", "go", "se", "cm", "so", "ph", "mt", "db", "mb", "sb", "kr", "ln", "tm", "le", "av", "sm", "ar", "ci", "ca", "br", "ti", "ba", "to", "ra", "fa", "yo", "ow", "sn", "ya", "cr", "po", "fe", "ho", "ma", "re", "or", "rn", "au", "ur", "rh", "sr", "tc", "lt", "lo", "as", "fr", "nb", "yb", "if", "pb", "ge", "th", "pm", "rb", "sh", "co", "ga", "li", "ha", "hz", "no", "bi", "di", "hi", "qa", "pi", "os", "uh", "wm", "an", "me", "mo", "na", "la", "st", "er", "sc", "ne", "mn", "mi", "am", "ex", "pt", "io", "be", "fm", "ta", "tb", "ni", "mr", "pa", "he", "lr", "sq", "ye"])) +console.time('findLadders1') +console.log(findLadders1("qa", "sq", ["si", "go", "se", "cm", "so", "ph", "mt", "db", "mb", "sb", "kr", "ln", "tm", "le", "av", "sm", "ar", "ci", "ca", "br", "ti", "ba", "to", "ra", "fa", "yo", "ow", "sn", "ya", "cr", "po", "fe", "ho", "ma", "re", "or", "rn", "au", "ur", "rh", "sr", "tc", "lt", "lo", "as", "fr", "nb", "yb", "if", "pb", "ge", "th", "pm", "rb", "sh", "co", "ga", "li", "ha", "hz", "no", "bi", "di", "hi", "qa", "pi", "os", "uh", "wm", "an", "me", "mo", "na", "la", "st", "er", "sc", "ne", "mn", "mi", "am", "ex", "pt", "io", "be", "fm", "ta", "tb", "ni", "mr", "pa", "he", "lr", "sq", "ye"])) +console.timeEnd('findLadders1') diff --git a/Week_04/127ladderLength.js b/Week_04/127ladderLength.js index d83f6f0d..9072ab98 100644 --- a/Week_04/127ladderLength.js +++ b/Week_04/127ladderLength.js @@ -27,38 +27,36 @@ const ladderLength = function (beginWord, endWord, wordList) { return 0 } -// DFS (递归,部分案例会超时!) -const ladderLength2 = function (beginWord, endWord, wordList) { +// 拓展:寻一种解法 +const findOnePath = function (beginWord, endWord, wordList) { const s = new Set(wordList), + queue = [[1, [beginWord]]] alphs = [...'abcdefghijklmnopqrstuvwxyz'] - let res = Infinity - const dfs = (level, word) => { - // console.log("🚀", level, res, word, s) - if (word === endWord) { - res = Math.min(res, level) - } + while (queue.length) { + const [level, path] = queue.pop() + const word = path[path.length - 1] + if (word === endWord) return path for (let i = 0; i < word.length; ++i) { for (const ch of alphs) { const nextWord = word.slice(0, i) + ch + word.slice(i + 1) if (s.has(nextWord)) { s.delete(nextWord) - dfs(level + 1, nextWord) - s.add(nextWord) + queue.unshift([level + 1, path.concat([nextWord])]) } } } } - dfs(1, beginWord) - return res === Infinity ? 0 : res + return [] } // ---- test case ---- +// console.log(ladderLength('abc', 'def', ['dbc', 'bbc', 'dec', 'def', 'log', 'cog'])) // console.log(ladderLength('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log', 'cog'])) // console.log(ladderLength('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log'])) +// console.log(ladderLength("qa","sq",["si","go","se","cm","so","ph","mt","db","mb","sb","kr","ln","tm","le","av","sm","ar","ci","ca","br","ti","ba","to","ra","fa","yo","ow","sn","ya","cr","po","fe","ho","ma","re","or","rn","au","ur","rh","sr","tc","lt","lo","as","fr","nb","yb","if","pb","ge","th","pm","rb","sh","co","ga","li","ha","hz","no","bi","di","hi","qa","pi","os","uh","wm","an","me","mo","na","la","st","er","sc","ne","mn","mi","am","ex","pt","io","be","fm","ta","tb","ni","mr","pa","he","lr","sq","ye"])) -// console.log(ladderLength2('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log', 'cog'])) -// console.log(ladderLength2('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log'])) - -console.log(ladderLength("qa","sq",["si","go","se","cm","so","ph","mt","db","mb","sb","kr","ln","tm","le","av","sm","ar","ci","ca","br","ti","ba","to","ra","fa","yo","ow","sn","ya","cr","po","fe","ho","ma","re","or","rn","au","ur","rh","sr","tc","lt","lo","as","fr","nb","yb","if","pb","ge","th","pm","rb","sh","co","ga","li","ha","hz","no","bi","di","hi","qa","pi","os","uh","wm","an","me","mo","na","la","st","er","sc","ne","mn","mi","am","ex","pt","io","be","fm","ta","tb","ni","mr","pa","he","lr","sq","ye"])) -console.log(ladderLength2("qa","sq",["si","go","se","cm","so","ph","mt","db","mb","sb","kr","ln","tm","le","av","sm","ar","ci","ca","br","ti","ba","to","ra","fa","yo","ow","sn","ya","cr","po","fe","ho","ma","re","or","rn","au","ur","rh","sr","tc","lt","lo","as","fr","nb","yb","if","pb","ge","th","pm","rb","sh","co","ga","li","ha","hz","no","bi","di","hi","qa","pi","os","uh","wm","an","me","mo","na","la","st","er","sc","ne","mn","mi","am","ex","pt","io","be","fm","ta","tb","ni","mr","pa","he","lr","sq","ye"])) +console.log(findOnePath('abc', 'def', ['dbc', 'bbc', 'dec', 'def', 'log', 'cog'])) +console.log(findOnePath('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log', 'cog'])) +console.log(findOnePath('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log'])) +console.log(findOnePath("qa","sq",["si","go","se","cm","so","ph","mt","db","mb","sb","kr","ln","tm","le","av","sm","ar","ci","ca","br","ti","ba","to","ra","fa","yo","ow","sn","ya","cr","po","fe","ho","ma","re","or","rn","au","ur","rh","sr","tc","lt","lo","as","fr","nb","yb","if","pb","ge","th","pm","rb","sh","co","ga","li","ha","hz","no","bi","di","hi","qa","pi","os","uh","wm","an","me","mo","na","la","st","er","sc","ne","mn","mi","am","ex","pt","io","be","fm","ta","tb","ni","mr","pa","he","lr","sq","ye"])) From 3314f35665d2c013a30eae1583af510db32ab7fd Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 2 Mar 2021 01:09:50 +0800 Subject: [PATCH 087/210] =?UTF-8?q?=E5=8D=95=E8=AF=8D=E6=8E=A5=E9=BE=99II?= =?UTF-8?q?=20=E8=BF=98=E6=98=AF=E9=9A=BE=EF=BC=8C=E7=9C=8B=E8=B5=B7?= =?UTF-8?q?=E6=9D=A5=E5=BF=85=E9=A1=BB=E7=94=A8=E5=9B=BE=E8=AE=BA=E7=9A=84?= =?UTF-8?q?=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_04/126findLadders.js | 28 +++++++++++++++------------- Week_04/127ladderLength.js | 2 +- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Week_04/126findLadders.js b/Week_04/126findLadders.js index 545f4292..8c16d26b 100644 --- a/Week_04/126findLadders.js +++ b/Week_04/126findLadders.js @@ -11,29 +11,27 @@ // 解法一:BFS (要搜寻的情况太多,会超时!!!) // 难点在于要找到 “所有的最短路径” -// 某测试用例中共有 51 条最短,全部搜出来很耗性能!! 164708.968ms +// 无法通过第 23 条测试用例,开 set 太多了,JS引擎垃圾回收跑崩了!!! const findLadders1 = function (beginWord, endWord, wordList) { const res = [], - queue = [ - [1, [beginWord], new Set(wordList)] - ], - alphabets = 'abcdefghijklmnopqrstuvwxyz'.split('') + queue = [[1, [beginWord], new Set(wordList)]], + alphs = [...'abcdefghijklmnopqrstuvwxyz'] let minLevel = Infinity while (queue.length) { - const [level, path, wordsSet] = queue.pop(), - word = path[path.length - 1] + const [level, path, wordSet] = queue.pop() + const word = path[path.length - 1] if (word === endWord && (minLevel === Infinity || level === minLevel)) { res.push(path.slice()) - minLevel = level + minLevel = level // 记录最短路径,用于后续剪枝 } else { - if (level >= minLevel) continue + if (level >= minLevel) continue // 剪枝 for (let i = 0; i < word.length; ++i) { - for (const ch of alphabets) { + for (const ch of alphs) { const nextWord = word.slice(0, i) + ch + word.slice(i + 1) - if (wordsSet.has(nextWord)) { - wordsSet.delete(nextWord) - queue.unshift([level + 1, path.concat([nextWord]), new Set(wordsSet)]) + if (wordSet.has(nextWord)) { + wordSet.delete(nextWord) + queue.unshift([level + 1, path.concat([nextWord]), new Set(wordSet)]) } } } @@ -120,3 +118,7 @@ var findLadders = function (beginWord, endWord, wordList) { console.time('findLadders1') console.log(findLadders1("qa", "sq", ["si", "go", "se", "cm", "so", "ph", "mt", "db", "mb", "sb", "kr", "ln", "tm", "le", "av", "sm", "ar", "ci", "ca", "br", "ti", "ba", "to", "ra", "fa", "yo", "ow", "sn", "ya", "cr", "po", "fe", "ho", "ma", "re", "or", "rn", "au", "ur", "rh", "sr", "tc", "lt", "lo", "as", "fr", "nb", "yb", "if", "pb", "ge", "th", "pm", "rb", "sh", "co", "ga", "li", "ha", "hz", "no", "bi", "di", "hi", "qa", "pi", "os", "uh", "wm", "an", "me", "mo", "na", "la", "st", "er", "sc", "ne", "mn", "mi", "am", "ex", "pt", "io", "be", "fm", "ta", "tb", "ni", "mr", "pa", "he", "lr", "sq", "ye"])) console.timeEnd('findLadders1') + +console.time('findLadders') +console.log(findLadders("cet", "ism", ["kid","tag","pup","ail","tun","woo","erg","luz","brr","gay","sip","kay","per","val","mes","ohs","now","boa","cet","pal","bar","die","war","hay","eco","pub","lob","rue","fry","lit","rex","jan","cot","bid","ali","pay","col","gum","ger","row","won","dan","rum","fad","tut","sag","yip","sui","ark","has","zip","fez","own","ump","dis","ads","max","jaw","out","btu","ana","gap","cry","led","abe","box","ore","pig","fie","toy","fat","cal","lie","noh","sew","ono","tam","flu","mgm","ply","awe","pry","tit","tie","yet","too","tax","jim","san","pan","map","ski","ova","wed","non","wac","nut","why","bye","lye","oct","old","fin","feb","chi","sap","owl","log","tod","dot","bow","fob","for","joe","ivy","fan","age","fax","hip","jib","mel","hus","sob","ifs","tab","ara","dab","jag","jar","arm","lot","tom","sax","tex","yum","pei","wen","wry","ire","irk","far","mew","wit","doe","gas","rte","ian","pot","ask","wag","hag","amy","nag","ron","soy","gin","don","tug","fay","vic","boo","nam","ave","buy","sop","but","orb","fen","paw","his","sub","bob","yea","oft","inn","rod","yam","pew","web","hod","hun","gyp","wei","wis","rob","gad","pie","mon","dog","bib","rub","ere","dig","era","cat","fox","bee","mod","day","apr","vie","nev","jam","pam","new","aye","ani","and","ibm","yap","can","pyx","tar","kin","fog","hum","pip","cup","dye","lyx","jog","nun","par","wan","fey","bus","oak","bad","ats","set","qom","vat","eat","pus","rev","axe","ion","six","ila","lao","mom","mas","pro","few","opt","poe","art","ash","oar","cap","lop","may","shy","rid","bat","sum","rim","fee","bmw","sky","maj","hue","thy","ava","rap","den","fla","auk","cox","ibo","hey","saw","vim","sec","ltd","you","its","tat","dew","eva","tog","ram","let","see","zit","maw","nix","ate","gig","rep","owe","ind","hog","eve","sam","zoo","any","dow","cod","bed","vet","ham","sis","hex","via","fir","nod","mao","aug","mum","hoe","bah","hal","keg","hew","zed","tow","gog","ass","dem","who","bet","gos","son","ear","spy","kit","boy","due","sen","oaf","mix","hep","fur","ada","bin","nil","mia","ewe","hit","fix","sad","rib","eye","hop","haw","wax","mid","tad","ken","wad","rye","pap","bog","gut","ito","woe","our","ado","sin","mad","ray","hon","roy","dip","hen","iva","lug","asp","hui","yak","bay","poi","yep","bun","try","lad","elm","nat","wyo","gym","dug","toe","dee","wig","sly","rip","geo","cog","pas","zen","odd","nan","lay","pod","fit","hem","joy","bum","rio","yon","dec","leg","put","sue","dim","pet","yaw","nub","bit","bur","sid","sun","oil","red","doc","moe","caw","eel","dix","cub","end","gem","off","yew","hug","pop","tub","sgt","lid","pun","ton","sol","din","yup","jab","pea","bug","gag","mil","jig","hub","low","did","tin","get","gte","sox","lei","mig","fig","lon","use","ban","flo","nov","jut","bag","mir","sty","lap","two","ins","con","ant","net","tux","ode","stu","mug","cad","nap","gun","fop","tot","sow","sal","sic","ted","wot","del","imp","cob","way","ann","tan","mci","job","wet","ism","err","him","all","pad","hah","hie","aim","ike","jed","ego","mac","baa","min","com","ill","was","cab","ago","ina","big","ilk","gal","tap","duh","ola","ran","lab","top","gob","hot","ora","tia","kip","han","met","hut","she","sac","fed","goo","tee","ell","not","act","gil","rut","ala","ape","rig","cid","god","duo","lin","aid","gel","awl","lag","elf","liz","ref","aha","fib","oho","tho","her","nor","ace","adz","fun","ned","coo","win","tao","coy","van","man","pit","guy","foe","hid","mai","sup","jay","hob","mow","jot","are","pol","arc","lax","aft","alb","len","air","pug","pox","vow","got","meg","zoe","amp","ale","bud","gee","pin","dun","pat","ten","mob"])) +console.timeEnd('findLadders') diff --git a/Week_04/127ladderLength.js b/Week_04/127ladderLength.js index 9072ab98..098c7767 100644 --- a/Week_04/127ladderLength.js +++ b/Week_04/127ladderLength.js @@ -27,7 +27,7 @@ const ladderLength = function (beginWord, endWord, wordList) { return 0 } -// 拓展:寻一种解法 +// 拓展:返回其中一条最短路径 const findOnePath = function (beginWord, endWord, wordList) { const s = new Set(wordList), queue = [[1, [beginWord]]] From cf481a5f32f4e5904e7304934be6634dfb340bff Mon Sep 17 00:00:00 2001 From: alwynzhou Date: Wed, 3 Mar 2021 20:05:39 +0800 Subject: [PATCH 088/210] robotSim --- Week_04/874robotSim.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/Week_04/874robotSim.js b/Week_04/874robotSim.js index c5e31d8e..87798489 100644 --- a/Week_04/874robotSim.js +++ b/Week_04/874robotSim.js @@ -10,28 +10,24 @@ // direct: 0 top | 1 right | 2 down | 3 left const robotSim = function(commands, obstacles) { let x = 0, y = 0, direct = 0, maxDist = 0 - const obsSet = new Set(obstacles.map(item => item.join())), + const obsSet = new Set(obstacles.map(pos => pos.join())), dx = [0, 1, 0, -1], dy = [1, 0, -1, 0] for(const command of commands) { - if (command === -1) { - direct = (direct + 1) % 4 - } else if (command === -2) { + if (command === -2) { direct = (direct + 3) % 4 - } else { - // 模拟每一步行走 + } else if (command === -1) { + direct = (direct + 1) % 4 + } else if (command >= 1 && command <= 9) { for (let i = 0; i < command; ++i) { const px = x + dx[direct] const py = y + dy[direct] - if (obsSet.has(`${px},${py}`)) { // 遇到障碍物 - break - } else { + if (!obsSet.has(`${px},${py}`)) { x = px y = py - maxDist = Math.max(maxDist, x * x + y * y) } } - console.log(x, y, direct) + maxDist = Math.max(maxDist, x * x + y * y) } } return maxDist @@ -39,4 +35,4 @@ const robotSim = function(commands, obstacles) { console.log(robotSim([4, -1, 3], [])) console.log(robotSim([4, -1, 4, -2, 4], [[2,4]])) -// console.log(robotSim([1,2,-2,5,-1,-2,-1,8,3,-1,9,4,-2,3,2,4,3,9,2,-1,-1,-2,1,3,-2,4,1,4,-1,1,9,-1,-2,5,-1,5,5,-2,6,6,7,7,2,8,9,-1,7,4,6,9,9,9,-1,5,1,3,3,-1,5,9,7,4,8,-1,-2,1,3,2,9,3,-1,-2,8,8,7,5,-2,6,8,4,6,2,7,2,-1,7,-2,3,3,2,-2,6,9,8,1,-2,-1,1,4,7], [[-57,-58],[-72,91],[-55,35],[-20,29],[51,70],[-61,88],[-62,99],[52,17],[-75,-32],[91,-22],[54,33],[-45,-59],[47,-48],[53,-98],[-91,83],[81,12],[-34,-90],[-79,-82],[-15,-86],[-24,66],[-35,35],[3,31],[87,93],[2,-19],[87,-93],[24,-10],[84,-53],[86,87],[-88,-18],[-51,89],[96,66],[-77,-94],[-39,-1],[89,51],[-23,-72],[27,24],[53,-80],[52,-33],[32,4],[78,-55],[-25,18],[-23,47],[79,-5],[-23,-22],[14,-25],[-11,69],[63,36],[35,-99],[-24,82],[-29,-98],[-50,-70],[72,95],[80,80],[-68,-40],[65,70],[-92,78],[-45,-63],[1,34],[81,50],[14,91],[-77,-54],[13,-88],[24,37],[-12,59],[-48,-62],[57,-22],[-8,85],[48,71],[12,1],[-20,36],[-32,-14],[39,46],[-41,75],[13,-23],[98,10],[-88,64],[50,37],[-95,-32],[46,-91],[10,79],[-11,43],[-94,98],[79,42],[51,71],[4,-30],[2,74],[4,10],[61,98],[57,98],[46,43],[-16,72],[53,-69],[54,-96],[22,0],[-7,92],[-69,80],[68,-73],[-24,-92],[-21,82],[32,-1],[-6,16],[15,-29],[70,-66],[-85,80],[50,-3],[6,13],[-30,-98],[-30,59],[-67,40],[17,72],[79,82],[89,-100],[2,79],[-95,-46],[17,68],[-46,81],[-5,-57],[7,58],[-42,68],[19,-95],[-17,-76],[81,-86],[79,78],[-82,-67],[6,0],[35,-16],[98,83],[-81,100],[-11,46],[-21,-38],[-30,-41],[86,18],[-68,6],[80,75],[-96,-44],[-19,66],[21,84],[-56,-64],[39,-15],[0,45],[-81,-54],[-66,-93],[-4,2],[-42,-67],[-15,-33],[1,-32],[-74,-24],[7,18],[-62,84],[19,61],[39,79],[60,-98],[-76,45],[58,-98],[33,26],[-74,-95],[22,30],[-68,-62],[-59,4],[-62,35],[-78,80],[-82,54],[-42,81],[56,-15],[32,-19],[34,93],[57,-100],[-1,-87],[68,-26],[18,86],[-55,-19],[-68,-99],[-9,47],[24,94],[92,97],[5,67],[97,-71],[63,-57],[-52,-14],[-86,-78],[-17,92],[-61,-83],[-84,-10],[20,13],[-68,-47],[7,28],[66,89],[-41,-17],[-14,-46],[-72,-91],[4,52],[-17,-59],[-85,-46],[-94,-23],[-48,-3],[-64,-37],[2,26],[76,88],[-8,-46],[-19,-68]])) +console.log(robotSim([1,2,-2,5,-1,-2,-1,8,3,-1,9,4,-2,3,2,4,3,9,2,-1,-1,-2,1,3,-2,4,1,4,-1,1,9,-1,-2,5,-1,5,5,-2,6,6,7,7,2,8,9,-1,7,4,6,9,9,9,-1,5,1,3,3,-1,5,9,7,4,8,-1,-2,1,3,2,9,3,-1,-2,8,8,7,5,-2,6,8,4,6,2,7,2,-1,7,-2,3,3,2,-2,6,9,8,1,-2,-1,1,4,7], [[-57,-58],[-72,91],[-55,35],[-20,29],[51,70],[-61,88],[-62,99],[52,17],[-75,-32],[91,-22],[54,33],[-45,-59],[47,-48],[53,-98],[-91,83],[81,12],[-34,-90],[-79,-82],[-15,-86],[-24,66],[-35,35],[3,31],[87,93],[2,-19],[87,-93],[24,-10],[84,-53],[86,87],[-88,-18],[-51,89],[96,66],[-77,-94],[-39,-1],[89,51],[-23,-72],[27,24],[53,-80],[52,-33],[32,4],[78,-55],[-25,18],[-23,47],[79,-5],[-23,-22],[14,-25],[-11,69],[63,36],[35,-99],[-24,82],[-29,-98],[-50,-70],[72,95],[80,80],[-68,-40],[65,70],[-92,78],[-45,-63],[1,34],[81,50],[14,91],[-77,-54],[13,-88],[24,37],[-12,59],[-48,-62],[57,-22],[-8,85],[48,71],[12,1],[-20,36],[-32,-14],[39,46],[-41,75],[13,-23],[98,10],[-88,64],[50,37],[-95,-32],[46,-91],[10,79],[-11,43],[-94,98],[79,42],[51,71],[4,-30],[2,74],[4,10],[61,98],[57,98],[46,43],[-16,72],[53,-69],[54,-96],[22,0],[-7,92],[-69,80],[68,-73],[-24,-92],[-21,82],[32,-1],[-6,16],[15,-29],[70,-66],[-85,80],[50,-3],[6,13],[-30,-98],[-30,59],[-67,40],[17,72],[79,82],[89,-100],[2,79],[-95,-46],[17,68],[-46,81],[-5,-57],[7,58],[-42,68],[19,-95],[-17,-76],[81,-86],[79,78],[-82,-67],[6,0],[35,-16],[98,83],[-81,100],[-11,46],[-21,-38],[-30,-41],[86,18],[-68,6],[80,75],[-96,-44],[-19,66],[21,84],[-56,-64],[39,-15],[0,45],[-81,-54],[-66,-93],[-4,2],[-42,-67],[-15,-33],[1,-32],[-74,-24],[7,18],[-62,84],[19,61],[39,79],[60,-98],[-76,45],[58,-98],[33,26],[-74,-95],[22,30],[-68,-62],[-59,4],[-62,35],[-78,80],[-82,54],[-42,81],[56,-15],[32,-19],[34,93],[57,-100],[-1,-87],[68,-26],[18,86],[-55,-19],[-68,-99],[-9,47],[24,94],[92,97],[5,67],[97,-71],[63,-57],[-52,-14],[-86,-78],[-17,92],[-61,-83],[-84,-10],[20,13],[-68,-47],[7,28],[66,89],[-41,-17],[-14,-46],[-72,-91],[4,52],[-17,-59],[-85,-46],[-94,-23],[-48,-3],[-64,-37],[2,26],[76,88],[-8,-46],[-19,-68]])) From 08a4f45439a35249d8f62fae6be6b9619e540863 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 3 Mar 2021 21:11:02 +0800 Subject: [PATCH 089/210] solve uniquePath --- Week_04/874robotSim.js | 4 +++ Week_06/062uniquePaths.js | 47 ++++++++++++++++++++++++++ Week_06/063uniquePathsWithObstacles.js | 45 ++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 Week_06/062uniquePaths.js create mode 100644 Week_06/063uniquePathsWithObstacles.js diff --git a/Week_04/874robotSim.js b/Week_04/874robotSim.js index 87798489..4b9ffc3b 100644 --- a/Week_04/874robotSim.js +++ b/Week_04/874robotSim.js @@ -25,6 +25,8 @@ const robotSim = function(commands, obstacles) { if (!obsSet.has(`${px},${py}`)) { x = px y = py + } else { + break } } maxDist = Math.max(maxDist, x * x + y * y) @@ -33,6 +35,8 @@ const robotSim = function(commands, obstacles) { return maxDist } +console.time('robotSim') console.log(robotSim([4, -1, 3], [])) console.log(robotSim([4, -1, 4, -2, 4], [[2,4]])) console.log(robotSim([1,2,-2,5,-1,-2,-1,8,3,-1,9,4,-2,3,2,4,3,9,2,-1,-1,-2,1,3,-2,4,1,4,-1,1,9,-1,-2,5,-1,5,5,-2,6,6,7,7,2,8,9,-1,7,4,6,9,9,9,-1,5,1,3,3,-1,5,9,7,4,8,-1,-2,1,3,2,9,3,-1,-2,8,8,7,5,-2,6,8,4,6,2,7,2,-1,7,-2,3,3,2,-2,6,9,8,1,-2,-1,1,4,7], [[-57,-58],[-72,91],[-55,35],[-20,29],[51,70],[-61,88],[-62,99],[52,17],[-75,-32],[91,-22],[54,33],[-45,-59],[47,-48],[53,-98],[-91,83],[81,12],[-34,-90],[-79,-82],[-15,-86],[-24,66],[-35,35],[3,31],[87,93],[2,-19],[87,-93],[24,-10],[84,-53],[86,87],[-88,-18],[-51,89],[96,66],[-77,-94],[-39,-1],[89,51],[-23,-72],[27,24],[53,-80],[52,-33],[32,4],[78,-55],[-25,18],[-23,47],[79,-5],[-23,-22],[14,-25],[-11,69],[63,36],[35,-99],[-24,82],[-29,-98],[-50,-70],[72,95],[80,80],[-68,-40],[65,70],[-92,78],[-45,-63],[1,34],[81,50],[14,91],[-77,-54],[13,-88],[24,37],[-12,59],[-48,-62],[57,-22],[-8,85],[48,71],[12,1],[-20,36],[-32,-14],[39,46],[-41,75],[13,-23],[98,10],[-88,64],[50,37],[-95,-32],[46,-91],[10,79],[-11,43],[-94,98],[79,42],[51,71],[4,-30],[2,74],[4,10],[61,98],[57,98],[46,43],[-16,72],[53,-69],[54,-96],[22,0],[-7,92],[-69,80],[68,-73],[-24,-92],[-21,82],[32,-1],[-6,16],[15,-29],[70,-66],[-85,80],[50,-3],[6,13],[-30,-98],[-30,59],[-67,40],[17,72],[79,82],[89,-100],[2,79],[-95,-46],[17,68],[-46,81],[-5,-57],[7,58],[-42,68],[19,-95],[-17,-76],[81,-86],[79,78],[-82,-67],[6,0],[35,-16],[98,83],[-81,100],[-11,46],[-21,-38],[-30,-41],[86,18],[-68,6],[80,75],[-96,-44],[-19,66],[21,84],[-56,-64],[39,-15],[0,45],[-81,-54],[-66,-93],[-4,2],[-42,-67],[-15,-33],[1,-32],[-74,-24],[7,18],[-62,84],[19,61],[39,79],[60,-98],[-76,45],[58,-98],[33,26],[-74,-95],[22,30],[-68,-62],[-59,4],[-62,35],[-78,80],[-82,54],[-42,81],[56,-15],[32,-19],[34,93],[57,-100],[-1,-87],[68,-26],[18,86],[-55,-19],[-68,-99],[-9,47],[24,94],[92,97],[5,67],[97,-71],[63,-57],[-52,-14],[-86,-78],[-17,92],[-61,-83],[-84,-10],[20,13],[-68,-47],[7,28],[66,89],[-41,-17],[-14,-46],[-72,-91],[4,52],[-17,-59],[-85,-46],[-94,-23],[-48,-3],[-64,-37],[2,26],[76,88],[-8,-46],[-19,-68]])) +console.timeEnd('robotSim') diff --git a/Week_06/062uniquePaths.js b/Week_06/062uniquePaths.js new file mode 100644 index 00000000..6eaacc5b --- /dev/null +++ b/Week_06/062uniquePaths.js @@ -0,0 +1,47 @@ +/** + * https://leetcode-cn.com/problems/unique-paths/ + * 62. 不同路径 | medium + * + * dp + * a. 重复性 problem(i, j) = problem(i + 1, j) + problem(i, j + 1) + * b. 定义状态数组 + * c. DP方程 + */ + +// dp1: O(mn) O(mn) +const uniquePaths = function(m, n) { + const dp = new Array(m).fill(new Array(n).fill(1)) + for (let i = m - 2; i >= 0; --i) { + for (let j = n - 2; j >= 0; --j) { + dp[i][j] = dp[i + 1][j] + dp[i][j + 1] + } + } + return dp[0][0] +} + +// dp2 优化空间复杂度 +// O(mn) O(n) +const uniquePaths2 = function(m, n) { + const dp = new Array(n).fill(1) + for (let i = m - 2; i >= 0; --i) { + for (let j = n - 2; j >= 0; --j) { + dp[j] = dp[j] + dp[j + 1] + } + } + return dp[0] +} + +// ---- test case ---- +console.time('uniquePaths') +console.log(uniquePaths(3,7)) +console.log(uniquePaths(3,2)) +console.log(uniquePaths(7,3)) +console.log(uniquePaths(3,3)) +console.timeEnd('uniquePaths') + +console.time('uniquePaths2') +console.log(uniquePaths2(3,7)) +console.log(uniquePaths2(3,2)) +console.log(uniquePaths2(7,3)) +console.log(uniquePaths2(3,3)) +console.timeEnd('uniquePaths2') diff --git a/Week_06/063uniquePathsWithObstacles.js b/Week_06/063uniquePathsWithObstacles.js new file mode 100644 index 00000000..77cb0889 --- /dev/null +++ b/Week_06/063uniquePathsWithObstacles.js @@ -0,0 +1,45 @@ +/** + * https://leetcode-cn.com/problems/unique-paths-ii/ + * 63. 不同路径 II | medium + * + * dp[i][j] = dp[i + 1][j] + dp[i][j + 1] + * + */ + +// 障碍物处 dp[x] = 0 +const uniquePathsWithObstacles = function(obstacleGrid) { + if (!Array.isArray(obstacleGrid) || + obstacleGrid.length < 1 || + !Array.isArray(obstacleGrid[0]) || + obstacleGrid[0].length < 1) return 0 + + const m = obstacleGrid.length, + n = obstacleGrid[0].length, + dp = new Array(n).fill(-1) + + for(let i = m - 1; i >= 0; --i) { + for (let j = n - 1; j >= 0; --j) { + if (obstacleGrid[i][j] === 1) { + dp[j] = 0 + } else if (i === m - 1 || j === n - 1) { + if (dp[j] === 0 || (j + 1 < n && dp[j + 1] === 0)) { // 障碍节点 + dp[j] = 0 + } else { + dp[j] = 1 + } + } else { + dp[j] = dp[j] + dp[j + 1] + } + } + } + return dp[0] +} + + +// ---- test case ---- +console.time('uniquePathsWithObstacles') +console.log(uniquePathsWithObstacles([[0,0,0],[0,1,0],[0,0,0]])) +console.log(uniquePathsWithObstacles([[0,1],[0,0]])) +console.log(uniquePathsWithObstacles([[0,0],[0,1]])) +console.log(uniquePathsWithObstacles([[0,0],[1,1],[0,0]])) +console.timeEnd('uniquePathsWithObstacles') From 18913a97a34fc5e1ad5ce3061a73deab8fbbcc53 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 3 Mar 2021 22:40:46 +0800 Subject: [PATCH 090/210] solve 4sum --- Week_01/018fourSum.js | 40 +++++++++++++++++++++++++ Week_06/1143longestCommonSubsequence.js | 20 +++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 Week_01/018fourSum.js create mode 100644 Week_06/1143longestCommonSubsequence.js diff --git a/Week_01/018fourSum.js b/Week_01/018fourSum.js new file mode 100644 index 00000000..7854743b --- /dev/null +++ b/Week_01/018fourSum.js @@ -0,0 +1,40 @@ +/** + * https://leetcode-cn.com/problems/4sum/ + * 18. 四数之和 | medium + */ + +// O(n^3) +const fourSum = function (nums, target) { + if (!Array.isArray(nums) || nums.length < 4) return [] + nums.sort((x, y) => x - y) + const res = [] + for (let i = 0; i < nums.length - 3; ++i) { + if (i > 0 && nums[i] === nums[i - 1]) continue // unique + for (let j = i + 1; j < nums.length - 2; ++j) { + if (j > i + 1 && nums[j] === nums[j - 1]) continue //unique + let l = j + 1, r = nums.length - 1 + while (l < r) { + const sum = nums[i] + nums[j] + nums[l] + nums[r] + if (sum < target) { + while (l < r && nums[l] === nums[++l]) { } + } else if (sum > target) { + while (l < r && nums[r] === nums[--r]) { } + } else { + res.push([nums[i], nums[j], nums[l], nums[r]]) + while (l < r && nums[l] === nums[++l]) { } + while (l < r && nums[r] === nums[--r]) { } + } + } + } + } + return res +} + + +// test case +console.time('fourSum') +console.log(fourSum([], 0)) +console.log(fourSum([1,0,-1,0,-2,2], 0)) +console.log(fourSum([1,0,-1,0,-2,2], 2)) +console.log(fourSum([1,-2,-5,-4,-3,3,3,5], -11)) +console.timeEnd('fourSum') diff --git a/Week_06/1143longestCommonSubsequence.js b/Week_06/1143longestCommonSubsequence.js new file mode 100644 index 00000000..3fe0f34d --- /dev/null +++ b/Week_06/1143longestCommonSubsequence.js @@ -0,0 +1,20 @@ +/** + * https://leetcode-cn.com/problems/longest-common-subsequence/ + * 1143. 最长公共子序列 | medium + */ + +/* + +*/ + +const longestCommonSubsequence = function(s1, s2) { + +} + + +// ---- test case ---- +console.time('longestCommonSubsequence') +console.log(longestCommonSubsequence('abcde', 'ace')) +console.log(longestCommonSubsequence('abc', 'abc')) +console.log(longestCommonSubsequence('abc', 'def')) +console.timeEnd('longestCommonSubsequence') From 4b9ee8c5a499d9ed06ebfbf49cfd1ef54b998a84 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 5 Mar 2021 00:21:52 +0800 Subject: [PATCH 091/210] 053 maxSubArray --- Week_06/053maxSubArray.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Week_06/053maxSubArray.js diff --git a/Week_06/053maxSubArray.js b/Week_06/053maxSubArray.js new file mode 100644 index 00000000..21596989 --- /dev/null +++ b/Week_06/053maxSubArray.js @@ -0,0 +1,25 @@ +/** + * https://leetcode-cn.com/problems/maximum-subarray/ + * 53. 最大子序和 | easy + * + * a. 分治(子问题) maxSum(i) = max(maxSum(i-1), 0) + A[i] + * b. 状态数组定义 f[i] + * c. DP方程 f[i] = max(f(i-1), 0) + A[i] + */ + +// dp 空间可以压缩到单个变量 +const maxSubArray = function(A) { + if (!Array.isArray(A) || A.length < 1) return + let max = dp = A[0] + for (let i = 1; i < A.length; ++i) { + dp = Math.max(0, dp) + A[i] + max = Math.max(max, dp) + } + return max +} + +// ---- test case ---- +console.log(maxSubArray([-2,1,-3,4,-1,2,1,-5,4])) +console.log(maxSubArray([1])) +console.log(maxSubArray([0])) +console.log(maxSubArray([-1000])) From 0ec30ae4607cb425efcfb41f4fae3741acd0d8a2 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 6 Mar 2021 00:14:42 +0800 Subject: [PATCH 092/210] solve 1143 with dp --- Week_06/1143longestCommonSubsequence.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Week_06/1143longestCommonSubsequence.js b/Week_06/1143longestCommonSubsequence.js index 3fe0f34d..dfc0d2d2 100644 --- a/Week_06/1143longestCommonSubsequence.js +++ b/Week_06/1143longestCommonSubsequence.js @@ -4,11 +4,24 @@ */ /* - + * s1[-1] = s2[-1]: f(i, j) = f(i - 1, j - 1) + 1 + * s1[-1] != s2[-1]: f(i, j) = max(f(i - 1, j), f(i, j - 1)) */ const longestCommonSubsequence = function(s1, s2) { - + const m = s1.length, n = s2.length + if (m === 0 || n === 0 || typeof s1 !== 'string' || typeof s2 !== 'string') return 0 + const dp = new Array(m + 1).fill(0).map(_ => new Array(n + 1).fill(0)) + for(let i = 1; i < m + 1; ++i) { + for (let j = 1; j < n + 1; ++j) { + if (s1[i - 1] === s2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1 + } else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + } + } + } + return dp[m][n] } From d14bc932b78e92c29d517b735fe7843a4c8d8a97 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 6 Mar 2021 00:47:24 +0800 Subject: [PATCH 093/210] solve every day task --- Week_01/070climbStairs.js | 19 +++++++++++-------- Week_03/070climbStairs.js | 17 ----------------- Week_04/074searchMatrix.js | 25 +++++++++++++------------ Week_06/1143longestCommonSubsequence.js | 5 +++-- 4 files changed, 27 insertions(+), 39 deletions(-) delete mode 100644 Week_03/070climbStairs.js diff --git a/Week_01/070climbStairs.js b/Week_01/070climbStairs.js index 2766d353..58ad341e 100644 --- a/Week_01/070climbStairs.js +++ b/Week_01/070climbStairs.js @@ -1,16 +1,19 @@ /** * https://leetcode-cn.com/problems/climbing-stairs/ - * + * 70. 爬楼梯 | easy + * dp + * f(n) = f(n - 1) + f(n - 2) */ // 思路:fibnacci数列 const climbStairs = function(n) { - if (typeof n !== 'number' || n < 4) return n - let a = 2, b = 3, c - for(let i = 4; i <= n; ++i) { - c = a + b - a = b - b = c + if (typeof n !== 'number') return 0 + if (n < 3) return n + let f1 = 1, f2 = 2, f3 + for (let i = 3; i <= n; ++i) { + f3 = f1 + f2 + f1 = f2 + f2 = f3 } - return c + return f3 } diff --git a/Week_03/070climbStairs.js b/Week_03/070climbStairs.js deleted file mode 100644 index 4f9893b0..00000000 --- a/Week_03/070climbStairs.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * https://leetcode-cn.com/problems/climbing-stairs/ - * @param {number} n - * @return {number} - */ -// 思路:fibnacci f(n) = f(n-1) + f(n-2) -var climbStairs = function(n) { - if (typeof n !== 'number') return 0 - if (n < 3) return n - let f1 = 1, f2 = 2, f3 = 3 - for(let i = 3; i <= n; ++i) { - f3 = f1 + f2 - f1 = f2 - f2 = f3 - } - return f3 -}; diff --git a/Week_04/074searchMatrix.js b/Week_04/074searchMatrix.js index 9f21bfe0..227c6333 100644 --- a/Week_04/074searchMatrix.js +++ b/Week_04/074searchMatrix.js @@ -13,21 +13,22 @@ */ const searchMatrix = function(matrix, target) { - const _getVal = (x) => { - const i = Math.floor(x/n) - const j = x % n - return matrix[i][j] + const _getVal = (idx) => { + const x = Math.floor(idx / n) + const y = idx % n + return matrix[x][y] } const m = matrix.length, n = matrix[0].length - let l = 0, r = m * n - 1 - while (l <= r) { - const mid = l + ((r - l) >> 1), - val = _getVal(mid) - if (val === target) return true - if (val > target) { - r = mid - 1 + let lo = 0, hi = m * n - 1 + while (lo <= hi) { + const mid = lo + ((hi - lo) >> 1) + const val = _getVal(mid) + if (val === target) { + return true + } else if (val > target){ + hi = mid - 1 } else { - l = mid + 1 + lo = mid + 1 } } return false diff --git a/Week_06/1143longestCommonSubsequence.js b/Week_06/1143longestCommonSubsequence.js index dfc0d2d2..726ab3b8 100644 --- a/Week_06/1143longestCommonSubsequence.js +++ b/Week_06/1143longestCommonSubsequence.js @@ -6,14 +6,15 @@ /* * s1[-1] = s2[-1]: f(i, j) = f(i - 1, j - 1) + 1 * s1[-1] != s2[-1]: f(i, j) = max(f(i - 1, j), f(i, j - 1)) + * tip: 声明dp数组,空首行和首列,便于迭代。 */ const longestCommonSubsequence = function(s1, s2) { const m = s1.length, n = s2.length if (m === 0 || n === 0 || typeof s1 !== 'string' || typeof s2 !== 'string') return 0 const dp = new Array(m + 1).fill(0).map(_ => new Array(n + 1).fill(0)) - for(let i = 1; i < m + 1; ++i) { - for (let j = 1; j < n + 1; ++j) { + for(let i = 1; i <= m; ++i) { + for (let j = 1; j <= n; ++j) { if (s1[i - 1] === s2[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1 } else { From 25f5cb4f1bba76a56588c5912f91612cf6f06e2b Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 7 Mar 2021 16:59:23 +0800 Subject: [PATCH 094/210] solve minPathSum --- Week_06/064minPathSum.js | 63 ++++++++++++++++++++++++++++++++++++++++ Week_06/README.md | 13 +++++++++ Week_06/homework.md | 2 ++ 3 files changed, 78 insertions(+) create mode 100644 Week_06/064minPathSum.js diff --git a/Week_06/064minPathSum.js b/Week_06/064minPathSum.js new file mode 100644 index 00000000..157380ac --- /dev/null +++ b/Week_06/064minPathSum.js @@ -0,0 +1,63 @@ +/** + * @param {number[][]} grid + * @return {number} + * F(i, j) = A(i, j) + min(F(i-1, j) + F(i, j-1)) + */ + +// 无副作用 O(mn) O(n) +const minPathSum1 = function(A) { + if (!Array.isArray(A) || + A.length < 1 || + !Array.isArray(A[0]) || + A[0].length < 1) return -1 + + const m = A.length, n = A[0].length + const dp = new Array(n).fill(0) + for (let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + if (i === 0 && j === 0) { + dp[j] = A[i][j] + } else if (i === 0) { + dp[j] = dp[j - 1] + A[i][j] + } else if (j === 0) { + dp[j] += A[i][j] + } else { + dp[j] = Math.min(dp[j], dp[j - 1]) + A[i][j] + } + } + } + return dp[n - 1] +} + +// 有副作用, 会修改入参矩阵 +const minPathSum2 = function (A) { + if (!Array.isArray(A) || + A.length < 1 || + !Array.isArray(A[0]) || + A[0].length < 1) return -1 + + const m = A.length, n = A[0].length + for(let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + if (i === 0 && j === 0) { + continue + } else if (i === 0) { + A[i][j] += A[i][j - 1] + } else if (j === 0) { + A[i][j] += A[i - 1][j] + } else { + A[i][j] += Math.min(A[i - 1][j], A[i][j - 1]) + } + } + } + return A[m - 1][n - 1] +} +// ---- test case ---- +console.time('minPathSum1') +console.log(minPathSum1([[1,3,1],[1,5,1],[4,2,1]])) +console.log(minPathSum1([[1,2,3],[4,5,6]])) +console.timeEnd('minPathSum1') +console.time('minPathSum2') +console.log(minPathSum2([[1,3,1],[1,5,1],[4,2,1]])) +console.log(minPathSum2([[1,2,3],[4,5,6]])) +console.timeEnd('minPathSum2') diff --git a/Week_06/README.md b/Week_06/README.md index 85f8a488..70054192 100644 --- a/Week_06/README.md +++ b/Week_06/README.md @@ -2,3 +2,16 @@ ## 第12课:动态规划 +**dp的关键点** + +1. 最优子结构 opt[n] = bestOf(opt[n-1], opt[n-2],...) +2. 储存中间状态 opt[i] +3. 递推公式(状态转移方程、dp方程) + + 🌰(Fib):f(i) = f(i-1) + f(i-2) + + 🌰(二维路径):f(i, j) = f(i+1, j) + f(i, j+1) + +**切题步骤** + +a. 重复性(分治) +b. 定义状态数组 +c. DP方程 diff --git a/Week_06/homework.md b/Week_06/homework.md index 564e5fef..e277293a 100644 --- a/Week_06/homework.md +++ b/Week_06/homework.md @@ -2,6 +2,8 @@ ## 1. 最小路径和(亚马逊、高盛集团、谷歌在半年内面试中考过) ++ dp ++ [实现代码](./064minPathSum.js) ## 2. 解码方法(亚马逊、Facebook、字节跳动在半年内面试中考过) From 9ceb8a96c9a842e6634d7a1426a52251d5e8fda3 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 8 Mar 2021 01:34:51 +0800 Subject: [PATCH 095/210] complete catelogy --- Week_07/README.md | 4 +++- Week_07/homework.md | 14 ++++++++++++++ Week_08/README.md | 12 +++++++++++- Week_08/homework.md | 17 +++++++++++++++++ Week_09/README.md | 14 +++++++++++++- Week_09/homework.md | 1 + 6 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 Week_07/homework.md create mode 100644 Week_08/homework.md create mode 100644 Week_09/homework.md diff --git a/Week_07/README.md b/Week_07/README.md index 50de3041..474d30d1 100644 --- a/Week_07/README.md +++ b/Week_07/README.md @@ -1 +1,3 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 第13课:高级搜索 diff --git a/Week_07/homework.md b/Week_07/homework.md new file mode 100644 index 00000000..9153de08 --- /dev/null +++ b/Week_07/homework.md @@ -0,0 +1,14 @@ +# 作业 + +简单 +爬楼梯(阿里巴巴、腾讯、字节跳动在半年内面试常考) + +中等 +括号生成(亚马逊、Facebook、字节跳动在半年内面试中考过) +有效的数独(亚马逊、苹果、微软在半年内面试中考过) +单词接龙(亚马逊、Facebook、谷歌在半年内面试中考过) +最小基因变化(谷歌、Twitter、腾讯在半年内面试中考过) + +困难 +N 皇后(亚马逊、苹果、字节跳动在半年内面试中考过) +解数独(亚马逊、华为、微软在半年内面试中考过) diff --git a/Week_08/README.md b/Week_08/README.md index 50de3041..166cccb6 100644 --- a/Week_08/README.md +++ b/Week_08/README.md @@ -1 +1,11 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 第 14 课 | 字典树和并查集 + + +## 第 15 课 | 红黑树和AVL树 + + +## 第 16 课 | 位运算 + + diff --git a/Week_08/homework.md b/Week_08/homework.md new file mode 100644 index 00000000..ace949bf --- /dev/null +++ b/Week_08/homework.md @@ -0,0 +1,17 @@ +# 作业 + +简单 +位 1 的个数(Facebook、苹果在半年内面试中考过) +2 的幂(谷歌、亚马逊、苹果在半年内面试中考过) +颠倒二进制位(苹果在半年内面试中考过) + +中等 +实现 Trie (前缀树) (亚马逊、微软、谷歌在半年内面试中考过) +省份数量(亚马逊、Facebook、字节跳动在半年内面试中考过) +岛屿数量(近半年内,亚马逊在面试中考查此题达到 361 次) +被围绕的区域(亚马逊、eBay、谷歌在半年内面试中考过) + +困难 +单词搜索 II (亚马逊、微软、苹果在半年内面试中考过) +N 皇后(字节跳动、亚马逊、百度在半年内面试中考过) +N 皇后 II (亚马逊在半年内面试中考过) diff --git a/Week_09/README.md b/Week_09/README.md index 50de3041..827e166c 100644 --- a/Week_09/README.md +++ b/Week_09/README.md @@ -1 +1,13 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 第 17 课 | 布隆过滤器 & LRU 缓存 + + +## 第 18 课 | 排序算法 + + +## 第 19 课 | 高级动态规划 + + +## 第 20 课 | 字符串算法 + diff --git a/Week_09/homework.md b/Week_09/homework.md new file mode 100644 index 00000000..c261e599 --- /dev/null +++ b/Week_09/homework.md @@ -0,0 +1 @@ +# 作业 From d1a808d94030672e905cbf657885ca30eb111ca6 Mon Sep 17 00:00:00 2001 From: alwynzhou Date: Tue, 9 Mar 2021 10:07:18 +0800 Subject: [PATCH 096/210] maxArea --- Week_01/011maxArea.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Week_01/011maxArea.js b/Week_01/011maxArea.js index e7ca408a..20614bae 100644 --- a/Week_01/011maxArea.js +++ b/Week_01/011maxArea.js @@ -29,12 +29,12 @@ console.log(maxArea1([1,1])) console.log(maxArea1([4,3,2,1,4])) console.log(maxArea1([1,2,1])) -// 解法二: O(n) +// 解法二: O(n) 核心:移动短板,area可能会变大;移动长板,area只会不变或变小。因此,双指针,每次移动短板即可。 const maxArea = function(a) { - if (Object.prototype.toString.call(a) !== '[object Array]' || a.length < 2) return 0 - let max = 0, l = 0, r = a.length - 1 - while(l < r) { - const minHeight = a[l] < a[r] ? a[l++] : a[r--] + if (!Array.isArray(A || A.length < 2)) return 0 + let max = 0, l = 0, r = A.length - 1 + while (l < r) { + const minHeight = A[l] < A[r] ? A[l++] : A[r--] const area = minHeight * (r - l + 1) max = Math.max(max, area) } From 457dde126b9f461b05acdcecb168451c1ea874c7 Mon Sep 17 00:00:00 2001 From: alwynzhou Date: Tue, 9 Mar 2021 10:08:36 +0800 Subject: [PATCH 097/210] fix grammer err --- Week_01/011maxArea.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Week_01/011maxArea.js b/Week_01/011maxArea.js index 20614bae..917b365a 100644 --- a/Week_01/011maxArea.js +++ b/Week_01/011maxArea.js @@ -31,7 +31,7 @@ console.log(maxArea1([1,2,1])) // 解法二: O(n) 核心:移动短板,area可能会变大;移动长板,area只会不变或变小。因此,双指针,每次移动短板即可。 const maxArea = function(a) { - if (!Array.isArray(A || A.length < 2)) return 0 + if (!Array.isArray(A) || A.length < 2) return 0 let max = 0, l = 0, r = A.length - 1 while (l < r) { const minHeight = A[l] < A[r] ? A[l++] : A[r--] From 738879b2bcc4a708aad362a3084a0c19c7285921 Mon Sep 17 00:00:00 2001 From: alwynzhou Date: Tue, 9 Mar 2021 10:08:51 +0800 Subject: [PATCH 098/210] fix grammer err --- Week_01/011maxArea.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Week_01/011maxArea.js b/Week_01/011maxArea.js index 917b365a..1deb5f12 100644 --- a/Week_01/011maxArea.js +++ b/Week_01/011maxArea.js @@ -30,7 +30,7 @@ console.log(maxArea1([4,3,2,1,4])) console.log(maxArea1([1,2,1])) // 解法二: O(n) 核心:移动短板,area可能会变大;移动长板,area只会不变或变小。因此,双指针,每次移动短板即可。 -const maxArea = function(a) { +const maxArea = function(A) { if (!Array.isArray(A) || A.length < 2) return 0 let max = 0, l = 0, r = A.length - 1 while (l < r) { From 0a04beff26736b2ab4e7b9d770052ca51bc205f3 Mon Sep 17 00:00:00 2001 From: alwynzhou Date: Tue, 9 Mar 2021 10:16:28 +0800 Subject: [PATCH 099/210] solve moveZeors --- Week_01/283moveZeros.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Week_01/283moveZeros.js b/Week_01/283moveZeros.js index 68c32e44..73842dae 100644 --- a/Week_01/283moveZeros.js +++ b/Week_01/283moveZeros.js @@ -3,7 +3,7 @@ * 思路: 用一个标记记录非0的位置 */ -const moveZeroes = function(nums) { +const moveZeroes1 = function(nums) { if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length <= 0) return nums const swap = function(nums, i, j) { @@ -27,17 +27,18 @@ const moveZeroes = function(nums) { * 解法二:nums[pos++] = nums[i] */ const moveZeroes = function(nums) { - if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) { - return - } - - let pos = 0 - for(let i = 0; i < nums.length; ++i) { + if (!Array.isArray(nums) || nums.length < 1) return + let insertPos = 0 + for (let i = 0; i < nums.length; ++i) { if (nums[i] !== 0) { - nums[pos++] = nums[i] + nums[insertPos++] = nums[i] } } - while(pos < nums.length) { - nums[pos++] = 0 + while (insertPos < nums.length) { + nums[insertPos++] = 0 } } +// ---- test case ---- +var nums = [0,1,0,3,12] +moveZeroes(nums) +console.log(nums) From 8557f04e2b74ffe7b9e47cb3887568b4a90284b6 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 9 Mar 2021 23:32:48 +0800 Subject: [PATCH 100/210] solve coinChange with dp --- Week_06/322coinChange.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Week_06/322coinChange.js diff --git a/Week_06/322coinChange.js b/Week_06/322coinChange.js new file mode 100644 index 00000000..64caa5b5 --- /dev/null +++ b/Week_06/322coinChange.js @@ -0,0 +1,36 @@ +/** + * https://leetcode-cn.com/problems/coin-change/ + * 322. 零钱兑换 | medium + * + * f(amount) = min((f(amount - coin) + 1) for coin in coins) + * O(mn) O(n) + * + * 11 -> [1, 2, 5] + * amount 0 1 2 3 4 5 6 7 8 9 10 11 + * 0 1 1 2 2 1 2 2 3 3 2 2 + */ + +const coinChange = function(coins, amount) { + if (!Array.isArray(coins) || coins.length < 1 || amount < 0) return -1 + if (amount === 0) return 0 + const dp = new Array(amount + 1).fill(Infinity) + dp[0] = 0 + + for (let i = 1; i <= amount; ++i) { + for (const coin of coins) { + if (i - coin >= 0 && dp[i - coin] !== Infinity) { + dp[i] = Math.min(dp[i], dp[i - coin] + 1) + } + } + } + // console.log(dp) + return dp[amount] === Infinity ? -1 : dp[amount] +} + +// ---- test case ---- +console.log(coinChange([1,2,5], 11)) +console.log(coinChange([2], 3)) +console.log(coinChange([1], 0)) +console.log(coinChange([1], 1)) +console.log(coinChange([1], 2)) +console.log(coinChange([186,419,83,408], 6249)) From 0f74d68f29d28bd63e4246a73a726d3f9ba18618 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 11 Mar 2021 00:29:06 +0800 Subject: [PATCH 101/210] solve 2 rob problem with dp --- Week_06/198rob.js | 33 +++++++++++++++++++++++++++++++++ Week_06/213rob.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 Week_06/198rob.js create mode 100644 Week_06/213rob.js diff --git a/Week_06/198rob.js b/Week_06/198rob.js new file mode 100644 index 00000000..0fff87fa --- /dev/null +++ b/Week_06/198rob.js @@ -0,0 +1,33 @@ +/** + * https://leetcode-cn.com/problems/house-robber/ + * 198. 打家劫舍 | medium + * + * f(i) = max(f(i-1), f(i-2) + A[i]) + */ + +const rob1 = function(A) { + if (!Array.isArray(A) || A.length < 1) return 0 + if (A.length < 3) return Math.max(...A) + const n = A.length, dp = new Array(n).fill(0) + dp[0] = A[0], dp[1] = Math.max(A[0], A[1]) + for (let i = 2; i < n; ++i) { + dp[i] = Math.max(dp[i - 1], dp[i - 2] + A[i]) + } + return dp[n - 1] +} + +// 优化空间复杂度为 O(1) +const rob = function(A) { + if (!Array.isArray(A) || A.length < 1) return 0 + let pre = 0, now = 0 + for (const a of A) { + ;[pre, now] = [now, Math.max(pre + a, now)] + } + return now +} + +// ---- test case ---- +console.log(rob1([1,2,3,1])) +console.log(rob1([2,7,9,3,1])) +console.log(rob([1,2,3,1])) +console.log(rob([2,7,9,3,1])) diff --git a/Week_06/213rob.js b/Week_06/213rob.js new file mode 100644 index 00000000..fc8289ed --- /dev/null +++ b/Week_06/213rob.js @@ -0,0 +1,34 @@ +/** + * https://leetcode-cn.com/problems/house-robber-ii/ + * 213. 打家劫舍 II | medium + * + * 环形~ + * + * 1. 不偷第一个 + * 2. 偷第一个 -> 不能偷最后一个 + * 3. 取max + */ + +// O(n) +const rob = function(A) { + if (!Array.isArray(A) || A.length < 1) return 0 + if (A.length < 4) return Math.max(...A) + + const myRob = (A) => { + const n = A.length + const dp = new Array(n).fill(0) + dp[0] = A[0] + dp[1] = Math.max(A[0], A[1]) + for (let i = 2; i < n; ++i) { + dp[i] = Math.max(dp[i - 1], dp[i - 2] + A[i]) + } + return dp[n - 1] + } + + return Math.max(myRob(A.slice(0, A.length - 1)), myRob(A.slice(1))) +} + +// ---- test case ---- +console.log(rob([2,3,2])) +console.log(rob([1,2,3,1])) +console.log(rob([0])) From 23beaa110e3d978906c8420f0a99d8b89eb73bc6 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 11 Mar 2021 00:43:23 +0800 Subject: [PATCH 102/210] refactor --- Week_02/589preorder.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Week_02/589preorder.js b/Week_02/589preorder.js index 5b267287..4278b807 100644 --- a/Week_02/589preorder.js +++ b/Week_02/589preorder.js @@ -21,9 +21,9 @@ const preorder1 = function(root) { const preorder = function(root) { if (root == null) return [] const res = [], stack = [root] - while (stack.length) { + while (stack.length > 0) { const p = stack.pop() - if (p.children) + if (p.children.length > 0) for(let i = p.children.length - 1; i >= 0; --i) stack.push(p.children[i]) res.push(p.val) From 1764ba9195b830daa28503aa812e7895ae8f5410 Mon Sep 17 00:00:00 2001 From: alwynzhou Date: Fri, 12 Mar 2021 14:30:14 +0800 Subject: [PATCH 103/210] remove readme content --- README.md | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/README.md b/README.md index 4d40aca4..5ee18f64 100644 --- a/README.md +++ b/README.md @@ -1,24 +1 @@ -# 极客大学「算法训练营-第24期」作业提交仓库 - - - -## 仓库目录结构说明 - -1. `week01/` 代表第一周作业提交目录,以此类推。 -2. 请在对应周的目录下新建或修改自己的代码作业。 -2. 每周均有一个 `README.md` 文档,你可以将自己当周的学习心得以及做题过程中的思考记录在该文档中。 - -## 作业提交规则 - -1. 先将本仓库 Fork 到自己 GitHub 账号下。 -2. 将 Fork 后的仓库 Clone 到本地,然后在本地仓库中对应周的目录下新建或修改自己的代码作业,当周的学习总结写在对应周的README.md文件里。 -3. 在本地仓库完成作业后,push 到自己的 GitHub 远程仓库。 -4. 最后将远程仓库中当周的作业链接,按格式贴到班级仓库对应学习周的issue下面。 -5. 提交issue请务必按照规定格式进行提交,否则作业统计工具将抓取不到你的作业提交记录。 - -详细的作业提交流程可以查阅:https://shimo.im/docs/m5rtM8K8rNsjw5jk/ - - -## 注意事项 - - 如果对 Git 和 GitHub 不太了解,请参考 [Git 官方文档](https://git-scm.com/book/zh/v2) 或者极客时间的[《玩转 Git 三剑客》](https://time.geekbang.org/course/intro/145)视频课程。 +# 算法训练 From 80c4f351da0b5197381df0855b5bb53f2ef8cf6c Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 14 Mar 2021 17:23:21 +0800 Subject: [PATCH 104/210] solve dp --- Week_06/053maxSubArray.js | 1 + Week_06/062uniquePaths.js | 12 +++++++ Week_06/063uniquePathsWithObstacles.js | 34 ++++++++---------- Week_06/085maximRectangle.js | 24 +++++++++++++ Week_06/091numDecodings.js | 32 +++++++++++++++++ Week_06/1143longestCommonSubsequence.js | 18 ++++++---- Week_06/120minimumTotal.js | 29 +++++++++++++++ Week_06/152maxProduct.js | 24 +++++++++++++ Week_06/221maximalSquare.js | 25 +++++++++++++ Week_06/322coinChange.js | 9 +++-- Week_06/363maxSumSubmatrix.js | 44 +++++++++++++++++++++++ Week_06/621leastInterval.js | 14 ++++++++ Week_06/647countSubstrings.js | 15 ++++++++ Week_06/887superEggDrop.js | 19 ++++++++++ Week_06/homework.md | 12 ++++++- Week_08/208trie.js | 47 +++++++++++++++++++++++++ Week_08/212findWords.js | 19 ++++++++++ 17 files changed, 346 insertions(+), 32 deletions(-) create mode 100644 Week_06/085maximRectangle.js create mode 100644 Week_06/091numDecodings.js create mode 100644 Week_06/120minimumTotal.js create mode 100644 Week_06/152maxProduct.js create mode 100644 Week_06/221maximalSquare.js create mode 100644 Week_06/363maxSumSubmatrix.js create mode 100644 Week_06/621leastInterval.js create mode 100644 Week_06/647countSubstrings.js create mode 100644 Week_06/887superEggDrop.js create mode 100644 Week_08/208trie.js create mode 100644 Week_08/212findWords.js diff --git a/Week_06/053maxSubArray.js b/Week_06/053maxSubArray.js index 21596989..c10a2b89 100644 --- a/Week_06/053maxSubArray.js +++ b/Week_06/053maxSubArray.js @@ -8,6 +8,7 @@ */ // dp 空间可以压缩到单个变量 +// O(n) O(1) const maxSubArray = function(A) { if (!Array.isArray(A) || A.length < 1) return let max = dp = A[0] diff --git a/Week_06/062uniquePaths.js b/Week_06/062uniquePaths.js index 6eaacc5b..a991fc51 100644 --- a/Week_06/062uniquePaths.js +++ b/Week_06/062uniquePaths.js @@ -31,6 +31,18 @@ const uniquePaths2 = function(m, n) { return dp[0] } +// 变成正向计算 +// O(mn) O(n) +const uniquePaths = function(m, n) { + const dp = Array(n).fill(1) + for (let i = 1; i < m; ++i) { + for (let j = 1; j < n; ++j) { + dp[j] += dp[j - 1] + } + } + return dp[n - 1] +} + // ---- test case ---- console.time('uniquePaths') console.log(uniquePaths(3,7)) diff --git a/Week_06/063uniquePathsWithObstacles.js b/Week_06/063uniquePathsWithObstacles.js index 77cb0889..cf5f6f0e 100644 --- a/Week_06/063uniquePathsWithObstacles.js +++ b/Week_06/063uniquePathsWithObstacles.js @@ -6,29 +6,25 @@ * */ -// 障碍物处 dp[x] = 0 -const uniquePathsWithObstacles = function(obstacleGrid) { - if (!Array.isArray(obstacleGrid) || - obstacleGrid.length < 1 || - !Array.isArray(obstacleGrid[0]) || - obstacleGrid[0].length < 1) return 0 +// 障碍物处 dp[j] = 0 +const uniquePathsWithObstacles = function(A) { + if (!Array.isArray(A) || A.length < 1 || + !Array.isArray(A[0]) || A[0].length < 1) return 0 - const m = obstacleGrid.length, - n = obstacleGrid[0].length, - dp = new Array(n).fill(-1) - - for(let i = m - 1; i >= 0; --i) { + const m = A.length + const n = A[0].length + const lastObsIdx = A[m - 1].lastIndexOf(1) + const dp = Array(lastObsIdx + 1).fill(0) + .concat(Array(n - lastObsIdx - 1).fill(1)) // 初始化最下行(最后一个障碍物前全是零,后面是1) + + for (let i = m - 2; i >= 0; --i) { for (let j = n - 1; j >= 0; --j) { - if (obstacleGrid[i][j] === 1) { + if (A[i][j] === 1) { // 障碍物 dp[j] = 0 - } else if (i === m - 1 || j === n - 1) { - if (dp[j] === 0 || (j + 1 < n && dp[j + 1] === 0)) { // 障碍节点 - dp[j] = 0 - } else { - dp[j] = 1 - } + } else if (j === n - 1) { // 最右列(如果该列下面有障碍物,则为零) + dp[j] = dp[j] === 0 ? 0 : 1 } else { - dp[j] = dp[j] + dp[j + 1] + dp[j] += dp[j + 1] } } } diff --git a/Week_06/085maximRectangle.js b/Week_06/085maximRectangle.js new file mode 100644 index 00000000..8c18993f --- /dev/null +++ b/Week_06/085maximRectangle.js @@ -0,0 +1,24 @@ +/** + * https://leetcode-cn.com/problems/maximal-rectangle/ + * 85. 最大矩形 | hard + * + */ + +// +const maximalRectangle = function(A) { + +} + +// ---- test case ---- +console.log(maximalRectangle( + [ + ["1","0","1","0","0"], + ["1","0","1","1","1"], + ["1","1","1","1","1"], + ["1","0","0","1","0"] + ] +)) +console.log(maximalRectangle([])) +console.log(maximalRectangle([["0"]])) +console.log(maximalRectangle([["1"]])) +console.log(maximalRectangle([["0","0"]])) diff --git a/Week_06/091numDecodings.js b/Week_06/091numDecodings.js new file mode 100644 index 00000000..a637aba0 --- /dev/null +++ b/Week_06/091numDecodings.js @@ -0,0 +1,32 @@ +/** + * https://leetcode-cn.com/problems/decode-ways/ + * 91. 解码方法 | medium + * + */ + +// O(n) 向前回头看一步 & 回头看两步 +const numDecodings = function(s) { + if (typeof s !== 'string' || !/^\d*$/.test(s)) return 0 + const n = s.length, dp = Array(n + 1).fill(0) + dp[0] = 1 + dp[1] = s[0] === '0' ? 0 : 1 + for (let i = 2; i <= n; ++i) { + const first = Number(s[i - 1]) + const second = Number(s[i - 2] + s[i - 1]) + if (first >= 1 && first <= 9) { + dp[i] += dp[i - 1] + } + if (second >= 10 && second <= 26) { + dp[i] += dp[i - 2] + } + } + return dp[n] +} + +// ---- test case ---- +console.log(numDecodings('12')) +console.log(numDecodings('226')) +console.log(numDecodings('0')) +console.log(numDecodings('06')) +console.log(numDecodings('11111')) +console.log(numDecodings('10011')) diff --git a/Week_06/1143longestCommonSubsequence.js b/Week_06/1143longestCommonSubsequence.js index 726ab3b8..fce2cf05 100644 --- a/Week_06/1143longestCommonSubsequence.js +++ b/Week_06/1143longestCommonSubsequence.js @@ -4,16 +4,20 @@ */ /* - * s1[-1] = s2[-1]: f(i, j) = f(i - 1, j - 1) + 1 - * s1[-1] != s2[-1]: f(i, j) = max(f(i - 1, j), f(i, j - 1)) - * tip: 声明dp数组,空首行和首列,便于迭代。 +情况1: s1[-1] == s2[-1] +-> f(i, j) = f(i - 1, j - 1) + 1 +情况2: s1[-1] != s2[-1] +-> f(i, j) = max(f(i - 1, j), f(i, j - 1)) */ +// !!! 因为要用到dp[i-1][j-1]的值,dp须开二维数组 const longestCommonSubsequence = function(s1, s2) { + if (typeof s1 !== 'string' || typeof s2 !== 'string' || !s1.length || !s2.length) return 0 const m = s1.length, n = s2.length - if (m === 0 || n === 0 || typeof s1 !== 'string' || typeof s2 !== 'string') return 0 - const dp = new Array(m + 1).fill(0).map(_ => new Array(n + 1).fill(0)) - for(let i = 1; i <= m; ++i) { + const dp = Array(m + 1).fill(0).map( + _ => Array(n + 1).fill(0)) + + for (let i = 1; i <= m; ++i) { for (let j = 1; j <= n; ++j) { if (s1[i - 1] === s2[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1 @@ -25,10 +29,10 @@ const longestCommonSubsequence = function(s1, s2) { return dp[m][n] } - // ---- test case ---- console.time('longestCommonSubsequence') console.log(longestCommonSubsequence('abcde', 'ace')) console.log(longestCommonSubsequence('abc', 'abc')) console.log(longestCommonSubsequence('abc', 'def')) +console.log(longestCommonSubsequence("abcba", "abcbcba")) console.timeEnd('longestCommonSubsequence') diff --git a/Week_06/120minimumTotal.js b/Week_06/120minimumTotal.js new file mode 100644 index 00000000..552126e8 --- /dev/null +++ b/Week_06/120minimumTotal.js @@ -0,0 +1,29 @@ +/** + * https://leetcode-cn.com/problems/triangle/ + * 120. 三角形最小路径和 | medium + * f(i, j) = min(f(i+1, j), f(i+1, j+1)) + A[i, j] + */ + +// O(mn) O(n) +const minimumTotal = function(A) { + const m = A.length, n = A[m - 1].length + const dp = A[m - 1].slice() + for (let i = m - 2; i >= 0; --i) { + for (let j = 0; j <= i; ++j) { + dp[j] = A[i][j] + Math.min(dp[j], dp[j + 1]) + } + } + return dp[0] +} + +// ---- test case ---- +console.log(minimumTotal([ + [ 2 ], + [ 3, 4 ], + [ 6, 5, 7 ], + [4, 1, 8, 3] +])) + +console.log(minimumTotal([ + [-10] +])) diff --git a/Week_06/152maxProduct.js b/Week_06/152maxProduct.js new file mode 100644 index 00000000..b44d0973 --- /dev/null +++ b/Week_06/152maxProduct.js @@ -0,0 +1,24 @@ +/** + * https://leetcode-cn.com/problems/maximum-product-subarray/ + * 152. 乘积最大子数组 | medium + * + */ + +// 保持最大值和最小值 +const maxProduct = function(A) { + if (!Array.isArray(A) || A.length < 1) return + const n = A.length + let min = max = res = A[0] + for (let i = 1; i < n; ++i) { + if (A[i] < 0) [min, max] = [max, min] // 交换 + max = Math.max(max * A[i], A[i]) + min = Math.min(min * A[i], A[i]) + res = Math.max(res, max) + } + return res +} + +// ---- test case ---- +console.log(maxProduct([2 , 3, -2, 4])) +console.log(maxProduct([2 , 3, -2, 4, -4])) +console.log(maxProduct([-2, 0, -1])) diff --git a/Week_06/221maximalSquare.js b/Week_06/221maximalSquare.js new file mode 100644 index 00000000..7bd620d4 --- /dev/null +++ b/Week_06/221maximalSquare.js @@ -0,0 +1,25 @@ +/** + * https://leetcode-cn.com/problems/maximal-square/ + * 221. 最大正方形 | medium + * + */ + +const maximalSquare = function(A) { + +} + +// ---- test case ---- +const m1 = [ + ["1","0","1","0","0"], + ["1","0","1","1","1"], + ["1","1","1","1","1"], + ["1","0","0","1","0"] +] +console.log(maximalSquare(m1)) +const m2 = [ + ["0","1"], + ["1","0"] +] +console.log(maximalSquare(m2)) +const m3 = [["0"]] +console.log(maximalSquare(m3)) diff --git a/Week_06/322coinChange.js b/Week_06/322coinChange.js index 64caa5b5..ab4ffc5e 100644 --- a/Week_06/322coinChange.js +++ b/Week_06/322coinChange.js @@ -13,18 +13,17 @@ const coinChange = function(coins, amount) { if (!Array.isArray(coins) || coins.length < 1 || amount < 0) return -1 if (amount === 0) return 0 - const dp = new Array(amount + 1).fill(Infinity) + const UPBOUND = amount + 1 + const dp = Array(amount + 1).fill(UPBOUND) dp[0] = 0 - for (let i = 1; i <= amount; ++i) { for (const coin of coins) { - if (i - coin >= 0 && dp[i - coin] !== Infinity) { + if (i - coin >= 0) { dp[i] = Math.min(dp[i], dp[i - coin] + 1) } } } - // console.log(dp) - return dp[amount] === Infinity ? -1 : dp[amount] + return dp[amount] === UPBOUND ? -1 : dp[amount] } // ---- test case ---- diff --git a/Week_06/363maxSumSubmatrix.js b/Week_06/363maxSumSubmatrix.js new file mode 100644 index 00000000..b6c64ee2 --- /dev/null +++ b/Week_06/363maxSumSubmatrix.js @@ -0,0 +1,44 @@ +/** + * https://leetcode-cn.com/problems/max-sum-of-rectangle-no-larger-than-k/ + * 363. 矩形区域不超过 K 的最大数值和 | hard + * + */ + +const maxSumSubmatrix = function (matrix, k) { + const row = matrix.length, + col = matrix[0].length; + let result = -Infinity; + for (let i = 0; i < col; i++) { + let rowSum = Array(row).fill(0); + for (let j = i; j < col; j++) { + let sum = 0, + max = -Infinity; + for (let r = 0; r < row; r++) { + rowSum[r] += matrix[r][j]; + if (sum < 0) sum = 0; + sum += rowSum[r]; + max = Math.max(max, sum) + } + if (max <= k) result = Math.max(result, max) + else { + max = -Infinity; + for (let m = 0; m < row; m++) { + sum = 0; + for (let n = m; n < row; n++) { + sum += rowSum[n]; + if (sum <= k) max = Math.max(max, sum) + } + } + result = Math.max(result, max) + } + if (result === k) return k; + } + } + return result; +} + +// ---- test case ---- +console.log([ + [1, 0, 1], + [0, -2, 3] +], 2) diff --git a/Week_06/621leastInterval.js b/Week_06/621leastInterval.js new file mode 100644 index 00000000..28896f3c --- /dev/null +++ b/Week_06/621leastInterval.js @@ -0,0 +1,14 @@ +/** + * https://leetcode-cn.com/problems/task-scheduler/ + * 621. 任务调度器 | medium + * + */ + +const leastInterval = function(tasks, n) { + +} + +// ---- test case ---- +console.log(leastInterval(["A","A","A","B","B","B"], 2)) +console.log(leastInterval(["A","A","A","B","B","B"], 0)) +console.log(leastInterval(["A","A","A","A","A","A","B","C","D","E","F","G"], 2)) diff --git a/Week_06/647countSubstrings.js b/Week_06/647countSubstrings.js new file mode 100644 index 00000000..4d47e21f --- /dev/null +++ b/Week_06/647countSubstrings.js @@ -0,0 +1,15 @@ +/** + * https://leetcode-cn.com/problems/palindromic-substrings/ + * 647. 回文子串 | medium + * + */ + +const countSubstrings = function(s) { + +} + +// ---- test case ---- +console.log(countSubstrings('12')) +console.log(countSubstrings('226')) +console.log(countSubstrings('0')) +console.log(countSubstrings('06')) diff --git a/Week_06/887superEggDrop.js b/Week_06/887superEggDrop.js new file mode 100644 index 00000000..9ba23b58 --- /dev/null +++ b/Week_06/887superEggDrop.js @@ -0,0 +1,19 @@ +/** + * https://leetcode-cn.com/problems/super-egg-drop/ + * 887. 鸡蛋掉落 | hard + * + * M(k, n) = max(M(k - 1, part), M(k, n - part)) + 1 + * for part in range(1...n) + * + * TODO x + */ + +const superEggDrop = function(k, n) { + +} + +// ---- test case ---- +console.log(superEggDrop(1, 2)) +console.log(superEggDrop(2, 6)) +console.log(superEggDrop(3, 14)) + diff --git a/Week_06/homework.md b/Week_06/homework.md index e277293a..18cf5d39 100644 --- a/Week_06/homework.md +++ b/Week_06/homework.md @@ -7,15 +7,23 @@ ## 2. 解码方法(亚马逊、Facebook、字节跳动在半年内面试中考过) ++ dp ++ [实现代码](./091numDecodings.js) ## 3. 最大正方形(华为、谷歌、字节跳动在半年内面试中考过) ++ dp ++ [实现代码](./221maximalSquare.js) ## 4. 任务调度器(Facebook 在半年内面试中常考) ++ dp ++ [实现代码](./621leastInterval.js) ## 5. 回文子串(Facebook、苹果、字节跳动在半年内面试中考过) ++ dp ++ [实现代码](./647countSubstrings.js) ## 6. 最长有效括号(字节跳动、亚马逊、微软在半年内面试中考过) @@ -23,8 +31,10 @@ ## 7. 编辑距离(字节跳动、亚马逊、谷歌在半年内面试中考过) -## 8. 矩形区域不超过 K 的最大数值和(谷歌在半年内面试中考过) +## TODO 8. 矩形区域不超过 K 的最大数值和(谷歌在半年内面试中考过) ++ binarySearch + dp ++ [实现代码](./363maxSumSubmatrix.js) ## 9. 青蛙过河(亚马逊、苹果、字节跳动在半年内面试中考过) diff --git a/Week_08/208trie.js b/Week_08/208trie.js new file mode 100644 index 00000000..f2ab33a3 --- /dev/null +++ b/Week_08/208trie.js @@ -0,0 +1,47 @@ +/** + * https://leetcode-cn.com/problems/implement-trie-prefix-tree/ + * 208. 实现 Trie (前缀树) | medium + * + */ + +/** + * Initialize your data structure here. + */ +var Trie = function() { + +}; + +/** + * Inserts a word into the trie. + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function(word) { + +}; + +/** + * Returns if the word is in the trie. + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function(word) { + +}; + +/** + * Returns if there is any word in the trie that starts with the given prefix. + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function(prefix) { + +}; + +/** + * Your Trie object will be instantiated and called as such: + * var obj = new Trie() + * obj.insert(word) + * var param_2 = obj.search(word) + * var param_3 = obj.startsWith(prefix) + */ diff --git a/Week_08/212findWords.js b/Week_08/212findWords.js new file mode 100644 index 00000000..ae6f19d7 --- /dev/null +++ b/Week_08/212findWords.js @@ -0,0 +1,19 @@ +/** + * https://leetcode-cn.com/problems/word-search-ii/ + * 212. 单词搜索 II | hard + * + * trie树 + */ + +const findWords = function(board, words) { + +} + +// ---- test words ---- +console.log(findWords([ + ["o","a","a","n"], + ["e","t","a","e"], + ["i","h","k","r"], + ["i","f","l","v"]], + ["oath","pea","eat","rain"] +)) From 7beb73c8c98a4d5a1a8c79da40a591728f731df7 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 14 Mar 2021 17:45:04 +0800 Subject: [PATCH 105/210] solve minPathSum whih dp --- Week_06/064minPathSum.js | 65 ++++++++++------------------------------ 1 file changed, 16 insertions(+), 49 deletions(-) diff --git a/Week_06/064minPathSum.js b/Week_06/064minPathSum.js index 157380ac..32cdd9eb 100644 --- a/Week_06/064minPathSum.js +++ b/Week_06/064minPathSum.js @@ -4,60 +4,27 @@ * F(i, j) = A(i, j) + min(F(i-1, j) + F(i, j-1)) */ -// 无副作用 O(mn) O(n) -const minPathSum1 = function(A) { - if (!Array.isArray(A) || - A.length < 1 || - !Array.isArray(A[0]) || - A[0].length < 1) return -1 +// O(mn) O(n) +const minPathSum = function(A) { + if (!Array.isArray(A) || A.length < 1 || + !Array.isArray(A[0]) || A[0].length < 1) return 0 const m = A.length, n = A[0].length - const dp = new Array(n).fill(0) - for (let i = 0; i < m; ++i) { - for (let j = 0; j < n; ++j) { - if (i === 0 && j === 0) { - dp[j] = A[i][j] - } else if (i === 0) { - dp[j] = dp[j - 1] + A[i][j] - } else if (j === 0) { - dp[j] += A[i][j] - } else { - dp[j] = Math.min(dp[j], dp[j - 1]) + A[i][j] - } + const dp = A[0].slice() + for (let j = 1; j < n; ++j) { + dp[j] += dp[j - 1] // 首行(从左到右累加) + } + for (let i = 1; i < m; ++i) { + dp[0] += A[i][0] // 最左列 + for (let j = 1; j < n; ++j) { + dp[j] = A[i][j] + Math.min(dp[j], dp[j - 1]) } } return dp[n - 1] } -// 有副作用, 会修改入参矩阵 -const minPathSum2 = function (A) { - if (!Array.isArray(A) || - A.length < 1 || - !Array.isArray(A[0]) || - A[0].length < 1) return -1 - - const m = A.length, n = A[0].length - for(let i = 0; i < m; ++i) { - for (let j = 0; j < n; ++j) { - if (i === 0 && j === 0) { - continue - } else if (i === 0) { - A[i][j] += A[i][j - 1] - } else if (j === 0) { - A[i][j] += A[i - 1][j] - } else { - A[i][j] += Math.min(A[i - 1][j], A[i][j - 1]) - } - } - } - return A[m - 1][n - 1] -} // ---- test case ---- -console.time('minPathSum1') -console.log(minPathSum1([[1,3,1],[1,5,1],[4,2,1]])) -console.log(minPathSum1([[1,2,3],[4,5,6]])) -console.timeEnd('minPathSum1') -console.time('minPathSum2') -console.log(minPathSum2([[1,3,1],[1,5,1],[4,2,1]])) -console.log(minPathSum2([[1,2,3],[4,5,6]])) -console.timeEnd('minPathSum2') +console.time('minPathSum') +console.log(minPathSum([[1,3,1],[1,5,1],[4,2,1]])) +console.log(minPathSum([[1,2,3],[4,5,6]])) +console.timeEnd('minPathSum') From cedd7d73619ec28a47e9f9c1f1a92cefec411d00 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 14 Mar 2021 17:46:17 +0800 Subject: [PATCH 106/210] add some description --- Week_06/064minPathSum.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Week_06/064minPathSum.js b/Week_06/064minPathSum.js index 32cdd9eb..f932a069 100644 --- a/Week_06/064minPathSum.js +++ b/Week_06/064minPathSum.js @@ -1,7 +1,8 @@ /** - * @param {number[][]} grid - * @return {number} - * F(i, j) = A(i, j) + min(F(i-1, j) + F(i, j-1)) + * https://leetcode-cn.com/problems/minimum-path-sum/ + * 64. 最小路径和 | medium + * + * f(i, j) = A[i][j] + min(f(i-1, j) + f(i, j-1)) */ // O(mn) O(n) From b9aeda56a52161122ebd9a37b7a22200ed393e8b Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 14 Mar 2021 18:11:59 +0800 Subject: [PATCH 107/210] solve 647 countSubstrings --- Week_06/647countSubstrings.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Week_06/647countSubstrings.js b/Week_06/647countSubstrings.js index 4d47e21f..91d326e4 100644 --- a/Week_06/647countSubstrings.js +++ b/Week_06/647countSubstrings.js @@ -5,11 +5,22 @@ */ const countSubstrings = function(s) { + if (!s.length) return 0 + let cnt = 0, n = s.length + const help = (l, r) => { + while (l >= 0 && r < n && s[l--] === s[r++]) { + ++cnt + } + } + + for (let i = 0; i < n; ++i) { + help(i, i) + help(i, i + 1) + } + return cnt } // ---- test case ---- -console.log(countSubstrings('12')) -console.log(countSubstrings('226')) -console.log(countSubstrings('0')) -console.log(countSubstrings('06')) +console.log(countSubstrings('abc')) +console.log(countSubstrings('aaa')) From 26062ef7a1447674fa1ab402e8a744b81e52a670 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 14 Mar 2021 23:01:57 +0800 Subject: [PATCH 108/210] solve 208 construct trie tree --- Week_08/208trie.js | 84 ++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/Week_08/208trie.js b/Week_08/208trie.js index f2ab33a3..f00177ed 100644 --- a/Week_08/208trie.js +++ b/Week_08/208trie.js @@ -4,44 +4,46 @@ * */ -/** - * Initialize your data structure here. - */ -var Trie = function() { - -}; - -/** - * Inserts a word into the trie. - * @param {string} word - * @return {void} - */ -Trie.prototype.insert = function(word) { - -}; - -/** - * Returns if the word is in the trie. - * @param {string} word - * @return {boolean} - */ -Trie.prototype.search = function(word) { - -}; - -/** - * Returns if there is any word in the trie that starts with the given prefix. - * @param {string} prefix - * @return {boolean} - */ -Trie.prototype.startsWith = function(prefix) { - -}; - -/** - * Your Trie object will be instantiated and called as such: - * var obj = new Trie() - * obj.insert(word) - * var param_2 = obj.search(word) - * var param_3 = obj.startsWith(prefix) - */ +class Trie { + constructor() { + this.root = {} + } + + insert(word) { + let node = this.root + for (const ch of word) { + if (node[ch] == null) node[ch] = {} + node = node[ch] + } + node.isWord = true + } + + search (word) { + let node = this.root + for (const ch of word) { + node = node[ch] + if (node == null) return false + } + return node.isWord != void(0) + } + + startsWith (prefix) { + let node = this.root + for (const ch of prefix) { + node = node[ch] + if (node == null) return false + } + return !!node + } +} + +// ---- test case ---- +var trie = new Trie() +trie.insert("apple") +console.log(trie.search("bbb")) +console.log(trie.search("apple")) // 返回 true +console.log(trie.search("app")) // 返回 false +console.log(trie.startsWith("app")) // 返回 true +console.log(trie.startsWith("apbbb")) // 返回 false +trie.insert("app") +console.log(trie.search("app")) // 返回 true From aa7917ad6c38e33cc95328e8ab48306301ddfa95 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 14 Mar 2021 23:55:44 +0800 Subject: [PATCH 109/210] use trie tree solve 212 findWords --- Week_08/208trie.js | 17 +++++----- Week_08/212findWords.js | 74 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/Week_08/208trie.js b/Week_08/208trie.js index f00177ed..11af5c33 100644 --- a/Week_08/208trie.js +++ b/Week_08/208trie.js @@ -18,21 +18,22 @@ class Trie { node.isWord = true } - search (word) { + _traverse (word) { let node = this.root for (const ch of word) { node = node[ch] - if (node == null) return false + if (node == null) return null } - return node.isWord != void(0) + return node + } + + search (word) { + const node = this._traverse(word) + return node != null && node.isWord === true } startsWith (prefix) { - let node = this.root - for (const ch of prefix) { - node = node[ch] - if (node == null) return false - } + const node = this._traverse(prefix) return !!node } } diff --git a/Week_08/212findWords.js b/Week_08/212findWords.js index ae6f19d7..a2002d90 100644 --- a/Week_08/212findWords.js +++ b/Week_08/212findWords.js @@ -5,8 +5,80 @@ * trie树 */ -const findWords = function(board, words) { +class Trie { + constructor() { + this.root = {} + } + insert(word) { + let node = this.root + for (const ch of word) { + if (node[ch] == null) node[ch] = {} + node = node[ch] + } + node.isWord = true + } + + _traverse (word) { + let node = this.root + for (const ch of word) { + node = node[ch] + if (node == null) return null + } + return node + } + + search (word) { + const node = this._traverse(word) + return node != null && node.isWord === true + } + + startsWith (prefix) { + const node = this._traverse(prefix) + return !!node + } +} + +const findWords = function(A, words) { + if (!Array.isArray(words) || words.length < 1 || + !Array.isArray(A) || A.length < 1 || + !Array.isArray(A[0]) || A[0].length < 1) return [] + // 1. 构建 trie 树 + const trie = new Trie() + for (const word of words) { + trie.insert(word) + } + + const dfs = (i, j, prefix, trie) => { + prefix += A[i][j] + if (trie.search(prefix)) res.add(prefix) + const tmp = A[i][j] + A[i][j] = TAG // 标记已访问过的节点 + for (let direct = 0; direct <= 3; ++direct) { + const x = i + dx[direct] + const y = j + dy[direct] + if (x >= 0 && x < m && + y >= 0 && y < n && + A[x][y] != TAG && + trie.startsWith(prefix)) { + dfs(x, y, prefix, trie) + } + } + A[i][j] = tmp // 去除标记 + } + // 2. 启动DFS + const res = new Set(), m = A.length, n = A[0].length + const TAG = '@' + const dx = [1, 0, -1, 0] + const dy = [0, 1, 0, -1] + for (let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + if (trie.startsWith(A[i][j])) { + dfs(i, j, '', trie) + } + } + } + return [...res] } // ---- test words ---- From 8f7736e9a930ec1f7333dd914bd18dfff0335510 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 15 Mar 2021 00:07:49 +0800 Subject: [PATCH 110/210] refactor: transfer trieNode --- Week_08/212findWords.js | 79 ++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/Week_08/212findWords.js b/Week_08/212findWords.js index a2002d90..207e7672 100644 --- a/Week_08/212findWords.js +++ b/Week_08/212findWords.js @@ -5,40 +5,6 @@ * trie树 */ -class Trie { - constructor() { - this.root = {} - } - - insert(word) { - let node = this.root - for (const ch of word) { - if (node[ch] == null) node[ch] = {} - node = node[ch] - } - node.isWord = true - } - - _traverse (word) { - let node = this.root - for (const ch of word) { - node = node[ch] - if (node == null) return null - } - return node - } - - search (word) { - const node = this._traverse(word) - return node != null && node.isWord === true - } - - startsWith (prefix) { - const node = this._traverse(prefix) - return !!node - } -} - const findWords = function(A, words) { if (!Array.isArray(words) || words.length < 1 || !Array.isArray(A) || A.length < 1 || @@ -48,10 +14,10 @@ const findWords = function(A, words) { for (const word of words) { trie.insert(word) } - - const dfs = (i, j, prefix, trie) => { + const dfs = (i, j, prefix, trieNode) => { prefix += A[i][j] - if (trie.search(prefix)) res.add(prefix) + trieNode = trieNode[A[i][j]] + if (trieNode && trieNode.isWord) res.add(prefix) const tmp = A[i][j] A[i][j] = TAG // 标记已访问过的节点 for (let direct = 0; direct <= 3; ++direct) { @@ -60,8 +26,8 @@ const findWords = function(A, words) { if (x >= 0 && x < m && y >= 0 && y < n && A[x][y] != TAG && - trie.startsWith(prefix)) { - dfs(x, y, prefix, trie) + trieNode[A[x][y]]) { + dfs(x, y, prefix, trieNode) } } A[i][j] = tmp // 去除标记 @@ -74,12 +40,45 @@ const findWords = function(A, words) { for (let i = 0; i < m; ++i) { for (let j = 0; j < n; ++j) { if (trie.startsWith(A[i][j])) { - dfs(i, j, '', trie) + dfs(i, j, '', trie.root) } } } return [...res] } +class Trie { + constructor() { + this.root = {} + } + + insert(word) { + let node = this.root + for (const ch of word) { + if (node[ch] == null) node[ch] = {} + node = node[ch] + } + node.isWord = true + } + + _traverse (word) { + let node = this.root + for (const ch of word) { + node = node[ch] + if (node == null) return null + } + return node + } + + search (word) { + const node = this._traverse(word) + return node != null && node.isWord === true + } + + startsWith (prefix) { + const node = this._traverse(prefix) + return !!node + } +} // ---- test words ---- console.log(findWords([ From 2fe346be61cf92f8cf3486d1065548c4d60cd70d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 15 Mar 2021 01:06:33 +0800 Subject: [PATCH 111/210] solve 2 dp problem --- Week_06/221maximalSquare.js | 17 +++++++++++++++++ Week_06/621leastInterval.js | 28 ++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/Week_06/221maximalSquare.js b/Week_06/221maximalSquare.js index 7bd620d4..d3226592 100644 --- a/Week_06/221maximalSquare.js +++ b/Week_06/221maximalSquare.js @@ -2,10 +2,27 @@ * https://leetcode-cn.com/problems/maximal-square/ * 221. 最大正方形 | medium * + * f(i, j) 表示当前节点可往左上角扩散的正方形边长 + * f(i, j) = min{ f(i-1, j - 1), f(i, j -1), f(i - 1, j)} + 1 */ const maximalSquare = function(A) { + if (!Array.isArray(A) || A.length < 1 || + !Array.isArray(A[0]) || A[0].length < 1) return 0 + const m = A.length, n = A[0].length + const dp = Array(m + 1).fill(0) + .map(_ => Array(n + 1).fill(0)) + let max = 0 + for (let i = 1; i <= m; ++i) { + for (let j = 1; j <= n; ++j) { + if (A[i - 1][j - 1] != 0) { + dp[i][j] = Math.min(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]) + 1 + max = Math.max(dp[i][j], max) + } + } + } + return max * max } // ---- test case ---- diff --git a/Week_06/621leastInterval.js b/Week_06/621leastInterval.js index 28896f3c..9e62e437 100644 --- a/Week_06/621leastInterval.js +++ b/Week_06/621leastInterval.js @@ -4,11 +4,31 @@ * */ +// 后面的计算方法有点烧脑。。。 const leastInterval = function(tasks, n) { - + const startCodePoint = 'A'.codePointAt(0) + let counter = Array(26).fill(0) + let maxCnt = max = 0 + for (const task of tasks) { + const idx = task.codePointAt(0) - startCodePoint + counter[idx]++ + if (counter[idx] == max) maxCnt++ + else if (counter[idx] > max) { + max = counter[idx] + maxCnt = 1 + } + } + const emptySlots = (max - 1) * (n - (maxCnt - 1)) + const availTasks = tasks.length - max * maxCnt + const idles = Math.max(0, emptySlots - availTasks) + return tasks.length + idles; } // ---- test case ---- -console.log(leastInterval(["A","A","A","B","B","B"], 2)) -console.log(leastInterval(["A","A","A","B","B","B"], 0)) -console.log(leastInterval(["A","A","A","A","A","A","B","C","D","E","F","G"], 2)) +console.log(leastInterval( + ["A","A","A","B","B","B"], 2)) // A B x A B x A B x +console.log(leastInterval( + ["A","A","A","B","B","B"], 0)) +console.log(leastInterval( + ["A","A","A","A","A","A","B","C","D","E","F","G"], 2)) +// A B From 9d7f7b1a6b86a258ab87fc71c535aae6733b24a1 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 15 Mar 2021 01:21:29 +0800 Subject: [PATCH 112/210] touch files --- Week_06/032longestValidParentheses.js | 4 ++++ Week_06/072minDistance.js | 4 ++++ Week_06/076minWindow.js | 4 ++++ Week_06/312maxCoins.js | 4 ++++ Week_06/403canCross.js | 4 ++++ Week_06/410splitArray.js | 4 ++++ Week_06/552checkRecord.js | 4 ++++ Week_06/homework.md | 29 ++++++++++++++++++++------- 8 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 Week_06/032longestValidParentheses.js create mode 100644 Week_06/072minDistance.js create mode 100644 Week_06/076minWindow.js create mode 100644 Week_06/312maxCoins.js create mode 100644 Week_06/403canCross.js create mode 100644 Week_06/410splitArray.js create mode 100644 Week_06/552checkRecord.js diff --git a/Week_06/032longestValidParentheses.js b/Week_06/032longestValidParentheses.js new file mode 100644 index 00000000..4048371d --- /dev/null +++ b/Week_06/032longestValidParentheses.js @@ -0,0 +1,4 @@ +/** + * https://leetcode-cn.com/problems/longest-valid-parentheses/ + * 32. 最长有效括号 | hard + */ diff --git a/Week_06/072minDistance.js b/Week_06/072minDistance.js new file mode 100644 index 00000000..3dc03178 --- /dev/null +++ b/Week_06/072minDistance.js @@ -0,0 +1,4 @@ +/** + * https://leetcode-cn.com/problems/edit-distance/ + * 72. 编辑距离 | hard + */ diff --git a/Week_06/076minWindow.js b/Week_06/076minWindow.js new file mode 100644 index 00000000..afc8ce60 --- /dev/null +++ b/Week_06/076minWindow.js @@ -0,0 +1,4 @@ +/** + * https://leetcode-cn.com/problems/minimum-window-substring/ + * 76. 最小覆盖子串 + */ diff --git a/Week_06/312maxCoins.js b/Week_06/312maxCoins.js new file mode 100644 index 00000000..adfc94d8 --- /dev/null +++ b/Week_06/312maxCoins.js @@ -0,0 +1,4 @@ +/** + * https://leetcode-cn.com/problems/burst-balloons/ + * 312. 戳气球 | hard + */ diff --git a/Week_06/403canCross.js b/Week_06/403canCross.js new file mode 100644 index 00000000..b26c8e35 --- /dev/null +++ b/Week_06/403canCross.js @@ -0,0 +1,4 @@ +/** + * https://leetcode-cn.com/problems/frog-jump/ + * 403. 青蛙过河 | hard + */ diff --git a/Week_06/410splitArray.js b/Week_06/410splitArray.js new file mode 100644 index 00000000..6f4e04e0 --- /dev/null +++ b/Week_06/410splitArray.js @@ -0,0 +1,4 @@ +/** + * https://leetcode-cn.com/problems/split-array-largest-sum/ + * 410. 分割数组的最大值 | hard + */ diff --git a/Week_06/552checkRecord.js b/Week_06/552checkRecord.js new file mode 100644 index 00000000..23ffe595 --- /dev/null +++ b/Week_06/552checkRecord.js @@ -0,0 +1,4 @@ +/** + * https://leetcode-cn.com/problems/student-attendance-record-ii/ + * 552. 学生出勤记录 II | hard + */ diff --git a/Week_06/homework.md b/Week_06/homework.md index 18cf5d39..282942c6 100644 --- a/Week_06/homework.md +++ b/Week_06/homework.md @@ -25,27 +25,42 @@ + dp + [实现代码](./647countSubstrings.js) -## 6. 最长有效括号(字节跳动、亚马逊、微软在半年内面试中考过) +## TODO 6. 最长有效括号(字节跳动、亚马逊、微软在半年内面试中考过) ++ dp ++ [实现代码](./032longestValidParentheses.js) -## 7. 编辑距离(字节跳动、亚马逊、谷歌在半年内面试中考过) +## TODO 7. 编辑距离(字节跳动、亚马逊、谷歌在半年内面试中考过) ++ dp ++ [实现代码](./072minDistance.js) ## TODO 8. 矩形区域不超过 K 的最大数值和(谷歌在半年内面试中考过) + binarySearch + dp + [实现代码](./363maxSumSubmatrix.js) -## 9. 青蛙过河(亚马逊、苹果、字节跳动在半年内面试中考过) +## TODO 9. 青蛙过河(亚马逊、苹果、字节跳动在半年内面试中考过) + ++ dp ++ [实现代码](./403canCross.js) +## TODO 10. 分割数组的最大值(谷歌、亚马逊、Facebook 在半年内面试中考过) -## 10. 分割数组的最大值(谷歌、亚马逊、Facebook 在半年内面试中考过) ++ dp ++ [实现代码](./410splitArray.js) +## TODO 11. 学生出勤记录 II (谷歌在半年内面试中考过) -## 11. 学生出勤记录 II (谷歌在半年内面试中考过) ++ dp ++ [实现代码](./552checkRecord.js) +## TODO 12. 最小覆盖子串(Facebook 在半年内面试中常考) -## 12. 最小覆盖子串(Facebook 在半年内面试中常考) ++ dp ++ [实现代码](./076minWindow.js) +## TODO 13. 戳气球(亚马逊在半年内面试中考过) -## 13. 戳气球(亚马逊在半年内面试中考过) ++ dp ++ [实现代码](./312maxCoins.js) From 8d50057b8d2da44c7d4d42a0303852006580b46d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Mar 2021 16:47:13 +0800 Subject: [PATCH 113/210] A* --- Week_04/200numIslands.js | 34 ++++++----- Week_07/1091shortestPathBinaryMatrix.js | 53 +++++++++++++++++ Week_07/README.md | 77 +++++++++++++++++++++++++ Week_07/homework.md | 48 +++++++++++---- 4 files changed, 185 insertions(+), 27 deletions(-) create mode 100644 Week_07/1091shortestPathBinaryMatrix.js diff --git a/Week_04/200numIslands.js b/Week_04/200numIslands.js index 72e381c0..472fb908 100644 --- a/Week_04/200numIslands.js +++ b/Week_04/200numIslands.js @@ -4,26 +4,30 @@ * medium */ -const numIslands = function(grid) { - // 传染给其他的元素,标记为零 - const dfsMarking = function(i, j) { - if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] !== '1') return - grid[i][j] = '0' - dfsMarking(i + 1, j) - dfsMarking(i - 1, j) - dfsMarking(i, j + 1) - dfsMarking(i, j - 1) - } +// dfs +const numIslands = function(A) { + if (!Array.isArray(A) || A.length < 1 || + !Array.isArray(A[0] || A[0].length < 1)) return 0 - let cnt = 0, - m = grid.length, - n = grid[0].length + const dfsMarking = (i, j) => { + if (i >= 0 && i < m && + j >= 0 && j < n && + A[i][j] === '1') { + A[i][j] = '0' + dfsMarking(i + 1, j) + dfsMarking(i - 1, j) + dfsMarking(i, j + 1) + dfsMarking(i, j - 1) + } + } + const m = A.length, n = A[0].length + let cnt = 0 for (let i = 0; i < m; ++i) { for (let j = 0; j < n; ++j) { - if (grid[i][j] === '1') { - dfsMarking(i, j) + if (A[i][j] === '1') { ++cnt + dfsMarking(i, j) } } } diff --git a/Week_07/1091shortestPathBinaryMatrix.js b/Week_07/1091shortestPathBinaryMatrix.js new file mode 100644 index 00000000..9139f36a --- /dev/null +++ b/Week_07/1091shortestPathBinaryMatrix.js @@ -0,0 +1,53 @@ +/** + * https://leetcode-cn.com/problems/shortest-path-in-binary-matrix/ + * 1091. 二进制矩阵中的最短路径 + * + * + */ + +// BFS, 有副作用 +const shortestPathBinaryMatrix = function(A) { + const n = A.length + if (A[0][0] === 1 || A[n - 1][n - 1] === 1) { + return -1 + } else if (n <= 2) { + return n + } + const dx = [0, 0, 1, -1, 1, -1, 1, -1] + const dy = [1, -1, 0, 0, 1, 1, -1, -1] + const queue = [[0, 0, 2]] + for (let idx = 0; idx < queue.length; ++idx) { + const [i, j, level] = queue[idx] + for (let dir = 0; dir < 8; ++dir) { + const x = i + dx[dir] + const y = j + dy[dir] + if (x >= 0 && x < n && + y >= 0 && y < n && + A[x][y] === 0) { + if (x === n - 1 && y === n - 1) return level + queue.push([x, y, level + 1]) + A[x][y] = 1 + } + } + } + return -1 +} + +// ---- test case ---- +const grid1 = [ + [0, 1], + [1, 0], +] +const grid2 = [ + [0, 0, 0], + [1, 1, 0], + [1, 1, 0], +] +const grid3 = [ + [1, 0, 0], + [1, 1, 0], + [1, 1, 0], +] +console.log(shortestPathBinaryMatrix(grid1)) // 2 +console.log(shortestPathBinaryMatrix(grid2)) // 4 +console.log(shortestPathBinaryMatrix(grid3)) // -1 diff --git a/Week_07/README.md b/Week_07/README.md index 474d30d1..10aa7062 100644 --- a/Week_07/README.md +++ b/Week_07/README.md @@ -1,3 +1,80 @@ # 学习笔记 +```js +// BFS 手动维护队列 +const bfs = (root) => { + const result = [], queue = [root] + while (queue.length > 0) [ + const line = [], n = queue.length + for (let i = 0; i < n; ++i) { + const node = queue.pop() + line.push(node.val) + if (node.left) queue.unshift(node.left) + if (node.right) queue.unshift(node.right) + } + result.push(line) + ] + return result +} +// DFS 手动维护栈 +const dfs = (root) => { + const result = [], stack = [root] + while (stack.length > 0) { + const node = stack.pop() + res.push(node.val) + if (node.right) stack.push(node.right) + if (node.left) stack.push(node.left) + } + return res +} +``` + ## 第13课:高级搜索 + +### 初级搜索 + +1. 朴素搜索 +2. 优化方式:不重复(figonacci),剪枝(生成括号问题) +3. 搜索方向:DFS、BFS、双向搜索、启发式搜索 + +### 剪枝 + +### 双向BFS + +### 启发式搜索 A* + +```python +def BFS(graph, start, end): + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) +``` + +```python +def AstarSearch(graph, start, end): + pq = collections.priority_queue() # 优先级 -> 估价函数 + pq.append([start]) + visited.add(start) + while pq: + node = pq.pop() + visited.add(node) + process(node) + nodes = generate_related_nodes(node) + unvisited = [node for node in nodes if node not in visited] + pq.push(unvisited) +``` + +**估价函数** + +启发式函数:h(n),它用来评价哪些节点最有希望的是一个我们要找的节点,h(n)会返回一个非负实数,也可以认为是从节点n的目标节点路径的估计成本。 + +启发式函数是一种告知搜索节点方向的方法。它提供了一种明智的方法来猜测哪个邻居节点会导向一个目标。 + + diff --git a/Week_07/homework.md b/Week_07/homework.md index 9153de08..43fd4f37 100644 --- a/Week_07/homework.md +++ b/Week_07/homework.md @@ -1,14 +1,38 @@ # 作业 -简单 -爬楼梯(阿里巴巴、腾讯、字节跳动在半年内面试常考) - -中等 -括号生成(亚马逊、Facebook、字节跳动在半年内面试中考过) -有效的数独(亚马逊、苹果、微软在半年内面试中考过) -单词接龙(亚马逊、Facebook、谷歌在半年内面试中考过) -最小基因变化(谷歌、Twitter、腾讯在半年内面试中考过) - -困难 -N 皇后(亚马逊、苹果、字节跳动在半年内面试中考过) -解数独(亚马逊、华为、微软在半年内面试中考过) +## 一、剪枝 + +### 爬楼梯(阿里巴巴、腾讯、字节跳动在半年内面试常考) + + +### 括号生成(亚马逊、Facebook、字节跳动在半年内面试中考过) + + +### 有效的数独(亚马逊、苹果、微软在半年内面试中考过) + + +### N 皇后(亚马逊、苹果、字节跳动在半年内面试中考过) + + +### 解数独(亚马逊、华为、微软在半年内面试中考过) + + +## 二、双向BFS + +### 单词接龙(亚马逊、Facebook、谷歌在半年内面试中考过) + + +### 最小基因变化(谷歌、Twitter、腾讯在半年内面试中考过) + + +## 三、启发式搜索 +### 1091. 二进制矩阵中的最短路径 + +解法一:DP +解法二:BFS +解法三:A* + +[代码](./1091shortestPathBinaryMatrix.js) + +### 773. 滑动谜题 + From 870ea86f6b97fb4126d0f0a248c0919de1d2bce1 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 20 Mar 2021 17:25:10 +0800 Subject: [PATCH 114/210] Heuristic algorithm --- Week_07/1091shortestPathBinaryMatrix.js | 2 +- Week_07/773slidingPuzzle.js | 26 ++++++++++++ Week_07/README.md | 55 +++++++++++++++++++++++++ Week_07/homework.md | 14 ++++--- 4 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 Week_07/773slidingPuzzle.js diff --git a/Week_07/1091shortestPathBinaryMatrix.js b/Week_07/1091shortestPathBinaryMatrix.js index 9139f36a..fac2159a 100644 --- a/Week_07/1091shortestPathBinaryMatrix.js +++ b/Week_07/1091shortestPathBinaryMatrix.js @@ -2,7 +2,7 @@ * https://leetcode-cn.com/problems/shortest-path-in-binary-matrix/ * 1091. 二进制矩阵中的最短路径 * - * + * TODO A*解法更快 */ // BFS, 有副作用 diff --git a/Week_07/773slidingPuzzle.js b/Week_07/773slidingPuzzle.js new file mode 100644 index 00000000..6970e6cd --- /dev/null +++ b/Week_07/773slidingPuzzle.js @@ -0,0 +1,26 @@ +/** + * https://leetcode-cn.com/problems/sliding-puzzle/ + * 773. 滑动谜题 | hard + */ + +// BFS +const slidingPuzzle = function(A) { + +} + +// ---- test case ---- +const A1 = [ + [1, 2, 3], + [4, 0, 5], +] +const A2 = [ + [1, 2, 3], + [5, 4, 0], +] +const A3 = [ + [4, 1, 2], + [5, 0, 3], +] +console.log(slidingPuzzle(A1)) // 1 +console.log(slidingPuzzle(A2)) // -1 +console.log(slidingPuzzle(A3)) // 5 diff --git a/Week_07/README.md b/Week_07/README.md index 10aa7062..216527f9 100644 --- a/Week_07/README.md +++ b/Week_07/README.md @@ -78,3 +78,58 @@ def AstarSearch(graph, start, end): 启发式函数是一种告知搜索节点方向的方法。它提供了一种明智的方法来猜测哪个邻居节点会导向一个目标。 +```js +class SortedArray { + constructor(data, compare) { + this.data = data + this.compare = compare + } + // 每次取最小值 + take() { + let minIdx = 0, min = this.data[0] + for(let i = 0; i < this.data.length; ++i) { + if (this.compare(min, this.data[i]) > 0) { + min = this.data[i] + minIdx = i + } + } + this.data[minIdx] = this.data[this.data.length - 1] + this.data.push() + return min + } + insert(value) { + this.data.push(value) + } + get length() { + return this.data.length + } +} + +function aStarSearch (graph, start, end) { + // graph 使用二维数组来存储数据 + let collection = new SortedArray([start], (p1, p2) => distance(p1) - distance(p2)) + while (collection.length > 0) { + let [x, y] = collection.take() + if (x === end[0] && y === end[1]) { + return true + } + insert([x - 1, y]) + insert([x + 1, y]) + insert([x, y - 1]) + insert([x, y + 1]) + } + return false + + function distance([x, y]) { + return (x - end[0]) ** 2 - (y - end[1]) ** 2 + } + + function insert([x, y]) { + if (graph[x][y] !== 0) return + if (x < 0 || x >= graph[0].length || + y < 0 || y >= graph.length) return + graph[x][y] = 2 + collection.insert([x, y]) + } +} +``` diff --git a/Week_07/homework.md b/Week_07/homework.md index 43fd4f37..36f61a70 100644 --- a/Week_07/homework.md +++ b/Week_07/homework.md @@ -28,11 +28,13 @@ ## 三、启发式搜索 ### 1091. 二进制矩阵中的最短路径 -解法一:DP -解法二:BFS -解法三:A* ++ 解法一:DP ++ 解法二:BFS ++ 解法三:A* ++ [代码](./1091shortestPathBinaryMatrix.js) -[代码](./1091shortestPathBinaryMatrix.js) - -### 773. 滑动谜题 +### TODO 773. 滑动谜题 ++ 解法一:BFS ++ 解法二:A* ++ [代码](./773slidingPuzzle.js) From ad4c0c896625dde41f297f799a7ca9e12a6e702a Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Mar 2021 09:25:26 +0800 Subject: [PATCH 115/210] solve slidingPuzzle with BFS --- Week_07/773slidingPuzzle.js | 48 +++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/Week_07/773slidingPuzzle.js b/Week_07/773slidingPuzzle.js index 6970e6cd..59b11872 100644 --- a/Week_07/773slidingPuzzle.js +++ b/Week_07/773slidingPuzzle.js @@ -1,11 +1,55 @@ /** * https://leetcode-cn.com/problems/sliding-puzzle/ * 773. 滑动谜题 | hard + * + * 0, 1, 2 + * 3, 4, 5 */ -// BFS -const slidingPuzzle = function(A) { +function swapArr(arr, i, j) { + if (i !== j && + i >= 0 && i < arr.length && + j >= 0 && j < arr.length) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp + } +} +// BFS [[str, idxOf0]...] +const slidingPuzzle = function(A) { + const moves = [ + [1, 3], + [0, 2, 4], + [1, 5], + [0, 4], + [1, 3, 5], + [2, 4], + ] + const used = new Set() + const str = A[0].join('') + A[1].join('') + let queue = [[str, str.indexOf('0')]] + let cnt = 0 + while (queue.length > 0) { + const nextQueue = [] + for (let idx = 0; idx < queue.length; ++idx) { + const [s, i] = queue[idx] + used.add(s) + if (s === '123450') return cnt + const curArr = s.split('') + for (const move of moves[i]) { + const nextArr = [].concat(curArr) + swapArr(nextArr, move, i) + const nextStr = nextArr.join('') + if (!used.has(nextStr)) { + nextQueue.push([nextStr, move]) + } + } + } + ++cnt + queue = nextQueue + } + return -1 } // ---- test case ---- From 9d038d5bf9d2518be92a16d2095a02890f1aa0e5 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Mar 2021 09:44:49 +0800 Subject: [PATCH 116/210] complete template of Week07 --- Week_07/022generateParenthesis.js | 12 ++++++++++++ Week_07/036isValidSudoku.js | 10 ++++++++++ Week_07/037solveSudoku.js | 10 ++++++++++ Week_07/051solveNQueens.js | 11 +++++++++++ Week_07/070climbStairs.js | 10 ++++++++++ Week_07/127ladderLength.js | 10 ++++++++++ Week_07/433minMutation.js | 12 ++++++++++++ Week_07/homework.md | 13 ++++++++++--- 8 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 Week_07/022generateParenthesis.js create mode 100644 Week_07/036isValidSudoku.js create mode 100644 Week_07/037solveSudoku.js create mode 100644 Week_07/051solveNQueens.js create mode 100644 Week_07/070climbStairs.js create mode 100644 Week_07/127ladderLength.js create mode 100644 Week_07/433minMutation.js diff --git a/Week_07/022generateParenthesis.js b/Week_07/022generateParenthesis.js new file mode 100644 index 00000000..025f3976 --- /dev/null +++ b/Week_07/022generateParenthesis.js @@ -0,0 +1,12 @@ +/** + * https://leetcode-cn.com/problems/generate-parentheses/ + * 22. 括号生成 | medium + * + */ + +// DFS +const generateParenthesis = function(n) { + +} + +// ---- test case ---- diff --git a/Week_07/036isValidSudoku.js b/Week_07/036isValidSudoku.js new file mode 100644 index 00000000..5852dfee --- /dev/null +++ b/Week_07/036isValidSudoku.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/valid-sudoku/ + * 36. 有效的数独 | medium + */ + +const isValidSudoku = function(board) { + +} + +// ---- test case ---- diff --git a/Week_07/037solveSudoku.js b/Week_07/037solveSudoku.js new file mode 100644 index 00000000..4df3c411 --- /dev/null +++ b/Week_07/037solveSudoku.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/sudoku-solver/ + * 37. 解数独 | hard + */ + +const solveSudoku = function(board) { + +} + +// ---- test case ---- diff --git a/Week_07/051solveNQueens.js b/Week_07/051solveNQueens.js new file mode 100644 index 00000000..9a618147 --- /dev/null +++ b/Week_07/051solveNQueens.js @@ -0,0 +1,11 @@ +/** + * https://leetcode-cn.com/problems/n-queens/ + * 51. N 皇后 | hard + */ + +// DFS +const solveNQueens = function(n) { + +} + +// ---- test case ---- diff --git a/Week_07/070climbStairs.js b/Week_07/070climbStairs.js new file mode 100644 index 00000000..34ae2bde --- /dev/null +++ b/Week_07/070climbStairs.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/climbing-stairs/ + * 70. 爬楼梯 + */ + +const climbStairs = function(n) { + +} + +// ---- test case ---- diff --git a/Week_07/127ladderLength.js b/Week_07/127ladderLength.js new file mode 100644 index 00000000..9c50e983 --- /dev/null +++ b/Week_07/127ladderLength.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/word-ladder/ + * 127. 单词接龙 | hard + */ + +const ladderLength = function(beginWord, endWord, wordList) { + +} + +// ---- test case ---- diff --git a/Week_07/433minMutation.js b/Week_07/433minMutation.js new file mode 100644 index 00000000..33b47c0c --- /dev/null +++ b/Week_07/433minMutation.js @@ -0,0 +1,12 @@ +/** + * https://leetcode-cn.com/problems/minimum-genetic-mutation/ + * 433. 最小基因变化 | medium + * + */ + +// +const minMutation = function(start, end, bank) { + +} + +// ---- test case ---- diff --git a/Week_07/homework.md b/Week_07/homework.md index 36f61a70..092f2bd7 100644 --- a/Week_07/homework.md +++ b/Week_07/homework.md @@ -4,26 +4,33 @@ ### 爬楼梯(阿里巴巴、腾讯、字节跳动在半年内面试常考) ++ [代码](./070climbStairs.js) ### 括号生成(亚马逊、Facebook、字节跳动在半年内面试中考过) ++ [代码](./022generateParenthesis.js) -### 有效的数独(亚马逊、苹果、微软在半年内面试中考过) +### N 皇后(亚马逊、苹果、字节跳动在半年内面试中考过) ++ [代码](./051solveNQueens.js) -### N 皇后(亚马逊、苹果、字节跳动在半年内面试中考过) +### 有效的数独(亚马逊、苹果、微软在半年内面试中考过) ++ [代码](./036isValidSudoku.js) ### 解数独(亚马逊、华为、微软在半年内面试中考过) ++ [代码](./037solveSudoku.js) ## 二、双向BFS ### 单词接龙(亚马逊、Facebook、谷歌在半年内面试中考过) ++ [代码](./127ladderLength.js) ### 最小基因变化(谷歌、Twitter、腾讯在半年内面试中考过) ++ [代码](./433minMutation.js) ## 三、启发式搜索 ### 1091. 二进制矩阵中的最短路径 @@ -33,7 +40,7 @@ + 解法三:A* + [代码](./1091shortestPathBinaryMatrix.js) -### TODO 773. 滑动谜题 +### 773. 滑动谜题 + 解法一:BFS + 解法二:A* From 1e4062d7dd0efabd8f88b70cf53033eb340d29df Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Mar 2021 10:51:03 +0800 Subject: [PATCH 117/210] solve three old problem --- Week_07/022generateParenthesis.js | 17 +++++++++-- Week_07/051solveNQueens.js | 50 ++++++++++++++++++++++++++++++- Week_07/070climbStairs.js | 15 +++++++++- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/Week_07/022generateParenthesis.js b/Week_07/022generateParenthesis.js index 025f3976..9a394637 100644 --- a/Week_07/022generateParenthesis.js +++ b/Week_07/022generateParenthesis.js @@ -4,9 +4,22 @@ * */ -// DFS +// DFS + prun const generateParenthesis = function(n) { - + const res = [] + const stack = [['(', 1, 0]] + while (stack.length > 0) { + const [curStr, cntL, cntR] = stack.pop() + if (cntL === n && cntR === n) res.push(curStr) + if (cntR < cntL) stack.push([curStr + ')', cntL, cntR + 1]) + if (cntL < n) stack.push([curStr + '(', cntL + 1, cntR]) + } + return res } // ---- test case ---- +new Array(5) + .fill(0) + .map((_, idx) => { + console.log(idx, generateParenthesis(idx)) + }) diff --git a/Week_07/051solveNQueens.js b/Week_07/051solveNQueens.js index 9a618147..eb8c430b 100644 --- a/Week_07/051solveNQueens.js +++ b/Week_07/051solveNQueens.js @@ -3,9 +3,57 @@ * 51. N 皇后 | hard */ +/** + * 构建结果表示形式 + * @param {Array} results 二维数组,每一项是一个可行解 + * @param {Number} n N皇后问题的N + * @returns {Array} 结果 + */ +function buildResultsBoard(results, n) { + const board = [] + results.forEach(res => { + const matrix = [] + res.forEach(i => { + const line = '.'.repeat(i) + 'Q' + '.'.repeat(n - i - 1) + matrix.push(line) + }) + board.push(matrix) + }) + return board +} + // DFS -const solveNQueens = function(n) { +function solveNQueens(n) { + if (n < 1) return [[]] + const results = [] + const cols = new Set() // 竖 + const pies = new Set() // 撇 + const nas = new Set() // 捺 + + const dfs = (i, curState) => { + if (i >= n) { + results.push(curState) + return + } + for (let j = 0; j < n; ++j) { + if (cols.has(j) || pies.has(i + j) || nas.has(i - j)) continue + cols.add(j) + pies.add(i + j) + nas.add(i - j) + dfs(i + 1, curState.concat([j])) + cols.delete(j) + pies.delete(i + j) + nas.delete(i - j) + } + } + dfs(0, []) + return buildResultsBoard(results, n) } // ---- test case ---- +// console.log(buildResultsBoard([ +// [1, 3, 0, 2], +// [2, 0, 3, 1], +// ], 4)) +console.log(solveNQueens(4)) diff --git a/Week_07/070climbStairs.js b/Week_07/070climbStairs.js index 34ae2bde..5e3b545c 100644 --- a/Week_07/070climbStairs.js +++ b/Week_07/070climbStairs.js @@ -3,8 +3,21 @@ * 70. 爬楼梯 */ +// DP const climbStairs = function(n) { - + if (n < 4) return n + let f1 = 2, f2 = 3, f3 + for(let i = 4; i <= n; ++i) { + f3 = f1 + f2 + f1 = f2 + f2 = f3 + } + return f3 } // ---- test case ---- +new Array(20) + .fill(0) + .map((_, idx) => { + console.log(climbStairs(idx + 1)) + }) From d343923c61b608b159ce984c75c7eaf97fe2bce0 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Mar 2021 16:16:01 +0800 Subject: [PATCH 118/210] sudoku --- Week_07/036isValidSudoku.js | 38 +++++++++++++++++++- Week_07/037solveSudoku.js | 71 ++++++++++++++++++++++++++++++++++++- Week_07/homework.md | 3 ++ 3 files changed, 110 insertions(+), 2 deletions(-) diff --git a/Week_07/036isValidSudoku.js b/Week_07/036isValidSudoku.js index 5852dfee..47d58fd5 100644 --- a/Week_07/036isValidSudoku.js +++ b/Week_07/036isValidSudoku.js @@ -3,8 +3,44 @@ * 36. 有效的数独 | medium */ -const isValidSudoku = function(board) { +// O(1) +const isValidSudoku = function(A) { + for (let i = 0; i < 9; ++i) { + const row = new Set() + const col = new Set() + const box = new Set() + for (let j = 0; j < 9; ++j) { + const rItem = A[i][j] + const cItem = A[j][i] + const bItem = A[3 * Math.floor(i / 3) + Math.floor(j / 3)][3 * (i % 3) + (j % 3)] + + if (rItem !== '.') { + if (row.has(rItem)) return false + row.add(rItem) + } + if (cItem !== '.') { + if (col.has(cItem)) return false + col.add(cItem) + } + if (bItem !== '.') { + if (box.has(bItem)) return false + box.add(bItem) + } + } + } + return true } // ---- test case ---- +console.log(isValidSudoku([ + ["5", "3", ".", ".", "7", ".", ".", ".", "."], + ["6", ".", ".", "1", "9", "5", ".", ".", "."], + [".", "9", "8", ".", ".", ".", ".", "6", "."], + ["8", ".", ".", ".", "6", ".", ".", ".", "3"], + ["4", ".", ".", "8", ".", "3", ".", ".", "1"], + ["7", ".", ".", ".", "2", ".", ".", ".", "6"], + [".", "6", ".", ".", ".", ".", "2", "8", "."], + [".", ".", ".", "4", "1", "9", ".", ".", "5"], + [".", ".", ".", ".", "8", ".", ".", "7", "9"], +])) // true diff --git a/Week_07/037solveSudoku.js b/Week_07/037solveSudoku.js index 4df3c411..e0c7ecdd 100644 --- a/Week_07/037solveSudoku.js +++ b/Week_07/037solveSudoku.js @@ -3,8 +3,77 @@ * 37. 解数独 | hard */ -const solveSudoku = function(board) { +// set 交集 +function intersection(set1, set2) { + return new Set([...set1].filter(x => set2.has(x))) +} + +function solveSudoku(A) { + const init = (n) => + Array(n).fill(0) + .map( + _ => + new Set( + Array(n).fill(0) + .map( + (_, i) => i + 1 + ) + ) + ) + const row = init(9) // 行剩余可用数字 + const col = init(9) // 列剩余可用数字 + const box = init(9) // 块剩余可用数字 + const empty = [] // 收集需填数位置 + for (let i = 0; i < 9; ++i) { + for (let j = 0; j < 9; ++j) { + if (A[i][j] === '.') { + empty.push([i, j]) + } else { + const val = Number(A[i][j]) + row[i].delete(val) + col[j].delete(val) + box[Math.floor(i / 3) * 3 + Math.floor(j / 3)].delete(val) + } + } + } + // console.log(row, col, box, empty) + backtrack(A, row, col, box, empty, 0) +} +// 对于每一个 empty 坐标,试探所有 set 交集中的数值,没有路了就回溯 +function backtrack(A, row, col, box, empty, iter) { + if (iter === empty.length) return true + const [i, j] = empty[iter] + const b = Math.floor(i / 3) * 3 + Math.floor(j / 3) + const validSet = intersection(intersection(row[i], col[j]), box[b]) + // console.log("🚀validSet", i, j, validSet) + for (const val of validSet) { + // console.log("🚀", iter, ': ', i, j, val) + row[i].delete(val) + col[j].delete(val) + box[b].delete(val) + A[i][j] = String(val) + if (backtrack(A, row, col, box, empty, iter + 1)) { + return true + } + row[i].add(val) + col[j].add(val) + box[b].add(val) + } + return false } // ---- test case ---- +const board = [ + ["5", "3", ".", ".", "7", ".", ".", ".", "."], + ["6", ".", ".", "1", "9", "5", ".", ".", "."], + [".", "9", "8", ".", ".", ".", ".", "6", "."], + ["8", ".", ".", ".", "6", ".", ".", ".", "3"], + ["4", ".", ".", "8", ".", "3", ".", ".", "1"], + ["7", ".", ".", ".", "2", ".", ".", ".", "6"], + [".", "6", ".", ".", ".", ".", "2", "8", "."], + [".", ".", ".", "4", "1", "9", ".", ".", "5"], + [".", ".", ".", ".", "8", ".", ".", "7", "9"], +] +solveSudoku(board) +console.log(board) diff --git a/Week_07/homework.md b/Week_07/homework.md index 092f2bd7..97517a2f 100644 --- a/Week_07/homework.md +++ b/Week_07/homework.md @@ -12,8 +12,11 @@ ### N 皇后(亚马逊、苹果、字节跳动在半年内面试中考过) ++ DFS + [代码](./051solveNQueens.js) +TODO 位运算 + ### 有效的数独(亚马逊、苹果、微软在半年内面试中考过) + [代码](./036isValidSudoku.js) From b87903fbbcdab9b0b3fd5ed3eba693667279858b Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Mar 2021 16:53:17 +0800 Subject: [PATCH 119/210] review BFS --- Week_07/127ladderLength.js | 29 ++++++++++++++++++++++++++++- Week_07/433minMutation.js | 29 +++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/Week_07/127ladderLength.js b/Week_07/127ladderLength.js index 9c50e983..49828be8 100644 --- a/Week_07/127ladderLength.js +++ b/Week_07/127ladderLength.js @@ -3,8 +3,35 @@ * 127. 单词接龙 | hard */ -const ladderLength = function(beginWord, endWord, wordList) { +// 解法一:BFS + 回溯 + 剪枝 +const ladderLength1 = function(beginWord, endWord, wordList) { + const wordSet = new Set(wordList) + const queue = [[beginWord, 1]] + const alphas = [...'abcdefghijklmnopqrstuvwxyz'] + while (queue.length > 0) { + const [curWord, level] = queue.pop() + if (curWord === endWord) return level + for (let i = 0; i < curWord.length; ++i) { + for (const ch of alphas) { + if (ch === curWord[i]) continue // prun + const nextWord = curWord.slice(0, i) + ch + curWord.slice(i + 1) + if (wordSet.has(nextWord)) { + wordSet.delete(nextWord) + queue.unshift([nextWord, level + 1]) + } + } + } + } + return 0 +} +// 解法二:双向BFS +const ladderLength = function(beginWord, endWord, wordList) { + // TODO } // ---- test case ---- +console.log(ladderLength('abc', 'def', ['dbc', 'bbc', 'dec', 'def', 'log', 'cog'])) // 4 +console.log(ladderLength('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log', 'cog'])) // 5 +console.log(ladderLength('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log'])) // 0 +console.log(ladderLength("qa","sq",["si","go","se","cm","so","ph","mt","db","mb","sb","kr","ln","tm","le","av","sm","ar","ci","ca","br","ti","ba","to","ra","fa","yo","ow","sn","ya","cr","po","fe","ho","ma","re","or","rn","au","ur","rh","sr","tc","lt","lo","as","fr","nb","yb","if","pb","ge","th","pm","rb","sh","co","ga","li","ha","hz","no","bi","di","hi","qa","pi","os","uh","wm","an","me","mo","na","la","st","er","sc","ne","mn","mi","am","ex","pt","io","be","fm","ta","tb","ni","mr","pa","he","lr","sq","ye"])) // 5 diff --git a/Week_07/433minMutation.js b/Week_07/433minMutation.js index 33b47c0c..95f53666 100644 --- a/Week_07/433minMutation.js +++ b/Week_07/433minMutation.js @@ -4,9 +4,34 @@ * */ -// +// 解法一:BFS + 回溯 + 剪枝 +const minMutation1 = function(start, end, bank) { + const bankSet = new Set(bank) + const genes = [...'ACGT'] + const queue = [[start, 0]] + while (queue.length > 0) { + const [curStr, level] = queue.pop() + if (curStr === end) return level + for (let i = 0; i < curStr.length; ++i) { + for (const ch of genes) { + if (ch === curStr[i]) continue + const nextStr = curStr.slice(0, i) + ch + curStr.slice(i + 1) + if (bankSet.has(nextStr)) { + bankSet.delete(nextStr) + queue.unshift([nextStr, level + 1]) + } + } + } + } + return -1 +} + +// 解法二:双向BFS const minMutation = function(start, end, bank) { - + // TODO } // ---- test case ---- +console.log(minMutation('AACCGGTT', 'AACCGGTA', ['AACCGGTA'])) // 1 +console.log(minMutation('AACCGGTT', 'AAACGGTA', ['AACCGGTA', 'AACCGCTA', 'AAACGGTA'])) // 2 +console.log(minMutation('AAAAACCC', 'AACCCCCC', ['AAAACCCC', 'AAACCCCC', 'AACCCCCC'])) // 3 From b8775c483dab2d37db04d27065aa3e146fefebe6 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 21 Mar 2021 18:13:52 +0800 Subject: [PATCH 120/210] two end bfs --- Week_07/127ladderLength.js | 36 +++++++++++++++++++++++++++++++++++- Week_07/433minMutation.js | 37 +++++++++++++++++++++++++++++++++++-- Week_07/README.md | 4 ++++ 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/Week_07/127ladderLength.js b/Week_07/127ladderLength.js index 49828be8..9f1327df 100644 --- a/Week_07/127ladderLength.js +++ b/Week_07/127ladderLength.js @@ -5,6 +5,7 @@ // 解法一:BFS + 回溯 + 剪枝 const ladderLength1 = function(beginWord, endWord, wordList) { + if (wordList.indexOf(endWord) === -1) return 0 const wordSet = new Set(wordList) const queue = [[beginWord, 1]] const alphas = [...'abcdefghijklmnopqrstuvwxyz'] @@ -27,7 +28,40 @@ const ladderLength1 = function(beginWord, endWord, wordList) { // 解法二:双向BFS const ladderLength = function(beginWord, endWord, wordList) { - // TODO + if (wordList.indexOf(endWord) === -1) return 0 + const alphas = [...'abcdefghijklmnopqrstuvwxyz'] + const n = beginWord.length + const wordSet = new Set(wordList) + let frontSet = new Set([beginWord]) + let endSet = new Set([endWord]) + let level = 1 + while (frontSet.size > 0) { + ++level + const nextFrontSet = new Set() + for (curWord of frontSet) { + for (let i = 0; i < n; ++i) { + for (const ch of alphas) { + if (ch !== curWord[i]) { + nextWord = curWord.slice(0, i) + ch + curWord.slice(i + 1) + if (endSet.has(nextWord)) { + return level + } + if (wordSet.has(nextWord)) { + nextFrontSet.add(nextWord) + wordSet.delete(nextWord) + } + } + } + } + } + frontSet = nextFrontSet + if (frontSet.size > endSet.size) { // swap + const tmp = frontSet + frontSet = endSet + endSet = tmp + } + } + return 0 } // ---- test case ---- diff --git a/Week_07/433minMutation.js b/Week_07/433minMutation.js index 95f53666..9aaef8c3 100644 --- a/Week_07/433minMutation.js +++ b/Week_07/433minMutation.js @@ -27,8 +27,41 @@ const minMutation1 = function(start, end, bank) { } // 解法二:双向BFS -const minMutation = function(start, end, bank) { - // TODO +const minMutation = function(beginWord, endWord, wordList) { + if (wordList.indexOf(endWord) === -1) return -1 + const alphas = [...'ACGT'] + const n = beginWord.length + const wordSet = new Set(wordList) + let frontSet = new Set([beginWord]) + let endSet = new Set([endWord]) + let level = 0 + while (frontSet.size > 0) { + ++level + const nextFrontSet = new Set() + for (curWord of frontSet) { + for (let i = 0; i < n; ++i) { + for (const ch of alphas) { + if (ch !== curWord[i]) { + nextWord = curWord.slice(0, i) + ch + curWord.slice(i + 1) + if (endSet.has(nextWord)) { + return level + } + if (wordSet.has(nextWord)) { + nextFrontSet.add(nextWord) + wordSet.delete(nextWord) + } + } + } + } + } + frontSet = nextFrontSet + if (frontSet.size > endSet.size) { // swap + const tmp = frontSet + frontSet = endSet + endSet = tmp + } + } + return -1 } // ---- test case ---- diff --git a/Week_07/README.md b/Week_07/README.md index 216527f9..662fb9e4 100644 --- a/Week_07/README.md +++ b/Week_07/README.md @@ -39,8 +39,12 @@ const dfs = (root) => { ### 剪枝 +尽早删除无效分支,加速搜索 + ### 双向BFS ++ two ended search + ### 启发式搜索 A* ```python From ab65b52326f4a7e88fe6edd98900bd23b9f4e02c Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 22 Mar 2021 00:18:53 +0800 Subject: [PATCH 121/210] BloomFilter & LRUCache --- Week_09/146LRUCache.js | 99 +++++++++++++++++++++++++++++++++++ Week_09/BloomFilter.js | 116 +++++++++++++++++++++++++++++++++++++++++ Week_09/README.md | 18 +++++++ 3 files changed, 233 insertions(+) create mode 100644 Week_09/146LRUCache.js create mode 100644 Week_09/BloomFilter.js diff --git a/Week_09/146LRUCache.js b/Week_09/146LRUCache.js new file mode 100644 index 00000000..525cda63 --- /dev/null +++ b/Week_09/146LRUCache.js @@ -0,0 +1,99 @@ +/** + * https://leetcode-cn.com/problems/lru-cache/ + * 146. LRU 缓存机制 | medium + */ + +// 解法一:利用 Map 本身是 orderedDict 的特性 +class LRUCache1 { + constructor(capacity) { + this.cache = new Map() + this.capacity = capacity + } + get(key) { + if (!this.cache.has(key)) return -1 + const v = this.cache.get(key) + this.cache.delete(key) + this.cache.set(key, v) + return this.cache.get(key) + } + put(key, value) { + if (this.cache.has(key)) { + this.cache.delete(key) + } + this.cache.set(key, value) + if (this.cache.size > this.capacity) { + this.cache.delete(this.cache.keys().next().value) + } + } +} + +// 解法二:HashMap + DoubleLinkedList +class ListNode { + constructor(key, value) { + this.key = key; // 用于存放key,以便于后面在cache中删除 + this.value = value; + this.prev = null; + this.next = null; + } +} +class LRUCache { + constructor(capacity) { + this.capacity = capacity; + this.cache = new Map(); + // 空头节点和空尾节点方便操作 + this.dummyHead = new ListNode(-1, -1); + this.dummyTail = new ListNode(-1, -1); + this.dummyHead.next = this.dummyTail; + this.dummyTail.prev = this.dummyHead; + } + get(key) { + if (!this.cache.has(key)) { + return -1; + } + const node = this.cache.get(key); + this._move2head(node); // 移到头部 + return node.value; + } + put(key, value) { + if (this.cache.has(key)) { // 存在 + const node = this.cache.get(key); + node.value = value; // 更新值 + this._move2head(node); + } else { // 不存在 + if (this.cache.size === this.capacity) { // 满了 + const removedNode = this.dummyTail.prev; // 移除最后一个 + this._removeNode(removedNode); + this.cache.delete(removedNode.key); + } + const newNode = new ListNode(key, value); + this.cache.set(key, newNode); + this._addHead(newNode); + } + } + _addHead(node) { + node.next = this.dummyHead.next; + this.dummyHead.next.prev = node; + this.dummyHead.next = node; + node.prev = this.dummyHead; + } + _removeNode(node) { + node.prev.next = node.next; + node.next.prev = node.prev; + } + _move2head(node) { + this._removeNode(node); + this._addHead(node); + } +} + +// ---- test case ---- +const cache = new LRUCache(2) +cache.put(1, 1) +cache.put(2, 2) +console.log(cache.get(1)) // 1 +cache.put(3, 3) +console.log(cache.get(2)) // -1 +cache.put(4, 4) +console.log(cache.get(1)) // -1 +console.log(cache.get(3)) // 3 +console.log(cache.get(4)) // 4 diff --git a/Week_09/BloomFilter.js b/Week_09/BloomFilter.js new file mode 100644 index 00000000..d6bd9743 --- /dev/null +++ b/Week_09/BloomFilter.js @@ -0,0 +1,116 @@ +// 布隆过滤器 +class BloomFilter { + constructor(maxKeys, errorRate) { + this.bitMap = [] + this.maxKeys = maxKeys + this.errorRate = errorRate + // 位图变量的长度,需要根据 maxKeys 和 errorRate 来计算 + this.bitSize = Math.ceil(maxKeys * (-Math.log(errorRate) / (Math.log(2) * Math.log(2)))) + // 哈希数量 + this.hashCount = Math.ceil(Math.log(2) * (this.bitSize / maxKeys)) + // 已加入元素数量 + this.keyCount = 0 + } + + bitSet(bit) { + let numArr = Math.floor(bit / 31) + let numBit = Math.floor(bit % 31) + this.bitMap[numArr] |= 1 << numBit + } + + bitGet(bit) { + let numArr = Math.floor(bit / 31) + let numBit = Math.floor(bit % 31) + return (this.bitMap[numArr] &= 1 << numBit) + } + + add(key) { + if (this.contain(key)) { + return -1 + } + let hash1 = MurmurHash(key, 0, 0), + hash2 = MurmurHash(key, 0, hash1) + for (let i = 0; i < this.hashCount; i++) { + this.bitSet(Math.abs(Math.floor((hash1 + i * hash2) % this.bitSize))) + } + this.keyCount++ + } + + contain(key) { + let hash1 = MurmurHash(key, 0, 0) + let hash2 = MurmurHash(key, 0, hash1) + for (let i = 0; i < this.hashCount; i++) { + if (!this.bitGet(Math.abs(Math.floor((hash1 + i * hash2) % this.bitSize)))) { + return false + } + } + return true + } +} + +/** + * MurmurHash + * + * 参考 http://murmurhash.googlepages.com/ + * + * data:待哈希的值 + * offset: + * seed:种子集 + * + */ +function MurmurHash(data, offset, seed) { + let len = data.length, + m = 0x5bd1e995, + r = 24, + h = seed ^ len, + len_4 = len >> 2; + + for (let i = 0; i < len_4; i++) { + let i_4 = (i << 2) + offset, + k = data[i_4 + 3]; + + k = k << 8; + k = k | (data[i_4 + 2] & 0xff); + k = k << 8; + k = k | (data[i_4 + 1] & 0xff); + k = k << 8; + k = k | (data[i_4 + 0] & 0xff); + k *= m; + k ^= k >>> r; + k *= m; + h *= m; + h ^= k; + } + + // avoid calculating modulo + let len_m = len_4 << 2, + left = len - len_m, + i_m = len_m + offset; + + if (left != 0) { + if (left >= 3) { + h ^= data[i_m + 2] << 16; + } + if (left >= 2) { + h ^= data[i_m + 1] << 8; + } + if (left >= 1) { + h ^= data[i_m]; + } + + h *= m; + } + + h ^= h >>> 13; + h *= m; + h ^= h >>> 15; + + return h; +} + + +let bloomFilter = new BloomFilter(10000, 0.01); + +bloomFilter.add("abcdefgh"); +console.log(bloomFilter.contain("abcdefgh")); +console.log(bloomFilter.contain("abcdefghi")); diff --git a/Week_09/README.md b/Week_09/README.md index 827e166c..f8732f21 100644 --- a/Week_09/README.md +++ b/Week_09/README.md @@ -2,6 +2,24 @@ ## 第 17 课 | 布隆过滤器 & LRU 缓存 +### Bloom Filter + +案例 + +1. 比特币网络 +2. 分布式系统(Map-Reduce)—— Hadoop,search engine +3. Redis缓存 +4. 垃圾邮件、评论等的过滤 + +> https://www.cnblogs.com/cpselvis/p/6265825.html +> https://blog.csdn.net/tianyaleixiaowu/article/details/74721877 + +### LRU cache + ++ Least recently used ++ 实现:HashMap + 双向链表 ++ O(1) 查询 ++ O(1) 修改、更新 ## 第 18 课 | 排序算法 From a2e82429f9931b36c4c33d8580bb4d118eade141 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 22 Mar 2021 13:23:28 +0800 Subject: [PATCH 122/210] basic & senior sort --- Week_09/README.md | 22 +++++++++++++++++ Week_09/sort-basic.js | 54 ++++++++++++++++++++++++++++++++++++++++++ Week_09/sort-heap.js | 48 +++++++++++++++++++++++++++++++++++++ Week_09/sort-merge.js | 27 +++++++++++++++++++++ Week_09/sort-quick.js | 24 +++++++++++++++++++ Week_09/sort.png | Bin 0 -> 211605 bytes 6 files changed, 175 insertions(+) create mode 100644 Week_09/sort-basic.js create mode 100644 Week_09/sort-heap.js create mode 100644 Week_09/sort-merge.js create mode 100644 Week_09/sort-quick.js create mode 100644 Week_09/sort.png diff --git a/Week_09/README.md b/Week_09/README.md index f8732f21..f9100ac9 100644 --- a/Week_09/README.md +++ b/Week_09/README.md @@ -23,6 +23,28 @@ ## 第 18 课 | 排序算法 +**比较类排序** + ++ 交换排序 + - [冒泡排序](./sort-basic.js) + - [快速排序](./sort-quick.js) ++ 插入排序 + - [简单插入排序](./sort-basic.js) + - 希尔排序 ++ 选择排序 + - [简单选择排序](./sort-basic.js) + - 堆排序 ++ 归并排序 + - [二路归并排序](./sort-merge.js) + - 多路归并排序 + +![](./sort.png) + +**非比较类排序** + ++ 计数排序 ++ 桶排序 ++ 基数排序 ## 第 19 课 | 高级动态规划 diff --git a/Week_09/sort-basic.js b/Week_09/sort-basic.js new file mode 100644 index 00000000..d8c0831f --- /dev/null +++ b/Week_09/sort-basic.js @@ -0,0 +1,54 @@ +// O(n^2) O(1) +function swap(arr, i, j) { + if (i !== j) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp + } +} +// 不稳定 +function selectionSort(arr) { + const n = arr.length + for (let i = 0; i < n - 1; ++i) { + let j, minIdx = i + for (j = i + 1; j < n; ++j) { + if (arr[j] < arr[minIdx]) { + minIdx = j + } + } + swap(arr, i, minIdx) + } + return arr +} +// 稳定 +function insertionSort(arr) { + const n = arr.length + let preIdx, curr + for (let i = 1; i < n; ++i) { + preIdx = i - 1 + curr = arr[i] + while (preIdx >= 0 && arr[preIdx] > curr) { + arr[preIdx + 1] = arr[preIdx] + --preIdx + } + arr[preIdx + 1] = curr + } + return arr +} +// 稳定 +function bubbleSort(arr) { + const n = arr.length + for (let i = 0; i < n - 1; ++i) { + for (let j = 0; j < n - 1 - i; ++j) { + if (arr[j] > arr[j + 1]) { + swap(arr, j, j + 1) + } + } + } + return arr +} + +// ---- test case ---- +console.log(selectionSort([3,2,32,45,767,234,66,32])) +console.log(insertionSort([3,2,32,45,767,234,66,32])) +console.log(bubbleSort([3,2,32,45,767,234,66,32])) diff --git a/Week_09/sort-heap.js b/Week_09/sort-heap.js new file mode 100644 index 00000000..cf16a302 --- /dev/null +++ b/Week_09/sort-heap.js @@ -0,0 +1,48 @@ +// 堆排序 不稳定 O(nlogn) +/** + * [array heap] + * element : i + * left child : 2i + 1 + * right child: 2i + 2 + */ + +function swap(arr, i, j) { + if (i !== j) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp + } +} + +function heapSort(arr) { + if (!arr.length) return + const n = arr.length + for (let i = (n >> 1) - 1; i >= 0; --i) { + heapify(arr, n, i) + } + for (let i = n - 1; i >= 0; --i) { + swap(arr, 0, i) + heapify(arr, i, 0) + } +} + +function heapify(arr, len, i) { + const left = 2 * i + 1, right = 2 * i + 2 + let largest = i + if (left < len && arr[left] > arr[largest]) { + largest = left + } + if (right < len && arr[right] > arr[largest]) { + largest = right + } + if (largest !== i) { + swap(arr, i, largest) + heapify(arr, len, largest) + } +} + + +// ---- test case ---- +const arr = [3, 2, 32, 45, 767, 234, 66, 32] +heapSort(arr) +console.log(arr) diff --git a/Week_09/sort-merge.js b/Week_09/sort-merge.js new file mode 100644 index 00000000..cd0a8eef --- /dev/null +++ b/Week_09/sort-merge.js @@ -0,0 +1,27 @@ +// 归并排序 稳定 O(nlogn) +// 缺点:需要额外空间 +function mergeSort(arr, left = 0, right = arr.length - 1) { + if (left >= right) return + const mid = left + ((right - left) >> 1) + mergeSort(arr, left, mid) + mergeSort(arr, mid + 1, right) + merge(arr, left, mid, right) +} + +function merge(arr, left, mid, right) { + const tmp = new Array(right - left + 1) + let i = left, j = mid + 1, k = 0 + while (i <= mid && j <= right) { + tmp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++] + } + while (i <= mid) tmp[k++] = arr[i++] + while (j <= right) tmp[k++] = arr[j++] + for (let p = 0; p < tmp.length; ++p) { + arr[left + p] = tmp[p] + } +} + +// ---- test case ---- +const arr = [3, 2, 32, 45, 767, 234, 66, 32] +mergeSort(arr) +console.log(arr) diff --git a/Week_09/sort-quick.js b/Week_09/sort-quick.js new file mode 100644 index 00000000..e20c024c --- /dev/null +++ b/Week_09/sort-quick.js @@ -0,0 +1,24 @@ +// 快速排序 不稳定 O(nlogn) +function quickSort(arr, left = 0, right = arr.length - 1) { + if (left >= right) return + const pivotIdx = partition(arr, left, right) + quickSort(arr, left, pivotIdx - 1) + quickSort(arr, pivotIdx + 1, right) +} + +function partition(arr, left, right) { + const pivot = arr[left] + while (left < right) { + while (left < right && arr[right] >= pivot) --right + if (left < right) arr[left] = arr[right] + while (left < right && arr[left] <= pivot) ++left + if (left < right) arr[right] = arr[left] + } + arr[left] = pivot + return left +} + +// ---- test case ---- +const arr = [3, 2, 32, 45, 767, 234, 66, 32] +quickSort(arr) +console.log(arr) diff --git a/Week_09/sort.png b/Week_09/sort.png new file mode 100644 index 0000000000000000000000000000000000000000..1027e76324313277e1f087ec86064f05bf93357e GIT binary patch literal 211605 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

9`^AexUpe9_evp^lIxeJXO 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 literal 0 HcmV?d00001 From a20486e3457e1e5f6d2dbe23944f76d325475a47 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 22 Mar 2021 13:42:18 +0800 Subject: [PATCH 123/210] complete template of Week09 --- Week_09/README.md | 2 +- Week_09/homework.md | 57 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/Week_09/README.md b/Week_09/README.md index f9100ac9..301b7bcb 100644 --- a/Week_09/README.md +++ b/Week_09/README.md @@ -33,7 +33,7 @@ - 希尔排序 + 选择排序 - [简单选择排序](./sort-basic.js) - - 堆排序 + - [堆排序](./sort-heap.js) + 归并排序 - [二路归并排序](./sort-merge.js) - 多路归并排序 diff --git a/Week_09/homework.md b/Week_09/homework.md index c261e599..95b90338 100644 --- a/Week_09/homework.md +++ b/Week_09/homework.md @@ -1 +1,58 @@ # 作业 +## 一、BloomFilter 和 LRU Cache + +### LRU 缓存机制(亚马逊、字节跳动、Facebook、微软在半年内面试中常考) + + + + + + +## 二、Sort + +### 用自己熟悉的编程语言,手写各种初级排序代码,提交到学习总结中。 + +1. [冒泡排序、插入排序、选择排序](./sort-basic.js) +2. [快速排序](./sort-quick.js) +3. [二路归并排序](./sort-merge.js) +4. [堆排序](./sort-heap.js) + +### 数组的相对排序(谷歌在半年内面试中考过) + + +### 有效的字母异位词(Facebook、亚马逊、谷歌在半年内面试中考过) + + +### 力扣排行榜(Bloomberg 在半年内面试中考过) + + +### 合并区间(Facebook、字节跳动、亚马逊在半年内面试中常考) + + +### 翻转对(字节跳动在半年内面试中考过) + + + + + + +## 三、高级动态规划 + +### 不同路径 2 这道题目的状态转移方程 + + +### 最长上升子序列(字节跳动、亚马逊、微软在半年内面试中考过) + + +### 解码方法(字节跳动、亚马逊、Facebook 在半年内面试中考过) + + +### 最长有效括号(亚马逊、字节跳动、华为在半年内面试中考过) + + +### 不同的子序列(MathWorks 在半年内面试中考过) + + +### 赛车(谷歌在半年内面试中考过) + + From 334149002676822072fc32dc6b8c7b798fb81a31 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 22 Mar 2021 16:39:17 +0800 Subject: [PATCH 124/210] sliding window --- Week_02/239maxSlidingWindow.js | 35 +++++++++++++++++++++++++++ Week_02/offer59-1.js | 44 ---------------------------------- 2 files changed, 35 insertions(+), 44 deletions(-) create mode 100644 Week_02/239maxSlidingWindow.js delete mode 100644 Week_02/offer59-1.js diff --git a/Week_02/239maxSlidingWindow.js b/Week_02/239maxSlidingWindow.js new file mode 100644 index 00000000..12d5d10b --- /dev/null +++ b/Week_02/239maxSlidingWindow.js @@ -0,0 +1,35 @@ +/** + * https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/ + * https://leetcode-cn.com/problems/sliding-window-maximum/ + * 239. 滑动窗口最大值 + * + * 用 window 记录窗口下标值 + * + */ + +const maxSlidingWindow = function (nums, k) { + if (!Array.isArray(nums) || nums.length < 1 || k < 1) return [] + const res = [], win = [] + for (let i = 0; i < nums.length; ++i) { + if (i >= k && i >= k + win[0]) { // window size + win.shift() + } + while (nums[i] >= nums[win[win.length - 1]]) { // override left elements + win.pop() + } + win.push(i) + if (i >= k - 1) { + res.push(nums[win[0]]) + } + } + return res +} + + +// ---- test case ---- +console.log(maxSlidingWindow([1,3,-1,-3,5,3,6,7], 3)) +console.log(maxSlidingWindow([1], 1)) +console.log(maxSlidingWindow([1,-1], 1)) +console.log(maxSlidingWindow([9,11], 2)) +console.log(maxSlidingWindow([4,-2], 2)) +console.log(maxSlidingWindow([1,3,1,2,0,5], 3)) diff --git a/Week_02/offer59-1.js b/Week_02/offer59-1.js deleted file mode 100644 index 8b1d759f..00000000 --- a/Week_02/offer59-1.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @param {number[]} nums - * @param {number} k - * @return {number[]} - * https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/ - * https://leetcode-cn.com/problems/sliding-window-maximum/ - * 思路1: 暴力求解 - */ -var maxSlidingWindow = function(nums, k) { - if (nums.length < 1 || k < 1) return [] - var res = [], start = 0; - for(var start = 0; start <= nums.length - k; ++start) { - var maxNum = nums[start] - for(var i = start + 1; i <= start + k - 1; ++i) { - maxNum = Math.max(maxNum, nums[i]) - } - res.push(maxNum) - } - return res -}; - -/** - * @param {number[]} nums - * @param {number} k - * @return {number[]} - * 思路2: 用 window 记录当前窗口,如果当前窗口左边有小值,pop掉 - */ -var maxSlidingWindow = function(nums, k) { - if (nums.length < 1 || k < 1) return [] - var res = [], window = [] - nums.forEach((item, idx) => { - if (idx >= k + window[0]) { // 维护窗口 - window.shift() - } - while(window.length > 0 && item > nums[window[window.length - 1]]) { // pop掉“无出头之日”的小值 - window.pop() - } - window.push(idx) // 加入当前值 - if (idx >= k - 1) { // 有效窗口中最左边的值就是最大值 - res.push(nums[window[0]]) - } - }) - return res -}; From 987a929485c0c3f547cc9bc96d4e0fb259faa1c8 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 22 Mar 2021 17:58:54 +0800 Subject: [PATCH 125/210] solve merge --- Week_01/088merge.js | 17 +++++------------ codetop/003lengthOfLongestSubstring.js | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 codetop/003lengthOfLongestSubstring.js diff --git a/Week_01/088merge.js b/Week_01/088merge.js index 0025b534..a7868f8a 100644 --- a/Week_01/088merge.js +++ b/Week_01/088merge.js @@ -5,18 +5,11 @@ */ const merge = function(nums1, m, nums2, n) { - const toS = Object.prototype.toString, ARRTYPE = '[object Array]' - if (toS.call(nums1) !== ARRTYPE || toS.call(nums2) !== ARRTYPE) return - + if (!Array.isArray(nums1) || !Array.isArray(nums2)) return + 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--] - } - } - while(j >= 0) { - nums1[k--] = nums2[j--] + while (i >= 0 && j >= 0) { + nums1[k--] = nums1[i] > nums2[j] ? nums1[i--] : nums2[j--] } + while (j >= 0) nums1[k--] = nums2[j--] } diff --git a/codetop/003lengthOfLongestSubstring.js b/codetop/003lengthOfLongestSubstring.js new file mode 100644 index 00000000..0d9f4d51 --- /dev/null +++ b/codetop/003lengthOfLongestSubstring.js @@ -0,0 +1,26 @@ +/** + * https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/ + * 3. 无重复字符的最长子串 | medium + * + * hashmap + */ + +const lengthOfLongestSubstring = function(s) { + const m = new Map() // 记录字母上一次出现的位置 + let left = 0, max = 0 // left 记录左边界 + for (let i = 0; i < s.length; ++i) { + const ch = s[i] + if (m.has(ch) && m.get(ch) >= left) { // 出现重复,更新 left + left = m.get(ch) + 1 + } + m.set(ch, i) + max = Math.max(max, i - left + 1) + } + return max +} + +// ---- test case ---- +console.log(lengthOfLongestSubstring('abcabcbb')) // 3 +console.log(lengthOfLongestSubstring('bbbbb')) // 1 +console.log(lengthOfLongestSubstring('pwwkew')) // 3 +console.log(lengthOfLongestSubstring('')) // 0 From e2869fecf9e2ba4511d9139734452d4f4821b1f7 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 23 Mar 2021 00:31:33 +0800 Subject: [PATCH 126/210] codetop --- Week_01/015threeSum.js | 20 ++++++------- Week_09/sort-quick.js | 39 ++++++++++++++++++++++++-- codetop/003lengthOfLongestSubstring.js | 3 +- codetop/209minSubArrayLen.js | 25 +++++++++++++++++ codetop/912sortArray.js | 31 ++++++++++++++++++++ codetop/offer022-getKthFromEnd.js | 16 +++++++++++ 6 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 codetop/209minSubArrayLen.js create mode 100644 codetop/912sortArray.js create mode 100644 codetop/offer022-getKthFromEnd.js diff --git a/Week_01/015threeSum.js b/Week_01/015threeSum.js index d652aa6a..26bbac5d 100644 --- a/Week_01/015threeSum.js +++ b/Week_01/015threeSum.js @@ -44,23 +44,23 @@ console.log('solution 1: ', threeSum2([-1, 0, 1, 2, -1, -4])) */ const threeSum = function(nums) { - if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 3) return [] - nums.sort((x, y) => x - y) // O(nlogn) + if (!Array.isArray(nums) || nums.length < 3) return [] + nums.sort((x, y) => x - y) const res = [] - for(let k = 0; k < nums.length - 2; ++k) { - if (nums[k] > 0) break // prun - if (k > 0 && nums[k] === nums[k-1]) continue // unique + for (let k = 0; k < nums.length - 2; ++k) { + if (nums[k] > 0) break + if (k > 0 && nums[k] === nums[k - 1]) continue let l = k + 1, r = nums.length - 1 - while(l < r) { + while (l < r) { const sum = nums[k] + nums[l] + nums[r] if (sum < 0) { - while(l < r && nums[l] === nums[++l]) {} // unique + while (l < r && nums[l] === nums[++l]) {} } else if (sum > 0) { - while(l < r && nums[r] === nums[--r]) {} // unique + while (l < r && nums[r] === nums[--r]) {} } else { res.push([nums[k], nums[l], nums[r]]) - while(l < r && nums[l] === nums[++l]) {} // unique - while(l < r && nums[r] === nums[--r]) {} // unique + while (l < r && nums[l] === nums[++l]) {} + while (l < r && nums[r] === nums[--r]) {} } } } diff --git a/Week_09/sort-quick.js b/Week_09/sort-quick.js index e20c024c..fef04d87 100644 --- a/Week_09/sort-quick.js +++ b/Week_09/sort-quick.js @@ -19,6 +19,39 @@ function partition(arr, left, right) { } // ---- test case ---- -const arr = [3, 2, 32, 45, 767, 234, 66, 32] -quickSort(arr) -console.log(arr) +const arr1 = [5,2,3,1] +quickSort(arr1) +console.log(arr1) + +// const arr2 = [5,1,1,2,0,0] +// quickSort(arr2) +// console.log(arr2) + + + +// var quickSort = function(nums) { +// function quickSortHelper(nums, start, end) { +// if (start >= end) return nums + +// var pivotValue = nums[start] +// var smaller = start +// for (var i = start + 1; i <= end; i++) { +// var bigger = i +// if (nums[bigger] < pivotValue) { +// smaller++ +// var smallerValue = nums[bigger] +// nums[bigger] = nums[smaller] +// nums[smaller] = smallerValue +// } +// } +// var smallerCache = nums[smaller] +// nums[smaller] = nums[start] +// nums[start] = smallerCache + +// quickSortHelper(nums, start, smaller - 1) +// quickSortHelper(nums, smaller + 1, end) +// return nums +// } + +// return quickSortHelper(nums, 0, nums.length - 1) +// }; diff --git a/codetop/003lengthOfLongestSubstring.js b/codetop/003lengthOfLongestSubstring.js index 0d9f4d51..99a29331 100644 --- a/codetop/003lengthOfLongestSubstring.js +++ b/codetop/003lengthOfLongestSubstring.js @@ -1,8 +1,9 @@ /** * https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/ + * https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/ * 3. 无重复字符的最长子串 | medium * - * hashmap + * hashmap + 双指针 */ const lengthOfLongestSubstring = function(s) { diff --git a/codetop/209minSubArrayLen.js b/codetop/209minSubArrayLen.js new file mode 100644 index 00000000..8419dd79 --- /dev/null +++ b/codetop/209minSubArrayLen.js @@ -0,0 +1,25 @@ +/** + * https://leetcode-cn.com/problems/minimum-size-subarray-sum/ + * 209. 长度最小的子数组 | medium + * + * 双指针 + */ + +const minSubArrayLen = function(target, nums) { + let distance = Infinity + let left = 0, sum = 0 + for (let right = 0; right < nums.length; ++right) { + sum += nums[right] + while (sum >= target) { // 缩短 + distance = Math.min(distance, right - left + 1) + sum -= nums[left] + ++left + } + } + return distance === Infinity ? 0 : distance +} + +// ---- test case ---- +console.log(minSubArrayLen(7, [2, 3, 1, 2, 4, 3])) // 2 +console.log(minSubArrayLen(4, [1, 4, 4])) // 1 +console.log(minSubArrayLen(11, [1, 1, 1, 1, 1, 1, 1, 1])) // 0 diff --git a/codetop/912sortArray.js b/codetop/912sortArray.js new file mode 100644 index 00000000..e435b783 --- /dev/null +++ b/codetop/912sortArray.js @@ -0,0 +1,31 @@ +/** + * https://leetcode-cn.com/problems/sort-an-array/ + * 912. 排序数组 | medium + */ + +function quickSort(arr, left = 0, right = arr.length - 1) { + if (left >= right) return + const pivotIdx = partition(arr, left, right) + quickSort(arr, left, pivotIdx - 1) + quickSort(arr, pivotIdx + 1, right) +} + +function partition(arr, left, right) { + const pivot = arr[left] + while (left < right) { + while (left < right && arr[right] >= pivot) --right + if (left < right) arr[left] = arr[right] + while (left < right && arr[left] <= pivot) ++left + if (left < right) arr[right] = arr[left] + } + arr[left] = pivot + return left +} + +function sortArray(arr) { + quickSort(arr, 0, arr.length - 1) + return arr +} + +// ---- test case ---- +console.log(sortArray([5,2,3,1])) diff --git a/codetop/offer022-getKthFromEnd.js b/codetop/offer022-getKthFromEnd.js new file mode 100644 index 00000000..43732919 --- /dev/null +++ b/codetop/offer022-getKthFromEnd.js @@ -0,0 +1,16 @@ +/** + * https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/ + * 剑指 Offer 22. 链表中倒数第k个节点 | easy + * + * linklist、双指针 + */ + +const getKthFromEnd = function(head, k) { + let slow = fast = head + while (--k >= 0) fast = fast.next + while (fast) { + fast = fast.next + slow = slow.next + } + return slow +} From 8680cb400d177c88280d94d0c0a4e5ddc5aefa58 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 23 Mar 2021 11:22:58 +0800 Subject: [PATCH 127/210] solve code top --- Week_01/206reverseList.js | 1 + codetop/019removeNthFromEnd.js | 19 +++++++++++++++++++ codetop/160getIntersectionNode.js | 15 +++++++++++++++ codetop/415addStrings.js | 21 +++++++++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 codetop/019removeNthFromEnd.js create mode 100644 codetop/160getIntersectionNode.js create mode 100644 codetop/415addStrings.js diff --git a/Week_01/206reverseList.js b/Week_01/206reverseList.js index 011ef00a..dba8c129 100644 --- a/Week_01/206reverseList.js +++ b/Week_01/206reverseList.js @@ -1,5 +1,6 @@ /** * https://leetcode-cn.com/problems/reverse-linked-list/ + * https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/submissions/ * 思路:维护好 prev,cur * * @param {ListNode} head diff --git a/codetop/019removeNthFromEnd.js b/codetop/019removeNthFromEnd.js new file mode 100644 index 00000000..52df7e08 --- /dev/null +++ b/codetop/019removeNthFromEnd.js @@ -0,0 +1,19 @@ +/** + * https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/ + * 19. 删除链表的倒数第 N 个结点 | medium + * + */ + +function removeNthFromEnd(head, n) { + let dummy = new ListNode(-1, head) + let fast = slow = dummy + while (n-- >= 0 && fast) { // 先走n+1步 + fast = fast.next + } + while (fast) { + fast = fast.next + slow = slow.next + } + slow.next = slow.next ? slow.next.next : null + return dummy.next +} diff --git a/codetop/160getIntersectionNode.js b/codetop/160getIntersectionNode.js new file mode 100644 index 00000000..93f45b04 --- /dev/null +++ b/codetop/160getIntersectionNode.js @@ -0,0 +1,15 @@ +/** + * https://leetcode-cn.com/problems/intersection-of-two-linked-lists/ + * https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/ + * 160. 相交链表 | easy + * + */ + +function getIntersectionNode(headA, headB) { + let a = headA, b = headB + while (a !== b) { + a = a == null ? headB : a.next + b = b == null ? headA : b.next + } + return a +} diff --git a/codetop/415addStrings.js b/codetop/415addStrings.js new file mode 100644 index 00000000..7d443491 --- /dev/null +++ b/codetop/415addStrings.js @@ -0,0 +1,21 @@ +/** + * https://leetcode-cn.com/problems/add-strings/ + * 415. 字符串相加 | easy + * + */ + +function addStrings(s1, s2) { + const res = [] + let i = s1.length - 1, j = s2.length - 1, carry = 0 + while (i >= 0 || j >= 0 || carry > 0) { + const x = i >= 0 ? Number(s1[i--]) : 0 + const y = j >= 0 ? Number(s2[j--]) : 0 + res.push((x + y + carry) % 10) + carry = Math.floor((x + y + carry) / 10) + } + return res.reverse().join('') +} + +// ---- test case ---- +console.log(addStrings('234', '8498')) +console.log(addStrings('1', '9')) From 84b8e93dc13e1926e72a6215d1dae5cf6538f89d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 23 Mar 2021 12:05:46 +0800 Subject: [PATCH 128/210] solve merge-intervals --- codetop/056merge.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 codetop/056merge.js diff --git a/codetop/056merge.js b/codetop/056merge.js new file mode 100644 index 00000000..a72820f9 --- /dev/null +++ b/codetop/056merge.js @@ -0,0 +1,26 @@ +/** + * https://leetcode-cn.com/problems/merge-intervals/ + * 56. 合并区间 | medium + */ + +function merge(intervals) { + if (!intervals.length) return intervals + intervals.sort((a, b) => a[0] !== b[0] ? a[0] - b[0] : a[1] - b[1]) + let prev = intervals[0] + let res = [prev] + for (var curr of intervals) { + if (curr[0] <= prev[1]) { + prev[1] = Math.max(prev[1], curr[1]) + } else { + res.push(curr) + prev = curr + } + } + return res +} + +// ---- test case ---- +console.log(merge([[1,3],[2,6],[8,10],[15,18]])) +// [[1,6],[8,10],[15,18]] +console.log(merge([[1,4],[4,5]])) +// [[1,5]] From 7a2f30f1fc6fe8dbeee25459703b7ee32aca5e74 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 25 Mar 2021 00:07:17 +0800 Subject: [PATCH 129/210] javascript linkedlist --- .gitignore | 1 + Week_01/README.md | 4 ++ linkedlist/LinkedList.js | 79 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 linkedlist/LinkedList.js diff --git a/.gitignore b/.gitignore index 162304d3..2a802fa8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store note.md +jshandwrite diff --git a/Week_01/README.md b/Week_01/README.md index c4cb027e..cb1d4145 100644 --- a/Week_01/README.md +++ b/Week_01/README.md @@ -5,6 +5,10 @@ > [Java.util.ArrayList](http://developer.classpath.org/doc/java/util/ArrayList-source.html) > [Java.util.LinkedList](http://developer.classpath.org/doc/java/util/LinkedList-source.html) +**手撕代码** + ++ [JavaScript版实现单向链表](../linkedlist/LinkedList.js) + **时间复杂度** 备注:skiplist 是有序的,实现简单,维护成本较高,空间复杂度O(n)。 diff --git a/linkedlist/LinkedList.js b/linkedlist/LinkedList.js new file mode 100644 index 00000000..9193db63 --- /dev/null +++ b/linkedlist/LinkedList.js @@ -0,0 +1,79 @@ +// JavaScript 实现一个单向链表 +class ListNode { + constructor (val, next) { + this.val = val == null ? 0 : val + this.next = next == null ? null : next + } +} + +class LinkedList { + constructor () { + this.dummyHead = new ListNode('head') + } + append (val) { + let node = this.dummyHead + while (node && node.next) { + node = node.next + } + node.next = new ListNode(val) + return this + } + delete (val) { + let prev = this.dummyHead + while (prev && prev.next && prev.next.val != val) { + prev = prev.next + } + prev.next = prev.next.next + return this + } + reverse () { + let prev = null + let node = this.dummyHead.next + while (node) { + const curr = node + node = node.next + curr.next = prev + prev = curr + } + this.dummyHead.next = prev + return this + } + get size() { + let cnt = 0 + let node = this.dummyHead.next + while (node) { + ++cnt + node = node.next + } + return cnt + } + display() { + let node = this.dummyHead.next + const res = [] + while (node) { + res.push(node.val) + node = node.next + } + console.log(res.join(' -> ')) + return this + } +} + +// ---- test case ---- +let link = new LinkedList() +link.display() // '' + .append(1) + .display() // 1 + .append(2) + .append(3) + .append(4) + .append(5) + .delete(5) + .delete(2) + .display() // 1 -> 3 -> 4 + .reverse() + .display() // 4 -> 3 -> 1 + .reverse() + .display() // 1 -> 3 -> 4 + +console.log(link.size) From 12efd82266c006f0bb40780589f08cd55a602c63 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 25 Mar 2021 23:15:17 +0800 Subject: [PATCH 130/210] js >>> --- README.md | 8 +++++ Week_08/190reverseBits.js | 25 +++++++++++++ Week_08/README.md | 14 ++++++++ linkedlist/021mergeTwoLists.js | 35 ++++++++++++++++++ linkedlist/141hasCycle.js | 28 +++++++++++++++ linkedlist/160getIntersectionNode.js | 15 ++++++++ linkedlist/206reverseList.js | 36 +++++++++++++++++++ linkedlist/LinkedList.js | 54 ++++++++++++++++++---------- 8 files changed, 196 insertions(+), 19 deletions(-) create mode 100644 Week_08/190reverseBits.js create mode 100644 linkedlist/021mergeTwoLists.js create mode 100644 linkedlist/141hasCycle.js create mode 100644 linkedlist/160getIntersectionNode.js create mode 100644 linkedlist/206reverseList.js diff --git a/README.md b/README.md index 5ee18f64..69c5118c 100644 --- a/README.md +++ b/README.md @@ -1 +1,9 @@ # 算法训练 + +## 链表系列 + ++ [单向链表实现](./linkedlist/LinkedList.js) ++ [反转链表](./linkedlist/206reverseList.js) ++ [合并两个有序链表](./linkedlist/021mergeTwoLists.js) ++ [环形链表](./linkedlist/141hasCycle.js) ++ [相交链表](./linkedlist/160getIntersectionNode.js) diff --git a/Week_08/190reverseBits.js b/Week_08/190reverseBits.js new file mode 100644 index 00000000..7cf24c4f --- /dev/null +++ b/Week_08/190reverseBits.js @@ -0,0 +1,25 @@ +/** + * https://leetcode-cn.com/problems/reverse-bits/ + * 190. 颠倒二进制位 + */ +function reverseBits(n) { + let res = 0, loops = 32 + while (--loops >= 0) { + res = (res << 1) + (n & 1) + n = n >> 1 + } + return res >>> 0 // 无符号右移 +} + +// ---- test case ---- +let str1 = '00000010100101000001111010011100' +let str2 = '11111111111111111111111111111101' +let ret1 = reverseBits(parseInt(str1, 2)) +let ret2 = reverseBits(parseInt(str2, 2)) + +console.log(str1) +console.log(ret1.toString(2).padStart(32, '0')) + + +console.log(str2) +console.log(ret2.toString(2)) diff --git a/Week_08/README.md b/Week_08/README.md index 166cccb6..0755a015 100644 --- a/Week_08/README.md +++ b/Week_08/README.md @@ -2,9 +2,23 @@ ## 第 14 课 | 字典树和并查集 +**并查集** + ++ makeSet(s) 建立一个新的并查集 ++ unionSet(x, y) 把元素 x 和元素 y 所在的集合合并,要求x和y所在的集合不相交,如果相交则不合并 ++ find(x) 找到x所在的集合的代表。该操作也用来判断两个元素是否位于同一个集合 ## 第 15 课 | 红黑树和AVL树 +**平衡二叉搜索树** + +**AVL树** + +1. 发明人:G.M.Adelson-Velsky 和 Evgenii Landis +2. 平衡因子 Balance Factor + - 左子树的高度减去右子树的高度(有时相反) + - balance factor = {-1, 0, 1} +3. 通过旋转获得平衡 ## 第 16 课 | 位运算 diff --git a/linkedlist/021mergeTwoLists.js b/linkedlist/021mergeTwoLists.js new file mode 100644 index 00000000..8f65060c --- /dev/null +++ b/linkedlist/021mergeTwoLists.js @@ -0,0 +1,35 @@ +/** + * https://leetcode-cn.com/problems/merge-two-sorted-lists/ + * 21. 合并两个有序链表 | easy + */ + +const { ListNode, LinkedList } = require('./LinkedList.js') + +function mergeTwoLists(l1, l2) { + const dummy = new ListNode() + let curr = dummy + while (l1 && l2) { + if (l1.val < l2.val) { + curr.next = l1 + l1 = l1.next + } else { + curr.next = l2 + l2 = l2.next + } + curr = curr.next + } + curr.next = l1 || l2 + return dummy.next +} + + +// ---- test case ---- +let l1 = new LinkedList() +let l2 = new LinkedList() + +l1.append(1).append(2).append(4) +l2.append(1).append(3).append(4) + +let ret = mergeTwoLists(l1.head, l2.head) +let l3 = new LinkedList(ret) +l3.display() diff --git a/linkedlist/141hasCycle.js b/linkedlist/141hasCycle.js new file mode 100644 index 00000000..f4fb68c4 --- /dev/null +++ b/linkedlist/141hasCycle.js @@ -0,0 +1,28 @@ +/** + * https://leetcode-cn.com/problems/linked-list-cycle/ + * + * 141. 环形链表 | easy + * + */ + +const { ListNode, LinkedList } = require('./LinkedList.js') + +function hasCycle(head) { + let fast = slow = head + while (fast && fast.next && slow) { + fast = fast.next.next + slow = slow.next + if (fast == slow) return true + } + return false +} + +// ---- test case ---- +var link = new LinkedList() +link.append(3) + .append(2) + .append(0) + .append(4) + .display() + +console.log(hasCycle(link.head)) diff --git a/linkedlist/160getIntersectionNode.js b/linkedlist/160getIntersectionNode.js new file mode 100644 index 00000000..0ddc73c0 --- /dev/null +++ b/linkedlist/160getIntersectionNode.js @@ -0,0 +1,15 @@ +/** + * https://leetcode-cn.com/problems/intersection-of-two-linked-lists/ + * https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/ + * 160. 相交链表 | easy + * + */ + +const { ListNode, LinkedList } = require('./LinkedList.js') + +function getIntersectionNode(headA, headB) { + +} + +// ---- test case ---- + diff --git a/linkedlist/206reverseList.js b/linkedlist/206reverseList.js new file mode 100644 index 00000000..479629ff --- /dev/null +++ b/linkedlist/206reverseList.js @@ -0,0 +1,36 @@ +/** + * https://leetcode-cn.com/problems/reverse-linked-list/ + * + * 206. 反转链表 + */ +const { ListNode, LinkedList } = require('./LinkedList.js') + + +function reverseList(head) { + let prev = null + while (head) { + const curr = head + head = head.next + curr.next = prev + prev = curr + } + return prev +} + +// ---- test case ---- +let link = new LinkedList() + +link.append(1) + .append(2) + .append(3) + .append(4) + .append(5) + .display() + +link.head = reverseList(link.head) + +link.display() + +link.head = reverseList(link.head) + +link.display() diff --git a/linkedlist/LinkedList.js b/linkedlist/LinkedList.js index 9193db63..e67f3522 100644 --- a/linkedlist/LinkedList.js +++ b/linkedlist/LinkedList.js @@ -7,9 +7,10 @@ class ListNode { } class LinkedList { - constructor () { - this.dummyHead = new ListNode('head') + constructor (head = null) { + this.dummyHead = new ListNode('head', head) } + // 末尾追加节点 append (val) { let node = this.dummyHead while (node && node.next) { @@ -18,6 +19,7 @@ class LinkedList { node.next = new ListNode(val) return this } + // 删除第一个值为 val 的节点 delete (val) { let prev = this.dummyHead while (prev && prev.next && prev.next.val != val) { @@ -26,6 +28,7 @@ class LinkedList { prev.next = prev.next.next return this } + // 反转链表 reverse () { let prev = null let node = this.dummyHead.next @@ -38,6 +41,7 @@ class LinkedList { this.dummyHead.next = prev return this } + // 获取链表长度 get size() { let cnt = 0 let node = this.dummyHead.next @@ -47,6 +51,15 @@ class LinkedList { } return cnt } + // 获取链表头节点 + get head() { + return this.dummyHead.next + } + // 设置新的头节点 + set head(newHead) { + this.dummyHead.next = newHead + } + // 显示链表 display() { let node = this.dummyHead.next const res = [] @@ -59,21 +72,24 @@ class LinkedList { } } -// ---- test case ---- -let link = new LinkedList() -link.display() // '' - .append(1) - .display() // 1 - .append(2) - .append(3) - .append(4) - .append(5) - .delete(5) - .delete(2) - .display() // 1 -> 3 -> 4 - .reverse() - .display() // 4 -> 3 -> 1 - .reverse() - .display() // 1 -> 3 -> 4 +// // ---- test case ---- +// let link = new LinkedList() +// link.display() // '' +// .append(1) +// .display() // 1 +// .append(2) +// .append(3) +// .append(4) +// .append(5) +// .delete(5) +// .delete(2) +// .display() // 1 -> 3 -> 4 +// .reverse() +// .display() // 4 -> 3 -> 1 +// .reverse() +// .display() // 1 -> 3 -> 4 + +// console.log(link.size) -console.log(link.size) +// ---- export ---- +module.exports = { ListNode, LinkedList } From 61228bb9b9a3b0fd318f694045cb36df864480a7 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 28 Mar 2021 15:21:00 +0800 Subject: [PATCH 131/210] add template for week8 --- Week_08/051solveNQueens.js | 16 ++++++++++ Week_08/052totalNQueens.js | 12 ++++++++ Week_08/130solve.js | 11 +++++++ Week_08/191hammingWeight.js | 14 +++++++++ Week_08/200numIslands.js | 27 +++++++++++++++++ Week_08/231isPowerOfTwo.js | 9 ++++++ Week_08/547findCircleNum.js | 9 ++++++ Week_08/README.md | 14 ++++++++- Week_08/homework.md | 60 +++++++++++++++++++++++++++---------- 9 files changed, 156 insertions(+), 16 deletions(-) create mode 100644 Week_08/051solveNQueens.js create mode 100644 Week_08/052totalNQueens.js create mode 100644 Week_08/130solve.js create mode 100644 Week_08/191hammingWeight.js create mode 100644 Week_08/200numIslands.js create mode 100644 Week_08/231isPowerOfTwo.js create mode 100644 Week_08/547findCircleNum.js diff --git a/Week_08/051solveNQueens.js b/Week_08/051solveNQueens.js new file mode 100644 index 00000000..3058969f --- /dev/null +++ b/Week_08/051solveNQueens.js @@ -0,0 +1,16 @@ +/** + * https://leetcode-cn.com/problems/n-queens/ + * 51. N 皇后 | hard + * + */ + +function solveNQueens(n) { + +} + +// ---- test case ---- +// console.log(buildResultsBoard([ +// [1, 3, 0, 2], +// [2, 0, 3, 1], +// ], 4)) +console.log(solveNQueens(4)) diff --git a/Week_08/052totalNQueens.js b/Week_08/052totalNQueens.js new file mode 100644 index 00000000..bc310b1c --- /dev/null +++ b/Week_08/052totalNQueens.js @@ -0,0 +1,12 @@ +/** + * https://leetcode-cn.com/problems/n-queens-ii/ + * 52. N皇后 II | hard + * + */ + +function totalNQueens(n) { + +} + +// ---- test case ---- +console.log(totalNQueens(4)) diff --git a/Week_08/130solve.js b/Week_08/130solve.js new file mode 100644 index 00000000..c9704036 --- /dev/null +++ b/Week_08/130solve.js @@ -0,0 +1,11 @@ +/** + * https://leetcode-cn.com/problems/surrounded-regions/ + * 130. 被围绕的区域 | medium + * + */ + +function solve(A) { + +} + +// ---- test case ---- diff --git a/Week_08/191hammingWeight.js b/Week_08/191hammingWeight.js new file mode 100644 index 00000000..ff7ec2e9 --- /dev/null +++ b/Week_08/191hammingWeight.js @@ -0,0 +1,14 @@ +/** + * https://leetcode-cn.com/problems/number-of-1-bits/ + * 191. 位1的个数 + * + */ + +function hammingWeight(n) { + +} + +// ---- test case ---- +console.log(hammingWeight('00000000000000000000000000001011')) // 3 +console.log(hammingWeight('00000000000000000000000010000000')) // 1 +console.log(hammingWeight('11111111111111111111111111111101')) // 31 diff --git a/Week_08/200numIslands.js b/Week_08/200numIslands.js new file mode 100644 index 00000000..62344a66 --- /dev/null +++ b/Week_08/200numIslands.js @@ -0,0 +1,27 @@ +/** + * https://leetcode-cn.com/problems/number-of-islands/ + * 200. 岛屿数量 | medium + * + */ + +function numIslands(A) { + +} + + +// ---- test case ---- +const grid1 = [ + ['1', '1', '1', '1', '0'], + ['1', '1', '0', '1', '0'], + ['1', '1', '0', '0', '0'], + ['0', '0', '0', '0', '0'], +] +const grid2 = [ + ['1', '1', '0', '0', '0'], + ['1', '1', '0', '0', '0'], + ['0', '0', '1', '0', '0'], + ['0', '0', '0', '1', '1'], +] +console.log(numIslands(grid1)) +console.log(numIslands(grid2)) +console.log(numIslands([[]])) diff --git a/Week_08/231isPowerOfTwo.js b/Week_08/231isPowerOfTwo.js new file mode 100644 index 00000000..d1f85181 --- /dev/null +++ b/Week_08/231isPowerOfTwo.js @@ -0,0 +1,9 @@ +/** + * https://leetcode-cn.com/problems/power-of-two/ + * 231. 2的幂 + * + */ + +function isPowerOfTwo(n) { + +} diff --git a/Week_08/547findCircleNum.js b/Week_08/547findCircleNum.js new file mode 100644 index 00000000..de3ab8b2 --- /dev/null +++ b/Week_08/547findCircleNum.js @@ -0,0 +1,9 @@ +/** + * https://leetcode-cn.com/problems/number-of-provinces/ + * 547. 省份数量 | medium + * + */ + +function findCircleNum(isConnected) { + +} diff --git a/Week_08/README.md b/Week_08/README.md index 0755a015..2b880609 100644 --- a/Week_08/README.md +++ b/Week_08/README.md @@ -22,4 +22,16 @@ ## 第 16 课 | 位运算 - ++ | 按位或 ++ & 按位与 ++ ~ 按位取反 ++ ^ 按位异或 + +**trick** + +1. 把 x 最右边的 n 位清零:x & (~0 << n) +2. 获取 x 的第 n 位值:(x >> n) & 1 +3. 获取 x 的第 n 位幂值:x & (1 << n) +4. 把 x 的第 n 位置 1:x | (1 << n) +5. 把 x 的第 n 位置 0:x & (~(1 << n)) +6. 把 x 的最高位到第n位(含)清零:x & ((1 << n) - 1) diff --git a/Week_08/homework.md b/Week_08/homework.md index ace949bf..1aa5627d 100644 --- a/Week_08/homework.md +++ b/Week_08/homework.md @@ -1,17 +1,47 @@ # 作业 -简单 -位 1 的个数(Facebook、苹果在半年内面试中考过) -2 的幂(谷歌、亚马逊、苹果在半年内面试中考过) -颠倒二进制位(苹果在半年内面试中考过) - -中等 -实现 Trie (前缀树) (亚马逊、微软、谷歌在半年内面试中考过) -省份数量(亚马逊、Facebook、字节跳动在半年内面试中考过) -岛屿数量(近半年内,亚马逊在面试中考查此题达到 361 次) -被围绕的区域(亚马逊、eBay、谷歌在半年内面试中考过) - -困难 -单词搜索 II (亚马逊、微软、苹果在半年内面试中考过) -N 皇后(字节跳动、亚马逊、百度在半年内面试中考过) -N 皇后 II (亚马逊在半年内面试中考过) +## 第 14 课 | 字典树和并查集 + +### 实现 Trie (前缀树) (亚马逊、微软、谷歌在半年内面试中考过) + ++ [代码](./208trie.js) + +### 省份数量(亚马逊、Facebook、字节跳动在半年内面试中考过) + ++ [代码](./547findCircleNum.js) + +### 岛屿数量(近半年内,亚马逊在面试中考查此题达到 361 次) + ++ [代码](./200numIslands.js) + +### 被围绕的区域(亚马逊、eBay、谷歌在半年内面试中考过) + ++ [代码](./130solve.js) + + + +## 第 16 课 | 位运算 + +### 位 1 的个数(Facebook、苹果在半年内面试中考过) + ++ [代码](./191hammingWeight.js) + +### 2 的幂(谷歌、亚马逊、苹果在半年内面试中考过) + ++ [代码](./231isPowerOfTwo.js) + +### 颠倒二进制位(苹果在半年内面试中考过) + ++ [代码](./190reverseBits.js) + +### 单词搜索 II (亚马逊、微软、苹果在半年内面试中考过) + ++ [代码](./212findWords.js) + +### N 皇后(字节跳动、亚马逊、百度在半年内面试中考过) + ++ [代码](./051solveNQueens.js) + +### N 皇后 II (亚马逊在半年内面试中考过) + ++ [代码](./052totalNQueens.js) From 33eb2d5908db7d337258458ffe309353abd57043 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 28 Mar 2021 22:15:00 +0800 Subject: [PATCH 132/210] solve everyday task --- Week_09/1112relativeSortArray.js | 25 +++++++++++++++++++++ Week_09/718findLength.js | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 Week_09/1112relativeSortArray.js create mode 100644 Week_09/718findLength.js diff --git a/Week_09/1112relativeSortArray.js b/Week_09/1112relativeSortArray.js new file mode 100644 index 00000000..4f38f000 --- /dev/null +++ b/Week_09/1112relativeSortArray.js @@ -0,0 +1,25 @@ +/** + * https://leetcode-cn.com/problems/relative-sort-array/ + * 1122. 数组的相对排序 + * + */ + +// hashmap + Array.prototype.sort() +function relativeSortArray(arr1, arr2) { + const lookup = new Map() + const N = arr2.length + arr2.forEach((item, idx) => { + lookup.set(item, idx) + }) + return arr1.sort((x, y) => { + x = lookup.has(x) ? lookup.get(x) : N + x + y = lookup.has(y) ? lookup.get(y) : N + y + return x - y + }) +} + +// ---- test case ---- +var arr1 = [2,3,1,3,2,4,6,7,9,2,19] +var arr2 = [2,1,4,3,9,6] +console.log(relativeSortArray(arr1, arr2)) +console.log(arr1) diff --git a/Week_09/718findLength.js b/Week_09/718findLength.js new file mode 100644 index 00000000..ff1a6a7d --- /dev/null +++ b/Week_09/718findLength.js @@ -0,0 +1,38 @@ +/** + * https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/ + * 718. 最长重复子数组 | easy + * + * dp + * if (A[i] === B[j]) { + * f(i, j) = f(i-1, j-1) + 1 + * } else { + * f(i, j) = 0 + * } + */ + +function findLength(A, B) { + if (A.length < 1 || B.length < 1) return 0 + const m = A.length, n = B.length + const dp = Array(m).fill(0).map( + _ => Array(n).fill(0) + ) + let max = 0 + + for (let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + if (A[i] === B[j]) { + if (i === 0 || j === 0) { + dp[i][j] = 1 + } else { + dp[i][j] = dp[i - 1][j - 1] + 1 + } + max = Math.max(max, dp[i][j]) + } + } + } + // console.log(dp) + return max +} + +// ---- test case ---- +console.log(findLength([1,2,3,2,1], [3,2,1,4,7])) From f76191acdbac03db6973999fd5584740c5565e47 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 28 Mar 2021 23:12:33 +0800 Subject: [PATCH 133/210] bits --- Week_08/051solveNQueens.js | 4 ---- Week_08/052totalNQueens.js | 1 + Week_08/190reverseBits.js | 2 ++ Week_08/191hammingWeight.js | 21 +++++++++++++++++---- Week_08/231isPowerOfTwo.js | 9 ++++++++- Week_08/338countBits.js | 16 ++++++++++++++++ Week_08/homework.md | 19 ++++++++++++------- 7 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 Week_08/338countBits.js diff --git a/Week_08/051solveNQueens.js b/Week_08/051solveNQueens.js index 3058969f..fb54723f 100644 --- a/Week_08/051solveNQueens.js +++ b/Week_08/051solveNQueens.js @@ -9,8 +9,4 @@ function solveNQueens(n) { } // ---- test case ---- -// console.log(buildResultsBoard([ -// [1, 3, 0, 2], -// [2, 0, 3, 1], -// ], 4)) console.log(solveNQueens(4)) diff --git a/Week_08/052totalNQueens.js b/Week_08/052totalNQueens.js index bc310b1c..1e337d81 100644 --- a/Week_08/052totalNQueens.js +++ b/Week_08/052totalNQueens.js @@ -5,6 +5,7 @@ */ function totalNQueens(n) { + if (n < 1) return 0 } diff --git a/Week_08/190reverseBits.js b/Week_08/190reverseBits.js index 7cf24c4f..ea28bde9 100644 --- a/Week_08/190reverseBits.js +++ b/Week_08/190reverseBits.js @@ -2,6 +2,8 @@ * https://leetcode-cn.com/problems/reverse-bits/ * 190. 颠倒二进制位 */ + +// O(logn), 每次把最低位挪给 res function reverseBits(n) { let res = 0, loops = 32 while (--loops >= 0) { diff --git a/Week_08/191hammingWeight.js b/Week_08/191hammingWeight.js index ff7ec2e9..7cceb402 100644 --- a/Week_08/191hammingWeight.js +++ b/Week_08/191hammingWeight.js @@ -4,11 +4,24 @@ * */ +// 清除末位零 n & (n - 1) function hammingWeight(n) { - + let cnt = 0 + while (n !== 0) { + // console.log("🚀", (n >>> 0).toString(2)) + n = n & (n - 1) + ++cnt + } + return cnt } // ---- test case ---- -console.log(hammingWeight('00000000000000000000000000001011')) // 3 -console.log(hammingWeight('00000000000000000000000010000000')) // 1 -console.log(hammingWeight('11111111111111111111111111111101')) // 31 +console.log(hammingWeight( + parseInt('00000000000000000000000000001011', 2) +)) // 3 +console.log(hammingWeight( + parseInt('00000000000000000000000010000000', 2) +)) // 1 +console.log(hammingWeight( + parseInt('11111111111111111111111111111101', 2) +)) // 31 diff --git a/Week_08/231isPowerOfTwo.js b/Week_08/231isPowerOfTwo.js index d1f85181..51c332c9 100644 --- a/Week_08/231isPowerOfTwo.js +++ b/Week_08/231isPowerOfTwo.js @@ -4,6 +4,13 @@ * */ +// 清除末位零 n & (n - 1) function isPowerOfTwo(n) { - + return n > 0 && (n & (n - 1)) === 0 } + +// ---- test case ---- +console.log(isPowerOfTwo(1)) +console.log(isPowerOfTwo(16)) +console.log(isPowerOfTwo(1024)) +console.log(isPowerOfTwo(294)) diff --git a/Week_08/338countBits.js b/Week_08/338countBits.js new file mode 100644 index 00000000..360ecd97 --- /dev/null +++ b/Week_08/338countBits.js @@ -0,0 +1,16 @@ +/** + * https://leetcode-cn.com/problems/counting-bits/ + * 338. 比特位计数 | medium + */ + +function countBits(n) { + const bits = Array(n + 1).fill(0) + for (let i = 1; i <= n; ++i) { + bits[i] = bits[i >> 1] + (i & 1) + } + return bits +} + +// ---- test case ---- +console.log(countBits(2)) +console.log(countBits(5)) diff --git a/Week_08/homework.md b/Week_08/homework.md index 1aa5627d..691dd7b0 100644 --- a/Week_08/homework.md +++ b/Week_08/homework.md @@ -4,18 +4,27 @@ ### 实现 Trie (前缀树) (亚马逊、微软、谷歌在半年内面试中考过) ++ trie树 + [代码](./208trie.js) -### 省份数量(亚马逊、Facebook、字节跳动在半年内面试中考过) +### 单词搜索 II (亚马逊、微软、苹果在半年内面试中考过) + ++ trie树 ++ [代码](./212findWords.js) + +### TODO 省份数量(亚马逊、Facebook、字节跳动在半年内面试中考过) ++ UnionFind + [代码](./547findCircleNum.js) -### 岛屿数量(近半年内,亚马逊在面试中考查此题达到 361 次) +### TODO 岛屿数量(近半年内,亚马逊在面试中考查此题达到 361 次) ++ UnionFind + [代码](./200numIslands.js) -### 被围绕的区域(亚马逊、eBay、谷歌在半年内面试中考过) +### TODO 被围绕的区域(亚马逊、eBay、谷歌在半年内面试中考过) ++ UnionFind + [代码](./130solve.js) @@ -34,10 +43,6 @@ + [代码](./190reverseBits.js) -### 单词搜索 II (亚马逊、微软、苹果在半年内面试中考过) - -+ [代码](./212findWords.js) - ### N 皇后(字节跳动、亚马逊、百度在半年内面试中考过) + [代码](./051solveNQueens.js) From 9973523406bd4dd47640468ed2195e6e3fe2fd03 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 29 Mar 2021 00:06:09 +0800 Subject: [PATCH 134/210] solve N queens with bitmask --- Week_08/051solveNQueens.js | 49 ++++++++++++++++++++++++++++++++++++++ Week_08/052totalNQueens.js | 30 +++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/Week_08/051solveNQueens.js b/Week_08/051solveNQueens.js index fb54723f..e2374bf7 100644 --- a/Week_08/051solveNQueens.js +++ b/Week_08/051solveNQueens.js @@ -4,8 +4,57 @@ * */ +function buildResult (res, n) { + const m = new Map() + const graphes = [] + res.forEach(state => { + const graph = [] + state.forEach(bit => { + let lineStr = '' + for (let i = 0; i < n; ++i) { + const lastBit = bit & 1 + bit = bit >> 1 + lineStr = (lastBit ? 'Q' : '.') + lineStr + } + graph.push(lineStr) + }) + graphes.push(graph) + }) + return graphes +} + function solveNQueens(n) { + if (n < 1) return [] + + /** + * DFS + * @param {number} row 当前遍历到第几行 + * @param {number} col 不能用的列 + * @param {number} pie 不能用的撇 + * @param {number} na 不能用的捺 + * 副作用:修改 res + */ + const dfs = (row, col, pie, na, state) => { + if (row >= n) { + res.push(state) + return + } + let bits = (~(col | pie | na)) & ((1 << n) - 1) // 取得所有得空位 + while (bits) { + const pos = bits & (-bits) // 最低可用位 + // console.log("🚀", + // bits.toString(2).padStart(4, '0'), + // pos.toString(2).padStart(4, '0') + // ) + bits = bits & (bits - 1) + dfs(row + 1, col | pos, (pie | pos) << 1, (na | pos) >> 1, state.concat([pos])) + } + } + let res = [] + dfs(0, 0, 0, 0, []) + // console.log("🚀🚀🚀", res) + return buildResult(res, n) } // ---- test case ---- diff --git a/Week_08/052totalNQueens.js b/Week_08/052totalNQueens.js index 1e337d81..a5dc1bf4 100644 --- a/Week_08/052totalNQueens.js +++ b/Week_08/052totalNQueens.js @@ -4,9 +4,39 @@ * */ +// 位运算 function totalNQueens(n) { if (n < 1) return 0 + /** + * DFS + * @param {number} row 当前遍历到第几行 + * @param {number} col 不能用的列 + * @param {number} pie 不能用的撇 + * @param {number} na 不能用的捺 + * 副作用:修改 cnt 值 + */ + const dfs = (row, col, pie, na) => { + if (row >= n) { + ++cnt + console.log("🚀🚀🚀", col, pie, na) + return + } + let bits = (~(col | pie | na)) & ((1 << n) - 1) // 取得所有得空位 + while (bits) { + const pos = bits & (-bits) // 最低可用位 + console.log("🚀", + bits.toString(2).padStart(4, '0'), + pos.toString(2).padStart(4, '0') + ) + bits = bits & (bits - 1) + dfs(row + 1, col | pos, (pie | pos) << 1, (na | pos) >> 1) + } + } + + let cnt = 0 + dfs(0, 0, 0, 0) + return cnt } // ---- test case ---- From bd7f07d53dc5b68ddba0b905dc07c00dba87ade5 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 31 Mar 2021 16:16:53 +0800 Subject: [PATCH 135/210] everyday --- Week_01/541reverseStr.js | 15 ++++--- .../387firstUniqChar.js" | 44 +++++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/387firstUniqChar.js" diff --git a/Week_01/541reverseStr.js b/Week_01/541reverseStr.js index 0213f74b..8fda28ff 100644 --- a/Week_01/541reverseStr.js +++ b/Week_01/541reverseStr.js @@ -2,17 +2,20 @@ * https://leetcode-cn.com/problems/reverse-string-ii/ */ -const reverseStr = function(s, k) { - const swap = function (arr, i, j) { +function swap(arr, i, j) { + if (i !== j) { const tmp = arr[i] arr[i] = arr[j] arr[j] = tmp } +} + +function reverseStr(s, k) { const arr = s.split('') - for(let i = 0; i < arr.length; i += 2 * k) { - let start = i, end = Math.min(i + k - 1, arr.length - 1) - // console.log("🚀", start, end) - while(start < end) { + for (let i = 0; i < s.length; i += 2 * k) { + let start = i + let end = Math.min(i + k - 1, arr.length - 1) + while (start < end) { swap(arr, start++, end--) } } diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/387firstUniqChar.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/387firstUniqChar.js" new file mode 100644 index 00000000..f30c3206 --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/387firstUniqChar.js" @@ -0,0 +1,44 @@ +/** + * https://leetcode-cn.com/problems/first-unique-character-in-a-string/ + * 387. 字符串中的第一个唯一字符 + */ + +// O(n^2) O(1) +function firstUniqChar1(s) { + for (let i = 0; i < s.length; ++i) { + if (s.lastIndexOf(s[i]) === s.indexOf(s[i])) { + return i + } + } + return -1 +} + +// array存字母位置 +// O(n) O(26) +function firstUniqChar(s) { + const positions = Array(26) // 默认为 empty + const pos0 = 'a'.codePointAt(0) + for (let i = 0; i < s.length; ++i) { + const chIdx = s.codePointAt(i) - pos0 + if (positions[chIdx] >= 0) { // 该字符出现过 + positions[chIdx] = -1 // 标记为-1 + } else if (positions[chIdx] !== -1) { // 字符没出现过 + positions[chIdx] = i + } + } + let minPos = s.length + for (let i = 0; i < positions.length; ++i) { + if (positions[i] >= 0 && minPos > positions[i]) { + minPos = positions[i] + } + } + return minPos === s.length ? -1 : minPos +} + + + +// ---- test case ---- +console.log(firstUniqChar('aadadaad')) // -1 +console.log(firstUniqChar('aabb')) // -1 +console.log(firstUniqChar('leetcode')) // 0 +console.log(firstUniqChar('loveleetcode'))// 2 From 63d0936f136365d09a5de15f9323f45ed491e586 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 1 Apr 2021 01:01:18 +0800 Subject: [PATCH 136/210] findKthLargest --- Week_01/021mergeTwoLists.js | 21 +++++++++----------- Week_09/README.md | 3 --- codetop/215findKthLargest.js | 36 ++++++++++++++++++++++++++++++++++ codetop/678checkValidString.js | 19 ++++++++++++++++++ 4 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 codetop/215findKthLargest.js create mode 100644 codetop/678checkValidString.js diff --git a/Week_01/021mergeTwoLists.js b/Week_01/021mergeTwoLists.js index b6644621..fe14876c 100644 --- a/Week_01/021mergeTwoLists.js +++ b/Week_01/021mergeTwoLists.js @@ -8,22 +8,19 @@ * 思路: 类似归并排序的归并过程 * 思路: 声明一个空指针头,遍历l1 和 l2,谁的值比较小就把谁拼接在后面 */ -var mergeTwoLists = function (l1, l2) { - var dummy = { - val: -1, - next: null - }, - cur = dummy +function mergeTwoLists(l1, l2) { + const dummy = new ListNode(-1) + let p = dummy while (l1 && l2) { - if (l1.val < l2.val) { - cur.next = l1 + if (l1.val <= l2.val) { + p.next = l1 l1 = l1.next } else { - cur.next = l2 + p.next = l2 l2 = l2.next } - cur = cur.next + p = p.next } - cur.next = l1 || l2 + p.next = l1 || l2 return dummy.next -}; +} diff --git a/Week_09/README.md b/Week_09/README.md index 301b7bcb..01b3d06c 100644 --- a/Week_09/README.md +++ b/Week_09/README.md @@ -48,6 +48,3 @@ ## 第 19 课 | 高级动态规划 - -## 第 20 课 | 字符串算法 - diff --git a/codetop/215findKthLargest.js b/codetop/215findKthLargest.js new file mode 100644 index 00000000..e546e7cc --- /dev/null +++ b/codetop/215findKthLargest.js @@ -0,0 +1,36 @@ +/** + * https://leetcode-cn.com/problems/kth-largest-element-in-an-array/ + * 215. 数组中的第K个最大元素 | medium + */ + +function partition(arr, left, right) { + const pivot = arr[left] + while (left < right) { + while (left < right && arr[right] >= pivot) --right + if (left < right) arr[left] = arr[right] + while (left < right && arr[left] <= pivot) ++left + if (left < right) arr[right] = arr[left] + } + arr[left] = pivot + return left +} + +function findKthLargest(arr, k, l = 0, r = arr.length - 1) { + // console.log("🚀", arr, k, l, r) + if (l === r) return arr[l] + const pivotIdx = partition(arr, l, r) + if (pivotIdx === r + 1 - k) { + return arr[pivotIdx] + } else if (pivotIdx < r + 1 - k) { // 继续在右边找 + return findKthLargest(arr, k, pivotIdx + 1, r) + } else { // 在左边找 + return findKthLargest(arr, k - (r - pivotIdx + 1), l, pivotIdx - 1) + } +} + +// ---- test case ---- +console.log(findKthLargest([3,2,1,5,6,4], 2)) // 5 +console.log(findKthLargest([3,2,3,1,2,4,5,5,6], 4)) // 4 +console.log(findKthLargest([2, 1], 2)) // 1 +console.log(findKthLargest([7,6,5,4,3,2,1], 2)) // 6 +console.log(findKthLargest([7,6,5,4,3,2,1], 5)) // 3 diff --git a/codetop/678checkValidString.js b/codetop/678checkValidString.js new file mode 100644 index 00000000..d565ae76 --- /dev/null +++ b/codetop/678checkValidString.js @@ -0,0 +1,19 @@ +/** + * https://leetcode-cn.com/problems/valid-parenthesis-string/ + * 678. 有效的括号字符串 | medium + */ + +// 贪心法,双向遍历,检查是否有不匹配括号 +function checkValidString(s) { + let left = 0, right = 0, n = s.length + for (let i = 0; i < n; ++i) { + left += s[i] === ')' ? -1 : 1 + right += s[n - i - 1] === '(' ? -1 : 1 + if (left < 0 || right < 0) return false + } + return true +} + +// ---- test case ---- +console.log(checkValidString('(*))')) +console.log(checkValidString('(')) From 129907d62dd6d8c51dbbe1e604f44575a968d176 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 1 Apr 2021 11:31:18 +0800 Subject: [PATCH 137/210] codetop --- Week_02/429levelOrder.js | 5 +-- Week_03/046permute.js | 38 ++++++++++---------- Week_03/104maxDepth.js | 60 +++++++++++++++++++++++--------- Week_04/102levelOrder.js | 17 ++++----- codetop/1163getSmallestString.js | 20 +++++++++++ codetop/704search.js | 23 ++++++++++++ 6 files changed, 118 insertions(+), 45 deletions(-) create mode 100644 codetop/1163getSmallestString.js create mode 100644 codetop/704search.js diff --git a/Week_02/429levelOrder.js b/Week_02/429levelOrder.js index 40b8f28e..9f116d8f 100644 --- a/Week_02/429levelOrder.js +++ b/Week_02/429levelOrder.js @@ -1,9 +1,10 @@ /** * https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/ - * 【BFS】 + * 429. N 叉树的层序遍历 + * BFS */ -const levelOrder = function(root) { +function levelOrder(root) { if (root == null) return [] const res = [], queue = [root] while(queue.length) { diff --git a/Week_03/046permute.js b/Week_03/046permute.js index 886df171..cbcc85cf 100644 --- a/Week_03/046permute.js +++ b/Week_03/046permute.js @@ -5,27 +5,27 @@ * @param {number[]} nums * @return {number[][]} */ -const permute = function(nums) { - if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 1) return [] - const dfs = (path, remain) => { - // terminator - if (remain.length === 0) { - res.push(path.slice()) - return - } - for(let i = 0; i < remain.length; ++i) { - // process (choose one element of 【remain】 add into 【path】) - const [ val ] = remain.splice(i, 1) - path.push(val) - // drill down - dfs(path, remain) - // revere states - path.pop() - remain.splice(i, 0, val) - } +function dfs (path, remain, res) { + // terminator + if (remain.length === 0) { + res.push(path.slice()) + return } + for (let i = 0; i < remain.length; ++i) { + // process + const [val] = remain.splice(i, 1) + path.push(val) + // drill down + dfs(path, remain, res) + // revert status + path.pop() + remain.splice(i, 0, val) + } +} + +function permute(arr) { const res = [] - dfs([], nums) + dfs([], arr, res) return res } diff --git a/Week_03/104maxDepth.js b/Week_03/104maxDepth.js index 12bb76b1..1f76a557 100644 --- a/Week_03/104maxDepth.js +++ b/Week_03/104maxDepth.js @@ -1,23 +1,51 @@ /** * https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/ - * 思路: 递归 + * https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/ * - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } + * 剑指 Offer 55 - I. 二叉树的深度 */ -/** - * @param {TreeNode} root - * @return {number} - */ -const maxDepth = function(root) { - // terminator + +// 1. 递归 +function maxDepth(root) { if (root == null) return 0 - // process return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1 - // drill down - // revert states +} + +// 2. 非递归, BFS +function maxDepth(root) { + if (root == null) return 0 + const queue = [root] + let cnt = 0 + while (queue.length > 0) { + const size = queue.length + for (let i = 0; i < size; ++i) { + const node = queue.pop() + if (node.left) queue.unshift(node.left) + if (node.right) queue.unshift(node.right) + } + ++cnt + } + return cnt +} + +// 3. 非递归, DFS +function maxDepth(root) { + if (root == null) return 0 + const stack = [root] + const level = [1] + let max = 0 + while (stack.length > 0) { + const node = stack.pop() + const l = level.pop() + max = Math.max(max, l) + if (node.right) { + stack.push(node.right) + level.push(l + 1) + } + if (node.left) { + stack.push(node.left) + level.push(l + 1) + } + } + return max } diff --git a/Week_04/102levelOrder.js b/Week_04/102levelOrder.js index de4e6578..fc78259f 100644 --- a/Week_04/102levelOrder.js +++ b/Week_04/102levelOrder.js @@ -1,21 +1,22 @@ /** * https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ + * 102. 二叉树的层序遍历 * * 思路:【BFS】 * 手动维护queue (push + unshift) * 内层维护一个循环,循环当前queue的size,为一层(null不要加入queue) */ -const levelOrder = function(root) { +function levelOrder(root) { if (root == null) return [] const res = [], queue = [root] - while(queue.length) { - const n = queue.length, line = [] - for(let i = 0; i < n; ++i) { // 循环n次为一层结果 - const p = queue.pop() - if (p.left != null) queue.unshift(p.left) - if (p.right != null) queue.unshift(p.right) - line.push(p.val) + while (queue.length > 0) { + const size = queue.length, line = [] + for (let i = 0; i < size; ++i) { + const node = queue.pop() + if (node.left) queue.unshift(node.left) + if (node.right) queue.unshift(node.right) + line.push(node.val) } res.push(line) } diff --git a/codetop/1163getSmallestString.js b/codetop/1163getSmallestString.js new file mode 100644 index 00000000..653bfd03 --- /dev/null +++ b/codetop/1163getSmallestString.js @@ -0,0 +1,20 @@ +/** + * https://leetcode-cn.com/problems/smallest-string-with-a-given-numeric-value/ + * 1663. 具有给定数值的最小字符串 | medium + */ + +// 贪心法, 从右边往左填最大能放的字母 +function getSmallestString(n, k) { + const alphbets = [...' abcdefghijklmnopqrstuvwxyz'] + let str = '' + for (let i = n - 1; i >= 0; --i) { + let target = Math.min(k - i, 26) + k -= target + str = alphbets[target] + str + } + return str +} + +// ---- test case ---- +console.log(getSmallestString(3, 27)) +console.log(getSmallestString(5, 73)) diff --git a/codetop/704search.js b/codetop/704search.js new file mode 100644 index 00000000..e531a81f --- /dev/null +++ b/codetop/704search.js @@ -0,0 +1,23 @@ +/** + * https://leetcode-cn.com/problems/binary-search/ + * 704. 二分查找 + */ + +function search(arr, target) { + let left = 0, right = arr.length - 1 + while (left <= right) { + const mid = left + ((right - left) >> 1) + if (target === arr[mid]) { + return mid + } else if (target < arr[mid]) { + right = mid - 1 + } else { + left = mid + 1 + } + } + return -1 +} + +// ---- test case ---- +console.log(search([-1,0,3,5,9,12], 9)) +console.log(search([-1,0,3,5,9,12], 2)) From 2ba43990a01f6cbccfbb427ab5ff14b93932c30d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 2 Apr 2021 00:43:31 +0800 Subject: [PATCH 138/210] sort --- Week_09/300lengthOfLIS.js | 26 ++++++++++++++++++++++++++ codetop/112hasPathSum.js | 34 ++++++++++++++++++++++++++++++++++ codetop/129sumNumbers.js | 8 ++++++++ 3 files changed, 68 insertions(+) create mode 100644 Week_09/300lengthOfLIS.js create mode 100644 codetop/112hasPathSum.js create mode 100644 codetop/129sumNumbers.js diff --git a/Week_09/300lengthOfLIS.js b/Week_09/300lengthOfLIS.js new file mode 100644 index 00000000..600604ce --- /dev/null +++ b/Week_09/300lengthOfLIS.js @@ -0,0 +1,26 @@ +/** + * https://leetcode-cn.com/problems/longest-increasing-subsequence/ + * 300. 最长递增子序列 + * + */ + +// 解法一:O(n^2) +// f(i) 要遍历前面小于 dp +function lengthOfLIS(arr) { + if(arr.length < 1) return 0 + const dp = [] + for (let i = 0; i < arr.length; ++i) { + dp.push(1) + for (let j = 0; j < i; ++j) { + if (arr[j] < arr[i]) { + dp[i] = Math.max(dp[i], dp[j] + 1) + } + } + } + return Math.max(...dp) +} + +// ---- test case ---- +console.log(lengthOfLIS([10,9,2,5,3,7,101,18])) // 4 +console.log(lengthOfLIS([0,1,0,3,2,3])) // 4 +console.log(lengthOfLIS([7,7,7,7,7,7,7])) // 1 diff --git a/codetop/112hasPathSum.js b/codetop/112hasPathSum.js new file mode 100644 index 00000000..20feeca9 --- /dev/null +++ b/codetop/112hasPathSum.js @@ -0,0 +1,34 @@ +/** + * https://leetcode-cn.com/problems/path-sum/ + * 112. 路径总和 + */ + +// 递归 +function hasPathSum(root, sum) { + if (root == null) return false + if (root.left == null && root.right == null) { + return sum === root.val + } + return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val) +} + +// BFS(有副作用,会改变树的val) +function hasPathSum(root, sum) { + if (root == null) return false + let queue = [root] + while (queue.length > 0) { + let node = queue.pop() + if (node.left == null && node.right == null && node.val === sum) { + return true + } + if (node.left) { + node.left.val += node.val + queue.unshift(node.left) + } + if (node.right) { + node.right.val += node.val + queue.unshift(node.right) + } + } + return false +} diff --git a/codetop/129sumNumbers.js b/codetop/129sumNumbers.js new file mode 100644 index 00000000..673191ad --- /dev/null +++ b/codetop/129sumNumbers.js @@ -0,0 +1,8 @@ +/** + * https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/ + * 129. 求根节点到叶节点数字之和 + */ + +function sumNumbers(root) { + +} From 02c30b98fcb2755dbaeb2e53530d8497260f30c9 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 2 Apr 2021 19:48:38 +0800 Subject: [PATCH 139/210] week09 template --- Week_01/015threeSum.js | 2 +- Week_01/homework.md | 55 +++++++++++++++++++------------- Week_09/056merge.js | 14 ++++++++ Week_09/1112relativeSortArray.js | 38 ++++++++++++++++++---- Week_09/242isAnagram.js | 13 ++++++++ Week_09/493reversePairs.js | 12 +++++++ Week_09/README.md | 8 +++-- Week_09/homework.md | 13 ++++---- 8 files changed, 117 insertions(+), 38 deletions(-) create mode 100644 Week_09/056merge.js create mode 100644 Week_09/242isAnagram.js create mode 100644 Week_09/493reversePairs.js diff --git a/Week_01/015threeSum.js b/Week_01/015threeSum.js index 26bbac5d..9631db94 100644 --- a/Week_01/015threeSum.js +++ b/Week_01/015threeSum.js @@ -43,7 +43,7 @@ console.log('solution 1: ', threeSum2([-1, 0, 1, 2, -1, -4])) * 2. 外层循环k,左右双指针夹逼。挪动去重 */ -const threeSum = function(nums) { +function threeSum(nums) { if (!Array.isArray(nums) || nums.length < 3) return [] nums.sort((x, y) => x - y) const res = [] diff --git a/Week_01/homework.md b/Week_01/homework.md index 05deb4a1..1d386de7 100644 --- a/Week_01/homework.md +++ b/Week_01/homework.md @@ -1,44 +1,55 @@ -# 作业 +# Week01作业 -## 1. 用 add first 或 add last 这套新的 API 改写 Deque 的代码 - -## 2. 分析 Queue 和 Priority Queue 的源码 - -> [队列](http://fuseyism.com/classpath/doc/java/util/Queue-source.html) -> [优先队列](https://docs.oracle.com/javase/10/docs/api/java/util/PriorityQueue.html) - -## 3. 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) +## 一、数组 +### 删除排序数组中的重复项(Facebook、字节跳动、微软在半年内面试中考过) [实现代码](./026removeDuplicates.js) -## 4. 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) +### 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) [实现代码](./189rotate.js) -## 5. 合并两个有序链表(亚马逊、字节跳动在半年内面试常考) - -[实现代码](./021mergeTwoLists.js) - -## 6. 合并两个有序数组(Facebook 在半年内面试常考) +### 合并两个有序数组(Facebook 在半年内面试常考) [实现代码](./088merge.js) -## 7. 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) +### 两数之和(亚马逊、字节跳动、谷歌、Facebook、苹果、微软在半年内面试中高频常考) [实现代码](./001twoSum.js) -## 8. 移动零(Facebook、亚马逊、苹果在半年内面试中考过) +### 移动零(Facebook、亚马逊、苹果在半年内面试中考过) [实现代码](./283moveZeros.js) -## 9. 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) +### 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) [实现代码](./066plusOne.js) -## 10. 设计循环双端队列(Facebook 在 1 年内面试中考过) +### 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) -[实现代码](./641MyCircularDeque.js) +[实现代码](./042trap.js) -## 11. 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) -[实现代码](./042trap.js) + + +## 二、链表 + +### 合并两个有序链表(亚马逊、字节跳动在半年内面试常考) + +[实现代码](./021mergeTwoLists.js) + + + + +## 三、栈、队列、双端队列 + +### 用 add first 或 add last 这套新的 API 改写 Deque 的代码 + +### 分析 Queue 和 Priority Queue 的源码 + +> [队列](http://fuseyism.com/classpath/doc/java/util/Queue-source.html) +> [优先队列](https://docs.oracle.com/javase/10/docs/api/java/util/PriorityQueue.html) + +## 10. 设计循环双端队列(Facebook 在 1 年内面试中考过) + +[实现代码](./641MyCircularDeque.js) diff --git a/Week_09/056merge.js b/Week_09/056merge.js new file mode 100644 index 00000000..6d6d90c2 --- /dev/null +++ b/Week_09/056merge.js @@ -0,0 +1,14 @@ +/** + * https://leetcode-cn.com/problems/merge-intervals/ + * 56. 合并区间 | medium + */ + +function merge(intervals) { + +} + +// ---- test case ---- +console.log(merge([[1,3],[2,6],[8,10],[15,18]])) +// [[1,6],[8,10],[15,18]] +console.log(merge([[1,4],[4,5]])) +// [[1,5]] diff --git a/Week_09/1112relativeSortArray.js b/Week_09/1112relativeSortArray.js index 4f38f000..cef678d7 100644 --- a/Week_09/1112relativeSortArray.js +++ b/Week_09/1112relativeSortArray.js @@ -4,20 +4,46 @@ * */ -// hashmap + Array.prototype.sort() +// 方法一:O(nlogn) +// Step1: 使用 hashmap 记录相对次序 O(n) +// Step2: 按照相对顺序进行排序 O(nlogn) function relativeSortArray(arr1, arr2) { - const lookup = new Map() + const rank = new Map() const N = arr2.length arr2.forEach((item, idx) => { - lookup.set(item, idx) + rank.set(item, idx) }) return arr1.sort((x, y) => { - x = lookup.has(x) ? lookup.get(x) : N + x - y = lookup.has(y) ? lookup.get(y) : N + y - return x - y + const idx1 = rank.has(x) ? rank.get(x) : N + x + const idx2 = rank.has(y) ? rank.get(y) : N + y + return idx1 - idx2 }) } +// 方法二:计数排序 O(n) +// 注意题眼:1. 数据范围 [1, 1000] 2. arr2元素各不相同 +// Step1: 确定arr1上界,优化空间复杂度 +// Step2: 统计所有元素出现的频率 cnt +// Step3: 按照 arr2 的顺序,填充在arr2中出现过的元素 +// Step4: 填充 cnt 中剩余的元素 +function relativeSortArray(arr1, arr2) { + const upper = Math.max(...arr1) // O(n) + const cnt = Array(upper + 1).fill(0) + arr1.forEach(x => ++cnt[x]) // O(n) + let idx = 0 + arr2.forEach(n => { + while (cnt[n]-- > 0) { + arr1[idx++] = n + } + }) + for (let n = 0; n < cnt.length; ++n) { + while (cnt[n]-- > 0) { + arr1[idx++] = n + } + } + return arr1 +} + // ---- test case ---- var arr1 = [2,3,1,3,2,4,6,7,9,2,19] var arr2 = [2,1,4,3,9,6] diff --git a/Week_09/242isAnagram.js b/Week_09/242isAnagram.js new file mode 100644 index 00000000..1c6911e1 --- /dev/null +++ b/Week_09/242isAnagram.js @@ -0,0 +1,13 @@ +/** + * https://leetcode-cn.com/problems/valid-anagram/ + * 242. 有效的字母异位词 + */ + +// 解法一:词频统计 +function isAnagram(s, t) { + +} + +// ---- test case ---- +console.log(isAnagram('anagram', 'nagaram')) +console.log(isAnagram('rat', 'car')) diff --git a/Week_09/493reversePairs.js b/Week_09/493reversePairs.js new file mode 100644 index 00000000..95a03e41 --- /dev/null +++ b/Week_09/493reversePairs.js @@ -0,0 +1,12 @@ +/** + * https://leetcode-cn.com/problems/reverse-pairs/ + * 493. 翻转对 | hard + */ + +function reversePairs(arr) { + +} + +// ---- test case ---- +console.log(reversePairs([1,3,2,3,1])) // 2 +console.log(reversePairs([2,4,3,5,1])) // 3 diff --git a/Week_09/README.md b/Week_09/README.md index 01b3d06c..f128ca63 100644 --- a/Week_09/README.md +++ b/Week_09/README.md @@ -42,9 +42,11 @@ **非比较类排序** -+ 计数排序 -+ 桶排序 -+ 基数排序 ++ O(n) ++ 只能排整型数据 ++ [计数排序] Counting Sort ++ [桶排序] Bucket Sort ++ [基数排序] Radix Sort ## 第 19 课 | 高级动态规划 diff --git a/Week_09/homework.md b/Week_09/homework.md index 95b90338..f175d943 100644 --- a/Week_09/homework.md +++ b/Week_09/homework.md @@ -3,34 +3,35 @@ ### LRU 缓存机制(亚马逊、字节跳动、Facebook、微软在半年内面试中常考) ++ [代码](./146LRUCache.js) - -## 二、Sort +## 二、排序 ### 用自己熟悉的编程语言,手写各种初级排序代码,提交到学习总结中。 1. [冒泡排序、插入排序、选择排序](./sort-basic.js) 2. [快速排序](./sort-quick.js) -3. [二路归并排序](./sort-merge.js) +3. [归并排序](./sort-merge.js) 4. [堆排序](./sort-heap.js) ### 数组的相对排序(谷歌在半年内面试中考过) ++ [代码](./1112relativeSortArray.js) ### 有效的字母异位词(Facebook、亚马逊、谷歌在半年内面试中考过) - -### 力扣排行榜(Bloomberg 在半年内面试中考过) - ++ [代码](./242isAnagram.js) ### 合并区间(Facebook、字节跳动、亚马逊在半年内面试中常考) ++ [代码](./056merge.js) ### 翻转对(字节跳动在半年内面试中考过) ++ [代码](./493reversePairs.js) From 5f1f2dd459a7b2ecb724f5d2e7462c1af94f5918 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 3 Apr 2021 00:39:58 +0800 Subject: [PATCH 140/210] complete homework of sort --- Week_09/056merge.js | 20 +++++++++++++-- Week_09/242isAnagram.js | 18 ++++++++++++-- Week_09/493reversePairs.js | 51 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 6 deletions(-) diff --git a/Week_09/056merge.js b/Week_09/056merge.js index 6d6d90c2..75ebbac1 100644 --- a/Week_09/056merge.js +++ b/Week_09/056merge.js @@ -3,8 +3,24 @@ * 56. 合并区间 | medium */ -function merge(intervals) { - +// O(nlogn) +function merge(A) { + if (A.length < 2) return A + A.sort(([s1, d1], [s2, d2]) => { + return s1 === s2 ? d1 - d2 : s1 - s2 + }) // O(nlogn) + let prev = A[0] + const res = [prev] + for (let i = 1; i < A.length; ++i) { + const curr = A[i] + if (curr[0] <= prev[1]) { + prev[1] = Math.max(prev[1], curr[1]) + } else { + res.push(curr) + prev = curr + } + } + return res } // ---- test case ---- diff --git a/Week_09/242isAnagram.js b/Week_09/242isAnagram.js index 1c6911e1..673ae07a 100644 --- a/Week_09/242isAnagram.js +++ b/Week_09/242isAnagram.js @@ -3,9 +3,23 @@ * 242. 有效的字母异位词 */ -// 解法一:词频统计 +// 解法一:词频统计 O(n) O(n) +// 思想即计数排序 function isAnagram(s, t) { - + const m = s.length, n = t.length + if (m !== n) return false + const startIdx = 'a'.codePointAt(0) + const cnt = Array(26).fill(0) + for (let i = 0; i < m; ++i) { + const idx = s.codePointAt(i) - startIdx + ++cnt[idx] + } + for (let i = 0; i < n; ++i) { + const idx = t.codePointAt(i) - startIdx + --cnt[idx] + } + // return cnt.join('') === '0'.repeat(26) + return cnt.filter(item => item != 0).length === 0 } // ---- test case ---- diff --git a/Week_09/493reversePairs.js b/Week_09/493reversePairs.js index 95a03e41..3e575c20 100644 --- a/Week_09/493reversePairs.js +++ b/Week_09/493reversePairs.js @@ -3,10 +3,57 @@ * 493. 翻转对 | hard */ +// 解法一:暴力 O(n^2) function reversePairs(arr) { + const n = arr.length + if (n < 2) return 0 + let cnt = 0 + for (let i = 0; i < n - 1; ++i) { + for (let j = i + 1; j < n; ++j) { + if (arr[i] > 2 * arr[j]) ++cnt + } + } + return cnt +} + +// 解法二:归并排序 O(nlogn) +function reversePairs(arr, left = 0, right = arr.length - 1) { + if (left >= right) return 0 + const mid = left + ((right - left) >> 1) + const cnt1 = reversePairs(arr, left, mid) + const cnt2 = reversePairs(arr, mid + 1, right) + return merge(arr, left, mid, right, cnt1 + cnt2) +} +function merge(arr, left, mid, right, cnt) { + // 统计逆序对的逻辑 + let i = left, j = mid + 1 + while (i <= mid && j <= right) { + if (arr[i] > 2 * arr[j]) { + cnt += mid - i + 1 // 左边数组的i之后的元素与j都形成翻转对 + ++j + } else { + ++i + } + } + // 归并排序逻辑 + const tmp = Array(right - left + 1) + let k = 0 + i = left + j = mid + 1 + while (i <= mid && j <= right) { + tmp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++] + } + while (i <= mid) tmp[k++] = arr[i++] + while (j <= right) tmp[k++] = arr[j++] + for (let idx = 0; idx < tmp.length; ++idx) { + arr[left + idx] = tmp[idx] + } + return cnt } +// TODO 解法三:树状数组 O(nlogn) + // ---- test case ---- -console.log(reversePairs([1,3,2,3,1])) // 2 -console.log(reversePairs([2,4,3,5,1])) // 3 +console.log(reversePairs([1, 3, 2, 3, 1])) // 2 +console.log(reversePairs([2, 4, 3, 5, 1])) // 3 From 995384b2c3b48fdcbb4b96e522ad48aadd69bc6f Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 3 Apr 2021 21:37:27 +0800 Subject: [PATCH 141/210] add template --- Week_09/032longestValidParentheses.js | 9 +++++++ Week_09/063uniquePathsWithObstacles.js | 9 +++++++ Week_09/085maximalRectangle.js | 10 ++++++++ Week_09/091numDecodings.js | 8 ++++++ Week_09/115numDistinct.js | 10 ++++++++ Week_09/818racecar.js | 10 ++++++++ Week_09/homework.md | 19 ++++++++------ codetop/600validPalindrome.js | 34 ++++++++++++++++++++++++++ 8 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 Week_09/032longestValidParentheses.js create mode 100644 Week_09/063uniquePathsWithObstacles.js create mode 100644 Week_09/085maximalRectangle.js create mode 100644 Week_09/091numDecodings.js create mode 100644 Week_09/115numDistinct.js create mode 100644 Week_09/818racecar.js create mode 100644 codetop/600validPalindrome.js diff --git a/Week_09/032longestValidParentheses.js b/Week_09/032longestValidParentheses.js new file mode 100644 index 00000000..19bda2e9 --- /dev/null +++ b/Week_09/032longestValidParentheses.js @@ -0,0 +1,9 @@ +/** + * https://leetcode-cn.com/problems/longest-valid-parentheses/ + * 32. 最长有效括号 + */ + +function longestValidParentheses(s) { + +} + diff --git a/Week_09/063uniquePathsWithObstacles.js b/Week_09/063uniquePathsWithObstacles.js new file mode 100644 index 00000000..3f03ad14 --- /dev/null +++ b/Week_09/063uniquePathsWithObstacles.js @@ -0,0 +1,9 @@ +/** + * https://leetcode-cn.com/problems/unique-paths-ii/ + * 63. 不同路径 II + */ + +// 障碍物处 dp[x] = 0 +function uniquePathsWithObstacles(A) { + +} diff --git a/Week_09/085maximalRectangle.js b/Week_09/085maximalRectangle.js new file mode 100644 index 00000000..1cf7c2a1 --- /dev/null +++ b/Week_09/085maximalRectangle.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/maximal-rectangle/ + * 85. 最大矩形 + */ + +function maximalRectangle(matrix) { + +} + +// ---- test case ---- diff --git a/Week_09/091numDecodings.js b/Week_09/091numDecodings.js new file mode 100644 index 00000000..2cfa98c0 --- /dev/null +++ b/Week_09/091numDecodings.js @@ -0,0 +1,8 @@ +/** + * https://leetcode-cn.com/problems/decode-ways/ + * 91. 解码方法 + */ + +function numDecodings(s) { + +} diff --git a/Week_09/115numDistinct.js b/Week_09/115numDistinct.js new file mode 100644 index 00000000..531ea552 --- /dev/null +++ b/Week_09/115numDistinct.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/distinct-subsequences/ + * 115. 不同的子序列 + */ + +function numDistinct (s, t) { + +} + +// ---- test case ---- diff --git a/Week_09/818racecar.js b/Week_09/818racecar.js new file mode 100644 index 00000000..aa2b4156 --- /dev/null +++ b/Week_09/818racecar.js @@ -0,0 +1,10 @@ +/** + * https://leetcode-cn.com/problems/race-car/ + * 818. 赛车 + */ + +function racecar (target) { + +} + +// ---- test case ---- diff --git a/Week_09/homework.md b/Week_09/homework.md index f175d943..dd68448e 100644 --- a/Week_09/homework.md +++ b/Week_09/homework.md @@ -39,21 +39,26 @@ ## 三、高级动态规划 -### 不同路径 2 这道题目的状态转移方程 +TODO ### 不同路径 2 这道题目的状态转移方程 ++ [代码](./063uniquePathsWithObstacles.js) -### 最长上升子序列(字节跳动、亚马逊、微软在半年内面试中考过) +TODO ### 最长上升子序列(字节跳动、亚马逊、微软在半年内面试中考过) ++ [代码](./300lengthOfLIS.js) -### 解码方法(字节跳动、亚马逊、Facebook 在半年内面试中考过) +TODO ### 解码方法(字节跳动、亚马逊、Facebook 在半年内面试中考过) ++ [代码](./091numDecodings.js) -### 最长有效括号(亚马逊、字节跳动、华为在半年内面试中考过) +TODO ### 最长有效括号(亚马逊、字节跳动、华为在半年内面试中考过) ++ [代码](./032longestValidParentheses.js) -### 不同的子序列(MathWorks 在半年内面试中考过) +TODO ### 不同的子序列(MathWorks 在半年内面试中考过) ++ [代码](./115numDistinct.js) -### 赛车(谷歌在半年内面试中考过) - +TODO ### 赛车(谷歌在半年内面试中考过) ++ [代码](./818racecar.js) diff --git a/codetop/600validPalindrome.js b/codetop/600validPalindrome.js new file mode 100644 index 00000000..2de6b8b2 --- /dev/null +++ b/codetop/600validPalindrome.js @@ -0,0 +1,34 @@ +/** + * https://leetcode-cn.com/problems/valid-palindrome-ii/ + * 680. 验证回文字符串 Ⅱ + * + */ + +function validPalindrome(s) { + if (s.length < 3) return true + const n = s.length + if (s[0] === s[n - 1]) { + // 递归 + return validPalindrome(s.slice(1, n - 1)) + } + // 子问题 + return isPalinDrome(s.slice(1)) || isPalinDrome(s.slice(0, n - 1)) +} + +// 判断是否是回文串 +function isPalinDrome(s) { + if (s.length < 2) return true + const n = s.length + const halfLen = s.length >> 1 + for (let i = 0; i < halfLen; ++i) { + if (s.charAt(i) !== s.charAt(n - i - 1)) { + return false + } + } + return true +} + +// ---- test case ---- +console.log(validPalindrome('aba')) // true +console.log(validPalindrome('abca')) // true +console.log(validPalindrome('abcda')) // false From e50d4906535006d5eb5612ea8c29b944f455f633 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 3 Apr 2021 23:32:01 +0800 Subject: [PATCH 142/210] edit distance --- Week_09/062uniquePaths.js | 20 ++++++++++++ Week_09/063uniquePathsWithObstacles.js | 33 ++++++++++++++++++-- Week_09/072minDistance.js | 42 ++++++++++++++++++++++++++ Week_09/300lengthOfLIS.js | 1 - Week_09/README.md | 23 ++++++++++++++ Week_09/homework.md | 17 +++++++++-- 6 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 Week_09/062uniquePaths.js create mode 100644 Week_09/072minDistance.js diff --git a/Week_09/062uniquePaths.js b/Week_09/062uniquePaths.js new file mode 100644 index 00000000..071aec1f --- /dev/null +++ b/Week_09/062uniquePaths.js @@ -0,0 +1,20 @@ +/** + * https://leetcode-cn.com/problems/unique-paths/ + * 62. 不同路径 | medium + */ + +// dp f(i, j) = f(i - 1, j) + f(i, j-1) + +// O(mn) O(n) +function uniquePaths(m, n) { + const dp = Array(n).fill(1) + for (let i = 1; i < m; ++i) { + for (let j = 1; j < n; ++j) { + dp[j] += dp[j - 1] + } + } + return dp[n - 1] +} + +// ---- test case ---- +console.log(uniquePaths(3, 7)) diff --git a/Week_09/063uniquePathsWithObstacles.js b/Week_09/063uniquePathsWithObstacles.js index 3f03ad14..c748a964 100644 --- a/Week_09/063uniquePathsWithObstacles.js +++ b/Week_09/063uniquePathsWithObstacles.js @@ -3,7 +3,36 @@ * 63. 不同路径 II */ -// 障碍物处 dp[x] = 0 +/* +if 障碍物处: + f(i, j) = 0 +else + f(i, j) = f(i+1, j) + f(i, j+1) +*/ function uniquePathsWithObstacles(A) { - + const m = A.length, n = A[0].length + if (m < 1 || n < 1 || A[m-1][n-1] === 1) return 0 + const lastObsIdx = A[m - 1].lastIndexOf(1) + const dp = Array(lastObsIdx + 1).fill(0) + .concat(Array(n - lastObsIdx - 1).fill(1)) + for (let i = m - 2; i >= 0; --i) { + for (let j = n - 1; j >= 0; --j) { + if (A[i][j] === 1) { // 障碍物 + dp[j] = 0 + } else if (j === n - 1) { // 最右边一列 + dp[j] = dp[j] === 0 ? 0 : 1 + } else { + dp[j] += dp[j + 1] + } + } + } + return dp[0] } + +// ---- test case ---- +console.time('uniquePathsWithObstacles') +console.log(uniquePathsWithObstacles([[0,0,0],[0,1,0],[0,0,0]])) +console.log(uniquePathsWithObstacles([[0,1],[0,0]])) +console.log(uniquePathsWithObstacles([[0,0],[0,1]])) +console.log(uniquePathsWithObstacles([[0,0],[1,1],[0,0]])) +console.timeEnd('uniquePathsWithObstacles') diff --git a/Week_09/072minDistance.js b/Week_09/072minDistance.js new file mode 100644 index 00000000..35d1daf2 --- /dev/null +++ b/Week_09/072minDistance.js @@ -0,0 +1,42 @@ +/** + * https://leetcode-cn.com/problems/edit-distance/ + * 72. 编辑距离 | hard + */ + +/* +定义:f(i, j) + +if (w1,w2末尾字符相同) +---> f(i, j) = f(i-1, j-1) +else (w1,w2末尾字符相同) +---> f(i, j) = min( + f(i-1, j-1) + 1, // 修改w1,把最后一个x修改为y,然后相同末尾可以去掉 + f(i-1, j) + 1, // 删除w1末尾字符 + f(i, j-1) + 1, // 删除w2末尾字符 + ) +*/ +function minDistance(word1, word2) { + const m = word1.length, n = word2.length + if (m === 0 || n === 0) return Math.max(m, n) + const dp = Array.from(Array(m + 1)).map(_ => Array(n + 1).fill(0)) + for (let i = 1; i <= m; ++i) dp[i][0] = i + for (let j = 1; j <= n; ++j) dp[0][j] = j + for (let i = 1; i <= m; ++i) { + for (let j = 1; j <= n; ++j) { + if (word1[i-1] === word2[j-1]) { // tip: 注意下标,是 wordl1[i-1] 与 word2[j-1] + dp[i][j] = dp[i-1][j-1] + } else { + dp[i][j] = Math.min( + dp[i-1][j-1] + 1, // 修改word1的末尾字符 + dp[i-1][j] + 1, // 删word1 + dp[i][j-1] + 1, // 删word2 + ) + } + } + } + return dp[m][n] +} + +// ---- test case ---- +console.log(minDistance('horse', 'ros')) // 3 +console.log(minDistance('intention', 'execution')) // 5 diff --git a/Week_09/300lengthOfLIS.js b/Week_09/300lengthOfLIS.js index 600604ce..0bd4c029 100644 --- a/Week_09/300lengthOfLIS.js +++ b/Week_09/300lengthOfLIS.js @@ -1,7 +1,6 @@ /** * https://leetcode-cn.com/problems/longest-increasing-subsequence/ * 300. 最长递增子序列 - * */ // 解法一:O(n^2) diff --git a/Week_09/README.md b/Week_09/README.md index f128ca63..2ff2a284 100644 --- a/Week_09/README.md +++ b/Week_09/README.md @@ -50,3 +50,26 @@ ## 第 19 课 | 高级动态规划 +1. 划分子问题 +2. 分治 + 最优子结构 +3. 顺推公式:动态递推 + +**常见问题** + + +1. 爬楼梯问题 f(n) = f(n-1) + f(n-2) +2. 不同路径 f(i, j) = f(i-1, j) + f(i, j-1) +3. 打家劫舍 + + 方法一:f(i) = max(f(i-2) + A[i], f(i-1)) + + 方法二:f(i, 0) = max(f(i-1, 0), f(i-1, 1)), f(i, 1) = f(i-1, 0) + A[i] +4. 最小路径和 f(i, j) = min(f(i-1, j), f(i, j-1)) + A[i][j] +5. 股票买卖 第i天,交易了k次,是否持有股票 + + f(i, k, 0) = max(f(i-1, k, 0), f(i-1, k, 1) + A[i]) + + f(i, k, 1) = max(f(i-1, k, 1), f(i-1, k-1, 0) - A[i]) + +**高级DP** + +复杂度来源 + +1. 状态拥有更多维度(太多需要考虑压缩) +2. 状态方程更加复杂 diff --git a/Week_09/homework.md b/Week_09/homework.md index dd68448e..455a3242 100644 --- a/Week_09/homework.md +++ b/Week_09/homework.md @@ -39,9 +39,20 @@ ## 三、高级动态规划 -TODO ### 不同路径 2 这道题目的状态转移方程 - -+ [代码](./063uniquePathsWithObstacles.js) +### 不同路径 2 道题目的状态转移方程 + +```js +// 不同路径 I +f(i, j) = f(i-1, j) + f(i, j-1) +// 不同路径 II +if 障碍物处: + f(i, j) = 0 +else + f(i, j) = f(i+1, j) + f(i, j+1) +``` + ++ [不同路径 I](./062uniquePaths.js) ++ [不同路径 II](./063uniquePathsWithObstacles.js) TODO ### 最长上升子序列(字节跳动、亚马逊、微软在半年内面试中考过) From e72d8bdd6a82bfea916ee4ca62ae319352b63534 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 4 Apr 2021 00:54:32 +0800 Subject: [PATCH 143/210] lengthOfLIS --- Week_09/300lengthOfLIS.js | 57 ++++++++++++++++++++++++++++++++------- Week_09/homework.md | 2 +- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/Week_09/300lengthOfLIS.js b/Week_09/300lengthOfLIS.js index 0bd4c029..2e68a18c 100644 --- a/Week_09/300lengthOfLIS.js +++ b/Week_09/300lengthOfLIS.js @@ -3,13 +3,18 @@ * 300. 最长递增子序列 */ -// 解法一:O(n^2) -// f(i) 要遍历前面小于 dp +/* +[解法一] 动态规划 +[定义f(i)] 以 arr[i] 结尾的最长递增子序列长度,(arr[i]必选) +[状态方程] f(i) = max(f(j) + 1) + for (j at [0,i-1] && arr[j] < arr[i]) +[复杂度] O(n^2) O(n) +*/ function lengthOfLIS(arr) { - if(arr.length < 1) return 0 - const dp = [] - for (let i = 0; i < arr.length; ++i) { - dp.push(1) + const n = arr.length + if (n < 2) return n + const dp = Array(n).fill(1) + for (let i = 1; i < n; ++i) { for (let j = 0; j < i; ++j) { if (arr[j] < arr[i]) { dp[i] = Math.max(dp[i], dp[j] + 1) @@ -19,7 +24,41 @@ function lengthOfLIS(arr) { return Math.max(...dp) } + +// 解法二:贪心 + 二分查找 O(nlogn) O(n) +function lengthOfLIS(nums) { + const n = nums.length + if (n < 2) return n + + const search = (dp, target, hi) => { + let lo = 0 + while (lo <= hi) { + let mid = lo + ((hi - lo) >> 1) + if (target === dp[mid]) { + return mid + } else if (target < dp[mid]) { + hi = mid - 1 + } else { + lo = mid + 1 + } + } + return lo + } + + const UPBOUND = Math.max(...nums) + 1 // 上界 + const dp = Array(n).fill(UPBOUND) + for (let i = 0; i < n; i++) { + let pos = search(dp, nums[i], i) // 找到位置 + dp[pos] = nums[i] // 取而代之 + // console.log(dp) + } + for (let i = dp.length - 1; i >= 0; i--) { + if (dp[i] !== UPBOUND) return i + 1 + } + return 0 +} + // ---- test case ---- -console.log(lengthOfLIS([10,9,2,5,3,7,101,18])) // 4 -console.log(lengthOfLIS([0,1,0,3,2,3])) // 4 -console.log(lengthOfLIS([7,7,7,7,7,7,7])) // 1 +console.log(lengthOfLIS([10, 9, 2, 5, 3, 7, 101, 18])) // 4 +console.log(lengthOfLIS([0, 1, 0, 3, 2, 3])) // 4 +console.log(lengthOfLIS([7, 7, 7, 7, 7, 7, 7])) // 1 diff --git a/Week_09/homework.md b/Week_09/homework.md index 455a3242..4c6eb093 100644 --- a/Week_09/homework.md +++ b/Week_09/homework.md @@ -54,7 +54,7 @@ else + [不同路径 I](./062uniquePaths.js) + [不同路径 II](./063uniquePathsWithObstacles.js) -TODO ### 最长上升子序列(字节跳动、亚马逊、微软在半年内面试中考过) +### 最长上升子序列(字节跳动、亚马逊、微软在半年内面试中考过) + [代码](./300lengthOfLIS.js) From 228d064fc31c75d3d1646d046a05ecf6ad6c293a Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 4 Apr 2021 01:27:50 +0800 Subject: [PATCH 144/210] solve 091 numDecodings --- Week_09/091numDecodings.js | 28 +++++++++++++++++++++++++++- Week_09/homework.md | 2 +- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Week_09/091numDecodings.js b/Week_09/091numDecodings.js index 2cfa98c0..f53f744e 100644 --- a/Week_09/091numDecodings.js +++ b/Week_09/091numDecodings.js @@ -3,6 +3,32 @@ * 91. 解码方法 */ -function numDecodings(s) { +/* +转移方程 +if 1 <= A[i-1] <= 9 + f(i) += f(i-1) +if 10 <= A[i-2..i-1] <= 26 + f(i) += f(i-2) +复杂度 O(n) +*/ +function numDecodings(s) { + const n = s.length + const dp = Array(n + 1).fill(0) + dp[0] = 1 + dp[1] = s[0] === '0' ? 0 : 1 + for (let i = 2; i <= n; ++i) { + const curr = +s[i - 1] + const prev = +s.substr(i - 2, 2) + if (curr >= 1 && curr <= 9 ) dp[i] += dp[i - 1] // 第一种方式:当前位自成一个字符 + if (prev >= 10 && prev <= 26) dp[i] += dp[i - 2] // 第二种方式:与前一个字符组成一个字符 + } + return dp[n] } + +// ---- test case ---- +// console.log(numDecodings('0')) // 0 +// console.log(numDecodings('1')) // 1 A +// console.log(numDecodings('12')) // 2 AB L +console.log(numDecodings('226')) // 3 BZ VF BBF +console.log(numDecodings('222312')) // 3 BZ VF BBF diff --git a/Week_09/homework.md b/Week_09/homework.md index 4c6eb093..d74d2e89 100644 --- a/Week_09/homework.md +++ b/Week_09/homework.md @@ -58,7 +58,7 @@ else + [代码](./300lengthOfLIS.js) -TODO ### 解码方法(字节跳动、亚马逊、Facebook 在半年内面试中考过) +### 解码方法(字节跳动、亚马逊、Facebook 在半年内面试中考过) + [代码](./091numDecodings.js) From e5458e40694138610edce1b80384001b21556be9 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 4 Apr 2021 01:45:37 +0800 Subject: [PATCH 145/210] add test case & comments --- Week_09/032longestValidParentheses.js | 4 ++++ Week_09/056merge.js | 13 +++++++------ Week_09/085maximalRectangle.js | 10 ++++++++++ Week_09/115numDistinct.js | 2 ++ Week_09/818racecar.js | 2 ++ Week_09/homework.md | 5 +++++ 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Week_09/032longestValidParentheses.js b/Week_09/032longestValidParentheses.js index 19bda2e9..023daf37 100644 --- a/Week_09/032longestValidParentheses.js +++ b/Week_09/032longestValidParentheses.js @@ -7,3 +7,7 @@ function longestValidParentheses(s) { } +// ---- test case ---- +console.log(longestValidParentheses('(()')) // 2 +console.log(longestValidParentheses(')()())')) // 4 +console.log(longestValidParentheses('')) // 0 diff --git a/Week_09/056merge.js b/Week_09/056merge.js index 75ebbac1..3b4d41e0 100644 --- a/Week_09/056merge.js +++ b/Week_09/056merge.js @@ -6,16 +6,17 @@ // O(nlogn) function merge(A) { if (A.length < 2) return A - A.sort(([s1, d1], [s2, d2]) => { - return s1 === s2 ? d1 - d2 : s1 - s2 - }) // O(nlogn) - let prev = A[0] + A.sort(([start1, dest1], [start2, dest2]) => { // 优先级排序,优先按起点排序,起点相同则按终点排序 O(nlogn) + return start1 === start2 ? dest1 - dest2 : start1 - start2 + }) + + let prev = A[0] // 上一个区间 const res = [prev] for (let i = 1; i < A.length; ++i) { const curr = A[i] - if (curr[0] <= prev[1]) { + if (curr[0] <= prev[1]) { // 当前区间可以与上一区间合并 prev[1] = Math.max(prev[1], curr[1]) - } else { + } else { // 无法合并,推入res res.push(curr) prev = curr } diff --git a/Week_09/085maximalRectangle.js b/Week_09/085maximalRectangle.js index 1cf7c2a1..22cb550d 100644 --- a/Week_09/085maximalRectangle.js +++ b/Week_09/085maximalRectangle.js @@ -8,3 +8,13 @@ function maximalRectangle(matrix) { } // ---- test case ---- +console.log(maximalRectangle([ + ['1', '0', '1', '0', '0'], + ['1', '0', '1', '1', '1'], + ['1', '1', '1', '1', '1'], + ['1', '0', '0', '1', '0'], +])) // 6 +console.log(maximalRectangle([])) // 0 +console.log(maximalRectangle([['0']])) // 0 +console.log(maximalRectangle([['1']])) // 1 +console.log(maximalRectangle([['0', '0']])) // 0 diff --git a/Week_09/115numDistinct.js b/Week_09/115numDistinct.js index 531ea552..81a1ba42 100644 --- a/Week_09/115numDistinct.js +++ b/Week_09/115numDistinct.js @@ -8,3 +8,5 @@ function numDistinct (s, t) { } // ---- test case ---- +console.log(numDistinct('rabbbit', 'rabbit')) // 3 +console.log(numDistinct('babgbag', 'bag')) // 5 diff --git a/Week_09/818racecar.js b/Week_09/818racecar.js index aa2b4156..d47f5f1a 100644 --- a/Week_09/818racecar.js +++ b/Week_09/818racecar.js @@ -8,3 +8,5 @@ function racecar (target) { } // ---- test case ---- +console.log(racecar(3)) // 2 AA +console.log(racecar(6)) // 5 AAARA diff --git a/Week_09/homework.md b/Week_09/homework.md index d74d2e89..c607ceb9 100644 --- a/Week_09/homework.md +++ b/Week_09/homework.md @@ -66,10 +66,15 @@ TODO ### 最长有效括号(亚马逊、字节跳动、华为在半年内面 + [代码](./032longestValidParentheses.js) +TODO ### 最大矩形(谷歌、微软、字节跳动在半年内面试中考过) + ++ [代码](./085maximalRectangle.js) + TODO ### 不同的子序列(MathWorks 在半年内面试中考过) + [代码](./115numDistinct.js) + TODO ### 赛车(谷歌在半年内面试中考过) + [代码](./818racecar.js) From 52e6ddc6480c8be3a5de0a7cb2919a2553613cf9 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 4 Apr 2021 16:25:35 +0800 Subject: [PATCH 146/210] =?UTF-8?q?32.=20=E6=9C=80=E9=95=BF=E6=9C=89?= =?UTF-8?q?=E6=95=88=E6=8B=AC=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_09/032longestValidParentheses.js | 50 ++++++++++++++++++++++++++- Week_09/homework.md | 2 +- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/Week_09/032longestValidParentheses.js b/Week_09/032longestValidParentheses.js index 023daf37..4b47c5e9 100644 --- a/Week_09/032longestValidParentheses.js +++ b/Week_09/032longestValidParentheses.js @@ -1,13 +1,61 @@ /** * https://leetcode-cn.com/problems/longest-valid-parentheses/ * 32. 最长有效括号 + * + * !!! 格式正确且连续 */ +// 解法一:用栈记录下标 O(n) O(n) function longestValidParentheses(s) { + if (s.length < 2) return 0 + const stack = [-1] // 栈最左边位置用来存最后一个无法匹配的')'的下标,无则存 -1 + let res = 0 + for (let i = 0; i < s.length; ++i) { + if (s[i] === '(') { // 左括号先入栈等待匹配 + stack.push(i) + } else { + stack.pop() + if (stack.length > 0) { + res = Math.max(res, i - stack[stack.length - 1]) + } else { + stack.push(i) // 更新最左元素 + } + } + // console.log(stack, res, i) + } + return res +} +/** + * i 0 1 2 3 4 5 + * s ( ) ( ( ) ) + *dp 0 2 0 0 2 6 + */ +// DP O(n) O(n) +function longestValidParentheses(s) { + const n = s.length + if (n < 2) return 0 + const dp = Array(n).fill(0) + let leftCnt = 0 + for (let i = 0; i < n; ++i) { + if (s[i] === '(') { + ++leftCnt + } else if (leftCnt > 0) { + --leftCnt + dp[i] = dp[i - 1] + 2 + if (i - dp[i] >= 0) { + const prev = dp[i - dp[i]] // 之前有效的部分 + dp[i] += prev + } + } + } + // console.log(dp) + return Math.max(...dp) } // ---- test case ---- console.log(longestValidParentheses('(()')) // 2 -console.log(longestValidParentheses(')()())')) // 4 +console.log(longestValidParentheses('))))()())')) // 4 console.log(longestValidParentheses('')) // 0 +console.log(longestValidParentheses('()()')) // 4 +console.log(longestValidParentheses('()(()')) // 2 diff --git a/Week_09/homework.md b/Week_09/homework.md index c607ceb9..fa9ee213 100644 --- a/Week_09/homework.md +++ b/Week_09/homework.md @@ -62,7 +62,7 @@ else + [代码](./091numDecodings.js) -TODO ### 最长有效括号(亚马逊、字节跳动、华为在半年内面试中考过) +### 最长有效括号(亚马逊、字节跳动、华为在半年内面试中考过) + [代码](./032longestValidParentheses.js) From c9a12040cd639a8a2d37f19d36eea3d7470a0511 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 4 Apr 2021 17:05:40 +0800 Subject: [PATCH 147/210] numDistinct --- Week_09/032longestValidParentheses.js | 9 +++++---- Week_09/115numDistinct.js | 22 ++++++++++++++++++++-- Week_09/homework.md | 4 ++-- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Week_09/032longestValidParentheses.js b/Week_09/032longestValidParentheses.js index 4b47c5e9..d5dffb52 100644 --- a/Week_09/032longestValidParentheses.js +++ b/Week_09/032longestValidParentheses.js @@ -43,10 +43,11 @@ function longestValidParentheses(s) { } else if (leftCnt > 0) { --leftCnt dp[i] = dp[i - 1] + 2 - if (i - dp[i] >= 0) { - const prev = dp[i - dp[i]] // 之前有效的部分 - dp[i] += prev - } + // if (i - dp[i] >= 0) { + // const prev = dp[i - dp[i]] // 之前有效的部分 + // dp[i] += prev + // } + dp[i] += i - dp[i] >= 0 ? dp[i - dp[i]] : 0 } } // console.log(dp) diff --git a/Week_09/115numDistinct.js b/Week_09/115numDistinct.js index 81a1ba42..cdfbec09 100644 --- a/Week_09/115numDistinct.js +++ b/Week_09/115numDistinct.js @@ -1,10 +1,28 @@ /** * https://leetcode-cn.com/problems/distinct-subsequences/ - * 115. 不同的子序列 + * 115. 不同的子序列 | hard + * + * dp + * if s[i] === s[j] + * f(i, j) = f(i-1, j-1) + f(i, j-1) + * else + * f(i, j) = f(i, j-1) */ +// O(mn) O(n) function numDistinct (s, t) { - + const m = s.length, n = t.length + if (m < n) return 0 + const dp = new Array(n + 1).fill(0) + dp[0] = 1 + for(let i = 0; i < m; ++i) { + for(let j = n; j > 0; --j) { + if(s[i] === t[j - 1]) { + dp[j] += dp[j - 1] + } + } + } + return dp[n] } // ---- test case ---- diff --git a/Week_09/homework.md b/Week_09/homework.md index fa9ee213..bfc24459 100644 --- a/Week_09/homework.md +++ b/Week_09/homework.md @@ -70,11 +70,11 @@ TODO ### 最大矩形(谷歌、微软、字节跳动在半年内面试中考 + [代码](./085maximalRectangle.js) -TODO ### 不同的子序列(MathWorks 在半年内面试中考过) +### 不同的子序列(MathWorks 在半年内面试中考过) ++ TODO 比较难理解,还需要过遍数 + [代码](./115numDistinct.js) - TODO ### 赛车(谷歌在半年内面试中考过) + [代码](./818racecar.js) From 193783cb14df4ae07c7929a378c1a89787400d89 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 4 Apr 2021 17:46:31 +0800 Subject: [PATCH 148/210] rethinking 115 numDistinct --- Week_09/115numDistinct.js | 17 ++++++++++++++--- Week_09/homework.md | 1 - 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Week_09/115numDistinct.js b/Week_09/115numDistinct.js index cdfbec09..ee32ef3a 100644 --- a/Week_09/115numDistinct.js +++ b/Week_09/115numDistinct.js @@ -3,10 +3,20 @@ * 115. 不同的子序列 | hard * * dp - * if s[i] === s[j] - * f(i, j) = f(i-1, j-1) + f(i, j-1) + * if s[i] === t[j] + * f(i, j) = f(i-1, j) + f(i-1, j-1) // s去掉末尾 + s、t都去掉末尾 * else - * f(i, j) = f(i, j-1) + * f(i, j) = f(i-1, j) // s去掉末尾 + * + * ' b a g + * b 1 1 0 0 + * a 1 1 1 0 + * b 1 2 1 0 + * g 1 2 1 1 + * b 1 3 1 1 + * a 1 3 4 1 + * g 1 3 4 5 + * */ // O(mn) O(n) @@ -21,6 +31,7 @@ function numDistinct (s, t) { dp[j] += dp[j - 1] } } + console.log(i, dp) } return dp[n] } diff --git a/Week_09/homework.md b/Week_09/homework.md index bfc24459..c3b50f29 100644 --- a/Week_09/homework.md +++ b/Week_09/homework.md @@ -72,7 +72,6 @@ TODO ### 最大矩形(谷歌、微软、字节跳动在半年内面试中考 ### 不同的子序列(MathWorks 在半年内面试中考过) -+ TODO 比较难理解,还需要过遍数 + [代码](./115numDistinct.js) TODO ### 赛车(谷歌在半年内面试中考过) From 1594e3c8fcfe74ac93aade9fa16ab95d47d70672 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 5 Apr 2021 14:59:51 +0800 Subject: [PATCH 149/210] char template --- .../008myAtoi.js" | 13 ++ .../058lengthOfLastWord.js" | 13 ++ .../146toLowerCase.js" | 26 ++++ .../771numJewelsInStones.js" | 13 ++ .../README.md" | 17 +++ .../homework.md" | 138 ++++++++++++++++++ 6 files changed, 220 insertions(+) create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/058lengthOfLastWord.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/146toLowerCase.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/771numJewelsInStones.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/README.md" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" new file mode 100644 index 00000000..eb4767a2 --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" @@ -0,0 +1,13 @@ +/** + * https://leetcode-cn.com/problems/string-to-integer-atoi/ + * 8. 字符串转换整数 (atoi) | medium + */ + +function myAtoi(str) { + +} + +// ---- test case ---- +console.log() +console.log() +console.log() diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/058lengthOfLastWord.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/058lengthOfLastWord.js" new file mode 100644 index 00000000..026ffdb1 --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/058lengthOfLastWord.js" @@ -0,0 +1,13 @@ +/** + * https://leetcode-cn.com/problems/length-of-last-word/ + * 58. 最后一个单词的长度 + */ + +function lengthOfLastWord(str) { + +} + +// ---- test case ---- +console.log() +console.log() +console.log() diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/146toLowerCase.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/146toLowerCase.js" new file mode 100644 index 00000000..dbfe9535 --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/146toLowerCase.js" @@ -0,0 +1,26 @@ +/** + * https://leetcode-cn.com/problems/to-lower-case/ + * 709. 转换成小写字母 + * + * 扩展知识:ascii码点 + * + 数字零为 48 + * + 大写字母A 为 65 + * + 小写字母a 为 97 + */ + +// 解法一、调用语言内置API +function toLowerCase(str) { + return str.toLowerCase() +} + +// 解法二、利用正则匹配 + 码点API +function toLowerCase(str) { + return str.replace(/[A-Z]/g, ch => { + return String.fromCharCode(ch.charCodeAt() + 32) + }) +} + +// ---- test case ---- +console.log(toLowerCase('Hello')) +console.log(toLowerCase('here')) +console.log(toLowerCase('LOVELY')) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/771numJewelsInStones.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/771numJewelsInStones.js" new file mode 100644 index 00000000..d0dfe0f3 --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/771numJewelsInStones.js" @@ -0,0 +1,13 @@ +/** + * https://leetcode-cn.com/problems/jewels-and-stones/ + * 771. 宝石与石头 + */ + +function numJewelsInStones(jewels, stones) { + +} + +// ---- test case ---- +console.log() +console.log() +console.log() diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/README.md" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/README.md" new file mode 100644 index 00000000..ad77838a --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/README.md" @@ -0,0 +1,17 @@ +# 学习笔记 + +## 第 20 课 | 字符串算法 + +string immutable + +**字符串访问** +1. [String.prototype.charAt()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/charAt) +2. StringName[index] +3. [区别](https://stackoverflow.com/questions/5943726/string-charatx-or-stringx) + - charAt 兼容性更好 + +**字符串拷贝** +1. [String.prototype.slice()] +2. [String.prototype.substr()] +3. [String.prototype.substring()] + diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" new file mode 100644 index 00000000..81802baf --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" @@ -0,0 +1,138 @@ +# 作业 + +## 一、字符串基础 + +### 709 转换成小写字母(谷歌在半年内面试中考过) + ++ https://leetcode-cn.com/problems/to-lower-case/ ++ [代码](./146toLowerCase.js) + +### 58 最后一个单词的长度 + ++ https://leetcode-cn.com/problems/length-of-last-word/ ++ [代码](./058lengthOfLastWord.js) + +### 771 宝石与石头 + ++ https://leetcode-cn.com/problems/jewels-and-stones/ ++ [代码](./771numJewelsInStones.js) + +### 387 字符串中的第一个唯一字符 + ++ https://leetcode-cn.com/problems/first-unique-character-in-a-string/ ++ [代码](./387firstUniqChar.js) + +### 8 字符串转换整数 (atoi) + ++ https://leetcode-cn.com/problems/string-to-integer-atoi/ ++ [代码](./008myAtoi.js) + + + + + + +## 二、字符串操作 + +### 14 最长公共前缀 + ++ https://leetcode-cn.com/problems/longest-common-prefix/ + + +### 344 反转字符串 + ++ https://leetcode-cn.com/problems/reverse-string/ + + +### 541 反转字符串 II + ++ https://leetcode-cn.com/problems/reverse-string-ii/ + + +### 151 翻转字符串里的单词 + ++ https://leetcode-cn.com/problems/reverse-words-in-a-string/ + + +### 557 反转字符串中的单词 III + ++ https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/ + + +### 917 仅仅反转字母 + ++ https://leetcode-cn.com/problems/reverse-only-letters/ + + + + + + +## 三、异位词问题 + + +### 242 有效的字母异位词 + ++ https://leetcode-cn.com/problems/valid-anagram/ + + +### 49 字母异位词分组 + ++ https://leetcode-cn.com/problems/group-anagrams/ + + +### 438 找到字符串中所有字母异位词 + ++ https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/ + + + + + + +## 四、回文串问题 + +### 125 验证回文串 + ++ https://leetcode-cn.com/problems/valid-palindrome/ + + +### 680 验证回文字符串 Ⅱ + ++ https://leetcode-cn.com/problems/valid-palindrome-ii/ + + +### 5 最长回文子串 + ++ https://leetcode-cn.com/problems/longest-palindromic-substring/ + + + + +## 五、最长子串子序列问题 + +### 1143 最长公共子序列 + ++ https://leetcode-cn.com/problems/longest-common-subsequence/ + + + +## 六、最长子串子序列问题 + +### 10 正则表达式匹配 + ++ https://leetcode-cn.com/problems/regular-expression-matching/ + + +### 44 通配符匹配 + ++ https://leetcode-cn.com/problems/wildcard-matching + + +### 115 不同的子序列 + ++ https://leetcode-cn.com/problems/distinct-subsequences/ + + + + From 8526069958d211d70eaac559910e0d3aff641ccf Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 5 Apr 2021 21:55:59 +0800 Subject: [PATCH 150/210] lccp & linkedlist --- .gitignore | 1 + linkedlist/083deleteDuplicates.js | 34 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 linkedlist/083deleteDuplicates.js diff --git a/.gitignore b/.gitignore index 2a802fa8..28ce43bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .DS_Store note.md jshandwrite +LCCP diff --git a/linkedlist/083deleteDuplicates.js b/linkedlist/083deleteDuplicates.js new file mode 100644 index 00000000..cc254b48 --- /dev/null +++ b/linkedlist/083deleteDuplicates.js @@ -0,0 +1,34 @@ +/** + * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/ + * 83. 删除排序链表中的重复元素 + */ +const { ListNode, LinkedList } = require('./LinkedList.js') + +function deleteDuplicates(head) { + let node = head + while (node && node.next) { + if (node.val === node.next.val) { + node.next = node.next.next + } else { + node = node.next + } + } + return head +} + +// ---- test case ---- + +// ---- test case ---- +var link = new LinkedList() +link.append(1) + .append(1) + .append(2) + .append(3) + .append(3) + .display() + +link = deleteDuplicates(link.head) +// console.log(JSON.stringify(link, null, 2)) +link = new LinkedList(link) + +link.display() From 057e4a73f425a1d9afaf591239cb82a3936da806 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 5 Apr 2021 23:30:00 +0800 Subject: [PATCH 151/210] basic str --- .../008myAtoi.js" | 42 +++++++++++++++++-- .../058lengthOfLastWord.js" | 17 ++++++-- .../387firstUniqChar.js" | 23 ++++------ .../771numJewelsInStones.js" | 12 ++++-- 4 files changed, 70 insertions(+), 24 deletions(-) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" index eb4767a2..aeafb538 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" @@ -3,11 +3,47 @@ * 8. 字符串转换整数 (atoi) | medium */ +// 解法一:使用API function myAtoi(str) { + return Math.max(Math.min(parseInt(str) || 0, 2147483647), -2147483648) +} + +// 解法二:手写一趟遍历 O(n) +function myAtoi(str) { + const n = str.length + if (n < 1) return 0 + + let idx = 0, sign = 1, total = 0 + + // 去除左边空格 + while (str.charAt(idx) === ' ' && idx < n) ++idx + + // 处理正负号 + const ch = str.charAt(idx) + if (ch === '+' || ch === '-') { + sign = ch === '-' ? -1 : 1 + ++idx + } + + const startIdx = '0'.codePointAt(0) + for (; idx < n; ++idx) { + const digit = str.codePointAt(idx) - startIdx + if (digit < 0 || digit > 9) { // 遇到非数字,结束循环 + break + } + total = 10 * total + digit + } + const MAX = 2147483647, MIN = -2147483648 + let ret = total * sign + ret = ret > MAX ? MAX : ret + ret = ret < MIN ? MIN : ret + return ret } // ---- test case ---- -console.log() -console.log() -console.log() +console.log(myAtoi('42')) // 42 +console.log(myAtoi(' -42')) // -42 +console.log(myAtoi('4139 with words'))// 4139 +console.log(myAtoi('words and 987')) // 0 +console.log(myAtoi('-91283472332')) // -2147483648 diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/058lengthOfLastWord.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/058lengthOfLastWord.js" index 026ffdb1..70eaea5f 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/058lengthOfLastWord.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/058lengthOfLastWord.js" @@ -3,11 +3,20 @@ * 58. 最后一个单词的长度 */ +// 从后往前遍历 function lengthOfLastWord(str) { - + let cnt = 0, i = str.length - 1 + while (str.charAt(i) === ' ') --i // 去掉末尾空格 + for (; i >= 0; --i, ++cnt) { + if (str.charAt(i) === ' ') { + break + } + } + return cnt } // ---- test case ---- -console.log() -console.log() -console.log() +console.log(lengthOfLastWord('Hello World')) +console.log(lengthOfLastWord('a')) +console.log(lengthOfLastWord('a ')) +console.log(lengthOfLastWord('')) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/387firstUniqChar.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/387firstUniqChar.js" index f30c3206..5d4451d7 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/387firstUniqChar.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/387firstUniqChar.js" @@ -13,30 +13,25 @@ function firstUniqChar1(s) { return -1 } -// array存字母位置 -// O(n) O(26) function firstUniqChar(s) { - const positions = Array(26) // 默认为 empty + const UPPER = s.length + const positions = Array(26).fill(UPPER) // 默认为 empty const pos0 = 'a'.codePointAt(0) for (let i = 0; i < s.length; ++i) { const chIdx = s.codePointAt(i) - pos0 - if (positions[chIdx] >= 0) { // 该字符出现过 - positions[chIdx] = -1 // 标记为-1 - } else if (positions[chIdx] !== -1) { // 字符没出现过 + if (positions[chIdx] < UPPER) { // 已经出现过 & 未标记过 + positions[chIdx] = UPPER + 1 + } else if (positions[chIdx] === UPPER) { // 第一次出现 positions[chIdx] = i + } else { // 已经出现过 & 已标记过 + continue } } - let minPos = s.length - for (let i = 0; i < positions.length; ++i) { - if (positions[i] >= 0 && minPos > positions[i]) { - minPos = positions[i] - } - } - return minPos === s.length ? -1 : minPos + const minPos = Math.min(...positions) + return minPos >= UPPER ? -1 : minPos } - // ---- test case ---- console.log(firstUniqChar('aadadaad')) // -1 console.log(firstUniqChar('aabb')) // -1 diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/771numJewelsInStones.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/771numJewelsInStones.js" index d0dfe0f3..942fd2f1 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/771numJewelsInStones.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/771numJewelsInStones.js" @@ -3,11 +3,17 @@ * 771. 宝石与石头 */ +// 集合, O(m + n) function numJewelsInStones(jewels, stones) { - + const jewelSet = new Set([...jewels]) + let cnt = 0 + for (const ch of stones) { + if (jewelSet.has(ch)) ++cnt + } + return cnt } // ---- test case ---- -console.log() -console.log() +console.log(numJewelsInStones('aA', 'aAAbbbb')) // 3 +console.log(numJewelsInStones('z', 'ZZ')) // 0 console.log() From d5aa3abd99b7c9fdafe5ed6e0c1e9e43a4b24f88 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 6 Apr 2021 01:10:48 +0800 Subject: [PATCH 152/210] maniplate strings --- .../008myAtoi.js" | 6 ++- .../014longestCommonPrefix.js" | 26 ++++++++++++ .../151reverseWords.js" | 19 +++++++++ .../344reverseString.js" | 18 ++++++++ .../541reverseStr.js" | 28 +++++++++++++ .../557reverseWords.js" | 14 +++++++ .../917reverseOnlyLetters.js" | 41 +++++++++++++++++++ .../homework.md" | 19 ++++----- 8 files changed, 159 insertions(+), 12 deletions(-) create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/014longestCommonPrefix.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/151reverseWords.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/344reverseString.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/541reverseStr.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/557reverseWords.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/917reverseOnlyLetters.js" diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" index aeafb538..44f01fb1 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/008myAtoi.js" @@ -15,7 +15,7 @@ function myAtoi(str) { let idx = 0, sign = 1, total = 0 - // 去除左边空格 + // 去左空格 while (str.charAt(idx) === ' ' && idx < n) ++idx // 处理正负号 @@ -25,6 +25,7 @@ function myAtoi(str) { ++idx } + // 检索数字,计算total const startIdx = '0'.codePointAt(0) for (; idx < n; ++idx) { const digit = str.codePointAt(idx) - startIdx @@ -34,7 +35,8 @@ function myAtoi(str) { total = 10 * total + digit } - const MAX = 2147483647, MIN = -2147483648 + // 处理 int(32bit) 边界 + const MIN = 1 << 31, MAX = -1 * (MIN + 1) let ret = total * sign ret = ret > MAX ? MAX : ret ret = ret < MIN ? MIN : ret diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/014longestCommonPrefix.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/014longestCommonPrefix.js" new file mode 100644 index 00000000..100e366f --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/014longestCommonPrefix.js" @@ -0,0 +1,26 @@ +/** + * https://leetcode-cn.com/problems/longest-common-prefix/ + * 14. 最长公共前缀 + */ + +// O(n * minStrLen) +function longestCommonPrefix(strs) { + const minStrLen = Math.min(...strs.map(str => str.length)) + const n = strs.length + if (minStrLen < 1 || n < 1) return '' + if (n < 2) return strs[0] + + for (let i = 0; i < minStrLen; ++i) { + for (let j = 1; j < n; ++j) { + if (strs[j][i] !== strs[0][i]) { + return strs[j].slice(0, i) + } + } + } + return strs[0].slice(0, minStrLen) +} + +// ---- test case ---- +console.log(longestCommonPrefix(["flower","flow","flight"])) +console.log(longestCommonPrefix(["dog","racecar","car"])) +console.log(longestCommonPrefix(["ab","a"])) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/151reverseWords.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/151reverseWords.js" new file mode 100644 index 00000000..d5e0ab77 --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/151reverseWords.js" @@ -0,0 +1,19 @@ +/** + * https://leetcode-cn.com/problems/reverse-words-in-a-string/ + * 151. 翻转字符串里的单词 + */ + +// 解法一:调用api +function reverseWords(s) { + return s.split(' ') + .filter(str => !!str) + .reverse() + .join(' ') +} + +// ---- test case ---- +console.log(reverseWords('the sky is blue')) +console.log(reverseWords(' hello world! ')) +console.log(reverseWords('a good example')) +console.log(reverseWords(' Bob Loves Alice ')) +console.log(reverseWords('Alice does not even like bob')) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/344reverseString.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/344reverseString.js" new file mode 100644 index 00000000..c7119190 --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/344reverseString.js" @@ -0,0 +1,18 @@ +/** + * https://leetcode-cn.com/problems/reverse-string/ + * 344. 反转字符串 + */ + +function reverseString(s) { + const loops = s.length >> 1 + for (let i = 0; i < loops; ++i) { + const tmp = s[i] + s[i] = s[s.length - i - 1] + s[s.length - i - 1] = tmp + } +} + +// ---- test case ---- +const arr = ["h","e","l","l","o"] +reverseString(arr) +console.log(arr) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/541reverseStr.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/541reverseStr.js" new file mode 100644 index 00000000..3c4d1419 --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/541reverseStr.js" @@ -0,0 +1,28 @@ +/** + * https://leetcode-cn.com/problems/reverse-string-ii/ + * 541. 反转字符串 II + */ + +function swap(arr, i, j) { + if (i !== j) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp + } +} + +// 双指针 +function reverseStr(s, k) { + const arr = s.split('') + for (let i = 0; i < s.length; i += 2 * k) { + let start = i + let end = Math.min(i + k - 1, arr.length - 1) + while (start < end) { + swap(arr, start++, end--) + } + } + return arr.join('') +} + +// ---- test case ---- +console.log(reverseStr('abcdefg', 2)) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/557reverseWords.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/557reverseWords.js" new file mode 100644 index 00000000..2bb3d133 --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/557reverseWords.js" @@ -0,0 +1,14 @@ +/** + * https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/ + * 557. 反转字符串中的单词 III + */ + +// 调api +function reverseWords(s) { + return s.split(' ').map( + str => str.split('').reverse().join('') + ).join(' ') +} + +// ---- test case ---- +console.log(reverseWords("Let's take LeetCode contest")) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/917reverseOnlyLetters.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/917reverseOnlyLetters.js" new file mode 100644 index 00000000..fdd607d8 --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/917reverseOnlyLetters.js" @@ -0,0 +1,41 @@ +/** + * https://leetcode-cn.com/problems/reverse-only-letters/ + * 917. 仅仅反转字母 + */ + +function swap(arr, i, j) { + if (i !== j) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp + } +} + +function isStr(ch, A, Z, a, z) { + if (ch >= A && ch <= Z || ch >= a && ch <= z) { + return true + } + return false +} + +function reverseOnlyLetters(S) { + const A = 'A'.codePointAt(0) + const Z = 'Z'.codePointAt(0) + const a = 'a'.codePointAt(0) + const z = 'z'.codePointAt(0) + + const res = S.split('') + let lo = 0, hi = res.length - 1 + while (lo < hi) { + while(lo < hi && !isStr(res[lo].codePointAt(0), A, Z, a, z)) { ++lo } + while(lo < hi && !isStr(res[hi].codePointAt(0), A, Z, a, z)) { --hi } + swap(res, lo++, hi--) + } + return res.join('') +} + +// ---- test case ---- +console.log(reverseOnlyLetters('ab-cd')) +console.log(reverseOnlyLetters('a-bC-dEf-ghIj')) +console.log(reverseOnlyLetters('Test1ng-Leet=code-Q!')) +console.log(reverseOnlyLetters("7_28]")) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" index 81802baf..a94b4b58 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" @@ -31,38 +31,37 @@ - ## 二、字符串操作 ### 14 最长公共前缀 + https://leetcode-cn.com/problems/longest-common-prefix/ - ++ [代码](./014longestCommonPrefix.js) ### 344 反转字符串 + https://leetcode-cn.com/problems/reverse-string/ - ++ [代码](./344reverseString.js) ### 541 反转字符串 II + https://leetcode-cn.com/problems/reverse-string-ii/ - - -### 151 翻转字符串里的单词 - -+ https://leetcode-cn.com/problems/reverse-words-in-a-string/ - ++ [代码](./541reverseStr.js) ### 557 反转字符串中的单词 III + https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/ ++ [代码](./557reverseWords.js) + +### 151 翻转字符串里的单词 ++ https://leetcode-cn.com/problems/reverse-words-in-a-string/ ++ [代码](./151reverseWords.js) ### 917 仅仅反转字母 + https://leetcode-cn.com/problems/reverse-only-letters/ - ++ [代码](./917reverseOnlyLetters.js) From 65e6f34c2854ab9c4836d617b66e5512bc5e507b Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 6 Apr 2021 01:22:27 +0800 Subject: [PATCH 153/210] string template --- .../005longestPalindrome.js" | 5 +++++ .../010isMatch.js" | 5 +++++ .../044isMatch.js" | 5 +++++ .../049groupAnagrams.js" | 5 +++++ .../1143longestCommonSubsequence.js" | 5 +++++ .../115numDistinct.js" | 5 +++++ .../125isPalindrome.js" | 5 +++++ .../242isAnagram.js" | 5 +++++ .../438findAnagrams.js" | 5 +++++ .../680validPalindrome.js" | 5 +++++ .../homework.md" | 17 ++++++++++------- .../touch" | 0 12 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/010isMatch.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/044isMatch.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/049groupAnagrams.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/115numDistinct.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/125isPalindrome.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/242isAnagram.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/680validPalindrome.js" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/touch" diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" new file mode 100644 index 00000000..76f4002e --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" @@ -0,0 +1,5 @@ +/** + * + */ + +// ---- test case ---- diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/010isMatch.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/010isMatch.js" new file mode 100644 index 00000000..76f4002e --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/010isMatch.js" @@ -0,0 +1,5 @@ +/** + * + */ + +// ---- test case ---- diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/044isMatch.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/044isMatch.js" new file mode 100644 index 00000000..76f4002e --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/044isMatch.js" @@ -0,0 +1,5 @@ +/** + * + */ + +// ---- test case ---- diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/049groupAnagrams.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/049groupAnagrams.js" new file mode 100644 index 00000000..76f4002e --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/049groupAnagrams.js" @@ -0,0 +1,5 @@ +/** + * + */ + +// ---- test case ---- diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" new file mode 100644 index 00000000..76f4002e --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" @@ -0,0 +1,5 @@ +/** + * + */ + +// ---- test case ---- diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/115numDistinct.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/115numDistinct.js" new file mode 100644 index 00000000..76f4002e --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/115numDistinct.js" @@ -0,0 +1,5 @@ +/** + * + */ + +// ---- test case ---- diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/125isPalindrome.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/125isPalindrome.js" new file mode 100644 index 00000000..76f4002e --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/125isPalindrome.js" @@ -0,0 +1,5 @@ +/** + * + */ + +// ---- test case ---- diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/242isAnagram.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/242isAnagram.js" new file mode 100644 index 00000000..76f4002e --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/242isAnagram.js" @@ -0,0 +1,5 @@ +/** + * + */ + +// ---- test case ---- diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" new file mode 100644 index 00000000..76f4002e --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" @@ -0,0 +1,5 @@ +/** + * + */ + +// ---- test case ---- diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/680validPalindrome.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/680validPalindrome.js" new file mode 100644 index 00000000..76f4002e --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/680validPalindrome.js" @@ -0,0 +1,5 @@ +/** + * + */ + +// ---- test case ---- diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" index a94b4b58..13e27222 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" @@ -73,16 +73,17 @@ ### 242 有效的字母异位词 + https://leetcode-cn.com/problems/valid-anagram/ - ++ [代码](./242isAnagram.js) ### 49 字母异位词分组 + https://leetcode-cn.com/problems/group-anagrams/ - ++ [代码](./049groupAnagrams.js) ### 438 找到字符串中所有字母异位词 + https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/ ++ [代码](./438findAnagrams.js) @@ -94,16 +95,17 @@ ### 125 验证回文串 + https://leetcode-cn.com/problems/valid-palindrome/ - ++ [代码](./125isPalindrome.js) ### 680 验证回文字符串 Ⅱ + https://leetcode-cn.com/problems/valid-palindrome-ii/ - ++ [代码](./680validPalindrome.js) ### 5 最长回文子串 + https://leetcode-cn.com/problems/longest-palindromic-substring/ ++ [代码](./005longestPalindrome.js) @@ -113,6 +115,7 @@ ### 1143 最长公共子序列 + https://leetcode-cn.com/problems/longest-common-subsequence/ ++ [代码](./1143longestCommonSubsequence.js) @@ -121,17 +124,17 @@ ### 10 正则表达式匹配 + https://leetcode-cn.com/problems/regular-expression-matching/ - ++ [代码](./010isMatch.js) ### 44 通配符匹配 + https://leetcode-cn.com/problems/wildcard-matching - ++ [代码](./044isMatch.js) ### 115 不同的子序列 + https://leetcode-cn.com/problems/distinct-subsequences/ - ++ [代码](./115numDistinct.js) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/touch" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/touch" new file mode 100644 index 00000000..e69de29b From 2c9431534598bfbfba44bf51144fe05be4b3d5f0 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 6 Apr 2021 10:26:23 +0800 Subject: [PATCH 154/210] refactor: triangle --- Week_06/120minimumTotal.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Week_06/120minimumTotal.js b/Week_06/120minimumTotal.js index 552126e8..b7163ded 100644 --- a/Week_06/120minimumTotal.js +++ b/Week_06/120minimumTotal.js @@ -5,7 +5,7 @@ */ // O(mn) O(n) -const minimumTotal = function(A) { +function minimumTotal(A) { const m = A.length, n = A[m - 1].length const dp = A[m - 1].slice() for (let i = m - 2; i >= 0; --i) { @@ -16,6 +16,18 @@ const minimumTotal = function(A) { return dp[0] } +// ~等边三角形 +function minimumTotal(triangle) { + const n = triangle.length + const dp = triangle[n - 1].slice() + for(let i = n - 2; i >= 0; --i) { + for (let j = 0; j <= i; ++j) { + dp[j] = triangle[i][j] + Math.min(dp[j], dp[j + 1]) + } + } + return dp[0] +} + // ---- test case ---- console.log(minimumTotal([ [ 2 ], From 3159079e45a02458f05047d2e1b236e0dc3585ca Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 6 Apr 2021 16:20:19 +0800 Subject: [PATCH 155/210] refactor --- Week_09/146LRUCache.js | 8 +++++--- Week_09/README.md | 2 +- .../README.md" | 5 +++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Week_09/146LRUCache.js b/Week_09/146LRUCache.js index 525cda63..33f39df8 100644 --- a/Week_09/146LRUCache.js +++ b/Week_09/146LRUCache.js @@ -4,7 +4,7 @@ */ // 解法一:利用 Map 本身是 orderedDict 的特性 -class LRUCache1 { +class LRUCache { constructor(capacity) { this.cache = new Map() this.capacity = capacity @@ -22,7 +22,9 @@ class LRUCache1 { } this.cache.set(key, value) if (this.cache.size > this.capacity) { - this.cache.delete(this.cache.keys().next().value) + const iter = this.cache.keys() + // console.log("🚀", iter) + this.cache.delete(iter.next().value) } } } @@ -36,7 +38,7 @@ class ListNode { this.next = null; } } -class LRUCache { +class LRUCache1 { constructor(capacity) { this.capacity = capacity; this.cache = new Map(); diff --git a/Week_09/README.md b/Week_09/README.md index 2ff2a284..981cfb7d 100644 --- a/Week_09/README.md +++ b/Week_09/README.md @@ -16,7 +16,7 @@ ### LRU cache -+ Least recently used ++ Least recently used -> 最近最少使用 + 实现:HashMap + 双向链表 + O(1) 查询 + O(1) 修改、更新 diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/README.md" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/README.md" index ad77838a..f140d216 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/README.md" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/README.md" @@ -15,3 +15,8 @@ string immutable 2. [String.prototype.substr()] 3. [String.prototype.substring()] +**字符串DP** +1. 最长回文串 + 1. 暴力 O(n^3) + 2. 中间向两边扩张 O(n^2) + 3. 动态规划 O(n^2) From 8a69025cf80d0aa696da8e072db5d5cae03403ff Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 6 Apr 2021 18:27:11 +0800 Subject: [PATCH 156/210] spiral print --- .gitignore | 1 + Week_02/239maxSlidingWindow.js | 27 +++++++++++++++++---- codetop/054spiralOrder.js | 43 ++++++++++++++++++++++++++++++++++ codetop/059generateMatrix.js | 32 +++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 codetop/054spiralOrder.js create mode 100644 codetop/059generateMatrix.js diff --git a/.gitignore b/.gitignore index 28ce43bd..7160133c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ note.md jshandwrite LCCP +BST diff --git a/Week_02/239maxSlidingWindow.js b/Week_02/239maxSlidingWindow.js index 12d5d10b..fab4780b 100644 --- a/Week_02/239maxSlidingWindow.js +++ b/Week_02/239maxSlidingWindow.js @@ -25,11 +25,28 @@ const maxSlidingWindow = function (nums, k) { return res } +const maxSlidingWindow = function (nums, k) { + if (!Array.isArray(nums) || nums.length < 1 || k < 1) return [] + const res = [], win = [] + for (let i = 0; i < nums.length; ++i) { + if (i >= k && i >= k + win[0]) { // window size + win.shift() + } + while (nums[i] >= nums[win[win.length - 1]]) { // override left elements + win.pop() + } + win.push(i) + if (i >= k - 1) { + res.push(nums[win[0]]) + } + } + return res +} // ---- test case ---- console.log(maxSlidingWindow([1,3,-1,-3,5,3,6,7], 3)) -console.log(maxSlidingWindow([1], 1)) -console.log(maxSlidingWindow([1,-1], 1)) -console.log(maxSlidingWindow([9,11], 2)) -console.log(maxSlidingWindow([4,-2], 2)) -console.log(maxSlidingWindow([1,3,1,2,0,5], 3)) +// console.log(maxSlidingWindow([1], 1)) +// console.log(maxSlidingWindow([1,-1], 1)) +// console.log(maxSlidingWindow([9,11], 2)) +// console.log(maxSlidingWindow([4,-2], 2)) +// console.log(maxSlidingWindow([1,3,1,2,0,5], 3)) diff --git a/codetop/054spiralOrder.js b/codetop/054spiralOrder.js new file mode 100644 index 00000000..6aa028b9 --- /dev/null +++ b/codetop/054spiralOrder.js @@ -0,0 +1,43 @@ +/** + * https://leetcode-cn.com/problems/spiral-matrix/ + * 54. 螺旋矩阵 | medium + */ + +function spiralOrder (A) { + const m = A.length, n = A[0].length + const visited = [...Array(m)].map(() => Array(n).fill(0)) + let dir = 0, c = 0, r = 0 + const dr = [0, 1, 0, -1] + const dc = [1, 0, -1, 0] + const res = [] + for (let i = 0; i < m * n; ++i) { + res.push(A[r][c]) + visited[r][c] = 1 + let nr = r + dr[dir] + let nc = c + dc[dir] + if (nr < 0 || nr >= m || nc < 0 || nc >= n || visited[nr][nc] === 1) { + dir = (dir + 1) % 4 + nr = r + dr[dir] + nc = c + dc[dir] + } + r = nr + c = nc + } + return res +} + +// ---- test case ---- +console.log(spiralOrder( + [ + [1,2,3], + [4,5,6], + [7,8,9] + ] +)) +console.log(spiralOrder( + [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9,10,11,12] + ] +)) diff --git a/codetop/059generateMatrix.js b/codetop/059generateMatrix.js new file mode 100644 index 00000000..48bd1449 --- /dev/null +++ b/codetop/059generateMatrix.js @@ -0,0 +1,32 @@ +/** + * https://leetcode-cn.com/problems/spiral-matrix-ii/ + * 59. 螺旋矩阵 II | medium + */ + +// 1. 计算 nr,nc +// 2. 判断 nr,nc 是否合法 +// 3. 如果不合法,转向,并用新的方向重新计算nr,nc +// 4. nr,nc 赋值给 r, c +function generateMatrix (n) { + const res = [...Array(n)].map(() => Array(n).fill(0)) + const dr = [0, 1, 0, -1] + const dc = [1, 0, -1, 0] + let dir = 0, r = 0, c = 0 + for (let i = 0; i < n * n; ++i) { + res[r][c] = i + 1 + let nr = r + dr[dir] + let nc = c + dc[dir] + if (nr < 0 || nr >= n || nc < 0 || nc >= n || res[nr][nc] !== 0) { + dir = (dir + 1) % 4 + nr = r + dr[dir] + nc = c + dc[dir] + } + r = nr + c = nc + } + return res +} + +// ---- test case ---- +console.log(generateMatrix(3)) +console.log(generateMatrix(1)) From d27b2bfcfdadad67a68880fc189b75dd08b14c49 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 7 Apr 2021 00:57:16 +0800 Subject: [PATCH 157/210] add major --- codetop/major.js | 24 ++++++++++++++++++++++++ codetop/offer039majorityElement.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 codetop/major.js create mode 100644 codetop/offer039majorityElement.js diff --git a/codetop/major.js b/codetop/major.js new file mode 100644 index 00000000..d338553f --- /dev/null +++ b/codetop/major.js @@ -0,0 +1,24 @@ +function major(arr, k) { + const n = arr.length + const LOWLINE = n / k + const map = new Map() + for (let i = 0; i < n; ++i) { + if (map.has(arr[i])) { + map.set(arr[i], map.get(arr[i]) + 1) + } else { + map.set(arr[i], 1) + } + } + const ret = [...map.entries()].filter( + ([_item, times]) => { + return times > LOWLINE + } + ).map( + ([item, _times]) => item + ) + return ret +} + +// ---- test case ---- +console.log(major([1, 2, 3, 1, 2, 3, 4], 7)) // [1, 2, 3] +console.log(major([4, 1], 1)) // [] diff --git a/codetop/offer039majorityElement.js b/codetop/offer039majorityElement.js new file mode 100644 index 00000000..7f1f8c9a --- /dev/null +++ b/codetop/offer039majorityElement.js @@ -0,0 +1,28 @@ +/** + * https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/ + * 剑指 Offer 39. 数组中出现次数超过一半的数字 + */ + +// 摩尔投票法 +function majorityElement(arr) { + const n = arr.length + if (n < 1) return + let res = arr[0], cnt = 1 + for (let i = 1; i < n; ++i) { + if (arr[i] === res) { + ++cnt + } else { + if (cnt === 0) { + cnt = 1 + res = arr[i] + } else { + --cnt + } + } + } + return res +} + +// ---- test case ---- +console.log(majorityElement([1, 2, 3, 2, 2, 2, 5, 4, 2])) +console.log(majorityElement([3, 2, 3])) From 4aaa4d822cacd5989617fe7010a56a90f28f571d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 7 Apr 2021 11:16:30 +0800 Subject: [PATCH 158/210] refactor --- Week_01/042trap.js | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/Week_01/042trap.js b/Week_01/042trap.js index 37f4835e..d8e1b093 100644 --- a/Week_01/042trap.js +++ b/Week_01/042trap.js @@ -3,28 +3,34 @@ * 11. 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) * hard | leetcode-042 | array * - * 思路: maxLeft、maxRight 记录左右最高柱子 + * 思路: maxLo、maxHi 记录遍历过的柱子中,左右最高柱子 */ -var trap = function (A) { - var left = 0, right = A.length - 1 - var res = 0, maxLeft = 0, maxRight = 0 - while (left < right) { - if (A[left] <= A[right]) { - if (A[left] >= maxLeft) { - maxLeft = A[left] - } else { - res += maxLeft - A[left] +function trap (A) { + let lo = 0, hi = A.length - 1 + let res = 0 + let maxLo = 0, maxHi = 0 + while (lo < hi) { + if (A[lo] <= A[hi]) { // 左边矮于右边 + if (A[lo] >= maxLo) { // 左边提高了 + maxLo = A[lo] + } else { // 左边没提高,可以积累高度差个雨水 + res += maxLo - A[lo] } - ++left + ++lo } else { - if (A[right] >= maxRight) { - maxRight = A[right] + if (A[hi] >= maxHi) { + maxHi = A[hi] } else { - res += maxRight - A[right] + res += maxHi - A[hi] } - --right + --hi } + console.log(lo, hi, maxLo, maxHi, res) } return res -}; +} + +// ---- test case ---- +console.log(trap([0,1,0,2,1,0,1,3,2,1,2,1])) +console.log(trap([4,2,0,3,2,5])) From 260238aa079705a01ed2d5efc3b6fdf77a825846 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 7 Apr 2021 13:56:13 +0800 Subject: [PATCH 159/210] largest rect --- Week_01/084largestRectangleArea.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Week_01/084largestRectangleArea.js diff --git a/Week_01/084largestRectangleArea.js b/Week_01/084largestRectangleArea.js new file mode 100644 index 00000000..ebb35e60 --- /dev/null +++ b/Week_01/084largestRectangleArea.js @@ -0,0 +1,22 @@ +/** + * https://leetcode-cn.com/problems/largest-rectangle-in-histogram/ + * 84. 柱状图中最大的矩形 | hard + */ + +// stack O(n) +function largestRectangleArea(A) { + let maxArea = 0 + const stack = [] + A = [0, ...A, 0] + for (let i = 0; i < A.length; ++i) { + while (stack.length > 1 && A[stack[stack.length - 1]] > A[i]) { + const j = stack.pop() + maxArea = Math.max((i - stack[stack.length - 1] - 1) * A[j], maxArea) + } + stack.push(i) + } + return maxArea +} + +// ---- test case ---- +console.log(largestRectangleArea([2,1,5,6,2,3])) From 59f6c1202320623e25cf4ea828a86b7c8d700eb2 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 8 Apr 2021 14:27:08 +0800 Subject: [PATCH 160/210] solve anagram problem --- .../049groupAnagrams.js" | 25 +++++++++++- .../242isAnagram.js" | 19 +++++++++- .../438findAnagrams.js" | 38 ++++++++++++++++++- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/049groupAnagrams.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/049groupAnagrams.js" index 76f4002e..1a0277c0 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/049groupAnagrams.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/049groupAnagrams.js" @@ -1,5 +1,28 @@ /** - * + * https://leetcode-cn.com/problems/group-anagrams/ + * 49. 字母异位词分组 | medium */ +// 哈希表统计 +function groupAnagrams(strs) { + const startIdx = 'a'.codePointAt(0) + const map = {} + for(const str of strs) { + const cntArr = Array(26).fill(0) + for (let i = 0; i < str.length; ++i) { + cntArr[str.codePointAt(i) - startIdx]++ + } + const key = cntArr.toString() + if (map[key] === void(0)) { + map[key] = [str] + } else { + map[key].push(str) + } + } + return Object.values(map) +} + // ---- test case ---- +console.log(groupAnagrams( + ["eat", "tea", "tan", "ate", "nat", "bat"] +)) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/242isAnagram.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/242isAnagram.js" index 76f4002e..c104b6e3 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/242isAnagram.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/242isAnagram.js" @@ -1,5 +1,22 @@ /** - * + * https://leetcode-cn.com/problems/valid-anagram/ + * 242. 有效的字母异位词 */ +function isAnagram (s, t) { + const m = s.length, n = t.length + if (m !== n) return false + const startIdx = 'a'.codePointAt(0) + const cnt = Array(26).fill(0) + for (let i = 0; i < n; ++i) { + const idxS = s.codePointAt(i) - startIdx + const idxT = t.codePointAt(i) - startIdx + cnt[idxS] = cnt[idxS] + 1 + cnt[idxT] = cnt[idxT] - 1 + } + return cnt.filter(item => item !== 0).length === 0 +} + // ---- test case ---- +console.log(isAnagram('anagram', 'nagaram')) // true +console.log(isAnagram('rat', 'car')) // false diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" index 76f4002e..782d8035 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" @@ -1,5 +1,41 @@ /** - * + * https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/ + * 438. 找到字符串中所有字母异位词 | medium */ +function findAnagrams (s, p) { + const m = s.length, n = p.length + if (m < n || n < 1) return [] + const startIdx = 'a'.codePointAt(0) + // 按 s、p 前n个字符,初始化统计数组 cntArr + const cntArr = Array(26).fill(0) + for (let i = 0; i < n; ++i) { + const idxP = p.codePointAt(i) - startIdx + const idxS = s.codePointAt(i) - startIdx + ++cntArr[idxP] + --cntArr[idxS] + } + // 初始化 win 窗口,存储当前窗口中的字母 + const res = [] + const win = [...s.substr(0, n)] + if (cntArr.filter(cnt => cnt !== 0).length === 0) res.push(0) + for (let i = n; i < m; ++i) { + // 更新窗口 win + const newCh = s.charAt(i) + win.push(newCh) + const oldCh = win.shift() + // 更新 cntArr + const newIdx = newCh.codePointAt(0) - startIdx + const oldIdx = oldCh.codePointAt(0) - startIdx + --cntArr[newIdx] + ++cntArr[oldIdx] + // console.log(newCh, oldCh, cntArr, res) + if (cntArr.filter(cnt => cnt !== 0).length === 0) res.push(i - n + 1) + } + return res +} + // ---- test case ---- +console.log(findAnagrams('cbaebabacd', 'abc')) // [0, 6] +console.log(findAnagrams('abab', 'ab')) // [0, 1, 2] +console.log(findAnagrams('baa', 'aa')) From 16c7ab7aa249eb5da6923f4130be36554e1510e3 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 8 Apr 2021 15:43:34 +0800 Subject: [PATCH 161/210] solve palindrome --- .../005longestPalindrome.js" | 32 +++++++- .../125isPalindrome.js" | 75 ++++++++++++++++++- .../438findAnagrams.js" | 1 + .../680validPalindrome.js" | 27 ++++++- .../homework.md" | 2 +- 5 files changed, 133 insertions(+), 4 deletions(-) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" index 76f4002e..537bef59 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" @@ -1,5 +1,35 @@ /** - * + * https://leetcode-cn.com/problems/longest-palindromic-substring/ + * 5. 最长回文子串 | medium */ +// 中心扩散法,共 2n - 1 个中心 +function longestPalindrome (s) { + const n = s.length + if (n < 1) return '' + let start = 0, end = 0 + for (let i = 0; i < n; ++i) { + const len1 = expand(s, i, i) + const len2 = expand(s, i, i + 1) + const len = Math.max(len1, len2) + if (len > end - start) { + start = i - ((len - 1) >> 1) + end = i + (len >> 1) + } + } + return s.slice(start, end + 1) +} + +function expand(s, lo, hi) { + while (lo >= 0 && hi < s.length && s.charAt(lo) === s.charAt(hi)) { + --lo + ++hi + } + return hi - lo - 1 +} + // ---- test case ---- +console.log(longestPalindrome('babad')) // bab +console.log(longestPalindrome('cbbd')) // bb +console.log(longestPalindrome('a')) // a +console.log(longestPalindrome('ac')) // a diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/125isPalindrome.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/125isPalindrome.js" index 76f4002e..310810ac 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/125isPalindrome.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/125isPalindrome.js" @@ -1,5 +1,78 @@ /** - * + * https://leetcode-cn.com/problems/valid-palindrome/ + * 125. 验证回文串 */ +// 解法一:先用正则处理 O(n), O(n) +function isPalindrome(s) { + const t = s.replace(/[^\da-zA-Z]/g, '').toLowerCase() + const n = t.length + // console.log(t, n) + if (n < 2) return true + let lo = 0, hi = n - 1 + while (lo < hi && t[lo] === t[hi]) { + ++lo + --hi + } + return t[lo] === t[hi] +} + +// 解法二: 码点 + 双指针收缩 O(n) O(1) +function isPalindrome(s) { + const n = s.length + if (n < 2) return true + const s1 = 'A'.codePointAt(0) + const d1 = 'Z'.codePointAt(0) + const s2 = 'a'.codePointAt(0) + const d2 = 'z'.codePointAt(0) + const s3 = '0'.codePointAt(0) + const d3 = '9'.codePointAt(0) + const isAlpha = (ch) => { + const cp = ch.codePointAt(0) + return (cp >= s1 && cp <= d1 || cp >= s2 && cp <= d2) + } + const isDigital = (ch) => { + const cp = ch.codePointAt(0) + return (cp >= s3 && cp <= d3) + } + const isSameChar = (ch1, ch2) => { + const cp1 = ch1.codePointAt(0) + const cp2 = ch2.codePointAt(0) + return cp1 === cp2 + } + const isSameAlpha = (ch1, ch2) => { + if (!isAlpha(ch1) || !isAlpha(ch2)) return false // 要先保证两个字符都是字母 + const cp1 = ch1.codePointAt(0) + const cp2 = ch2.codePointAt(0) + const gap = Math.abs(cp1 - cp2) + return gap === s2 - s1 + } + + let lo = 0, hi = n - 1 + while (lo < hi) { + // filter + while (lo < hi && !isAlpha(s.charAt(lo)) && !isDigital(s.charAt(lo))) { ++lo } + while (lo < hi && !isAlpha(s.charAt(hi)) && !isDigital(s.charAt(hi))) { --hi } + // console.log(lo, hi, s[lo], s[hi]) + if (lo >= hi) { + break + } else if ( + isSameChar( s.charAt(lo), s.charAt(hi)) || + isSameAlpha(s.charAt(lo), s.charAt(hi)) + ) { + ++lo + --hi + } else { + return false + } + } + return true +} + // ---- test case ---- +console.log(isPalindrome('A man, a plan, a canal: Panama')) +console.log(isPalindrome('race a car')) +console.log(isPalindrome('.,')) +console.log(isPalindrome('OP')) +console.log(isPalindrome('0P')) +console.log(isPalindrome('ab_a')) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" index 782d8035..c1b9e829 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" @@ -3,6 +3,7 @@ * 438. 找到字符串中所有字母异位词 | medium */ +// 滑动窗口 + 数组统计 O(n) function findAnagrams (s, p) { const m = s.length, n = p.length if (m < n || n < 1) return [] diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/680validPalindrome.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/680validPalindrome.js" index 76f4002e..e6ef3078 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/680validPalindrome.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/680validPalindrome.js" @@ -1,5 +1,30 @@ /** - * + * https://leetcode-cn.com/problems/valid-palindrome-ii/ + * 680. 验证回文字符串 Ⅱ */ +// 分治,判断首尾是否相同来缩短问题规模 +function validPalindrome(s) { + if (s.length < 3) return true + const n = s.length + if (s[0] === s[n - 1]) { + return validPalindrome(s.slice(1, n - 1)) + } + return isPalinDrome(s.slice(1)) || isPalinDrome(s.slice(0, n - 1)) +} + +function isPalinDrome(s) { + if (s.length < 2) return true + const n = s.length + const halfLen = s.length >> 1 + for (let i = 0; i < halfLen; ++i) { + if (s.charAt(i) !== s.charAt(n - i - 1)) { + return false + } + } + return true +} + // ---- test case ---- +console.log(validPalindrome('aba')) +console.log(validPalindrome('abca')) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" index 13e27222..32f6bde7 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/homework.md" @@ -119,7 +119,7 @@ -## 六、最长子串子序列问题 +## 六、字符串 + DP问题 ### 10 正则表达式匹配 From 0f290837e138259caf1dc4bbf55fa2a4186ae526 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 8 Apr 2021 16:00:19 +0800 Subject: [PATCH 162/210] refactor longestPalindrome --- .../005longestPalindrome.js" | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" index 537bef59..d7e2615f 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/005longestPalindrome.js" @@ -9,12 +9,13 @@ function longestPalindrome (s) { if (n < 1) return '' let start = 0, end = 0 for (let i = 0; i < n; ++i) { - const len1 = expand(s, i, i) - const len2 = expand(s, i, i + 1) + const len1 = expand(s, i, i) // 奇数长度 + const len2 = expand(s, i, i + 1) // 偶数长度 const len = Math.max(len1, len2) - if (len > end - start) { + if (len > end - start + 1) { // 找到了更长的 + console.log(len1, len2, i) start = i - ((len - 1) >> 1) - end = i + (len >> 1) + end = i + ( len >> 1) } } return s.slice(start, end + 1) @@ -33,3 +34,4 @@ console.log(longestPalindrome('babad')) // bab console.log(longestPalindrome('cbbd')) // bb console.log(longestPalindrome('a')) // a console.log(longestPalindrome('ac')) // a +console.log(longestPalindrome('cbbd')) // bb From 02289d84712a00e691fc76e95f52dfbab0777bd2 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 8 Apr 2021 16:12:52 +0800 Subject: [PATCH 163/210] complete template --- .../010isMatch.js" | 12 +++++++++++- .../044isMatch.js" | 12 +++++++++++- .../1143longestCommonSubsequence.js" | 11 ++++++++++- .../115numDistinct.js" | 14 ++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/010isMatch.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/010isMatch.js" index 76f4002e..2450e343 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/010isMatch.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/010isMatch.js" @@ -1,5 +1,15 @@ /** - * + * https://leetcode-cn.com/problems/regular-expression-matching/ + * 10. 正则表达式匹配 | hard */ +function isMatch(s, p) { + +} + // ---- test case ---- +console.log(isMatch('aa', 'a')) // false +console.log(isMatch('aa', 'a*')) // true +console.log(isMatch('ab', '.*')) // true +console.log(isMatch('aab', 'c*a*b')) // true +console.log(isMatch('mississippi', 'mis*is*p*.'))// false diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/044isMatch.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/044isMatch.js" index 76f4002e..0e52962c 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/044isMatch.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/044isMatch.js" @@ -1,5 +1,15 @@ /** - * + * https://leetcode-cn.com/problems/wildcard-matching/ + * 44. 通配符匹配 | hard */ +function isMatch(s, p) { + +} + // ---- test case ---- +console.log(isMatch('aa', 'a')) // false +console.log(isMatch('aa', '*')) // true +console.log(isMatch('cb', '?a')) // false +console.log(isMatch('adceb', '*a*b')) // true +console.log(isMatch('acdcb', 'a*c?b'))// false diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" index 76f4002e..3c8b3510 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" @@ -1,5 +1,14 @@ /** - * + * https://leetcode-cn.com/problems/longest-common-subsequence/ + * 1143. 最长公共子序列 | medium */ +function longestCommonSubsequence(s1, s2) { + +} + // ---- test case ---- +console.log(longestCommonSubsequence('abcde', 'ace')) +console.log(longestCommonSubsequence('abc', 'abc')) +console.log(longestCommonSubsequence('abc', 'def')) +console.log(longestCommonSubsequence("abcba", "abcbcba")) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/115numDistinct.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/115numDistinct.js" index 76f4002e..2dc0131f 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/115numDistinct.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/115numDistinct.js" @@ -1,5 +1,19 @@ /** + * https://leetcode-cn.com/problems/distinct-subsequences/ + * 115. 不同的子序列 | hard * + * dp + * if s[i] === t[j] + * f(i, j) = f(i-1, j) + f(i-1, j-1) // s去掉末尾 + s、t都去掉末尾 + * else + * f(i, j) = f(i-1, j) // s去掉末尾 */ +// O(mn) O(n) +function numDistinct (s, t) { + +} + // ---- test case ---- +console.log(numDistinct('rabbbit', 'rabbit')) // 3 +console.log(numDistinct('babgbag', 'bag')) // 5 From 313ec105dad7a599fd96b2ce47d5e469548ca99d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 10 Apr 2021 23:56:44 +0800 Subject: [PATCH 164/210] complete every solve --- .../touch" | 0 codetop/238productExceptSelf.js | 38 +++++++++++++++++++ 2 files changed, 38 insertions(+) delete mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/touch" create mode 100644 codetop/238productExceptSelf.js diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/touch" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/touch" deleted file mode 100644 index e69de29b..00000000 diff --git a/codetop/238productExceptSelf.js b/codetop/238productExceptSelf.js new file mode 100644 index 00000000..8c44a110 --- /dev/null +++ b/codetop/238productExceptSelf.js @@ -0,0 +1,38 @@ +/** + * https://leetcode-cn.com/problems/product-of-array-except-self/ + * 238. 除自身以外数组的乘积 + */ + +// // 方法一:暴力 O(n^2) +// function productExceptSelf(nums) { +// const n = nums.length +// const res = Array(n) +// for(let i = 0; i < n; ++i) { +// res[i] = [ +// ...nums.slice(0, i), +// ...nums.slice(i + 1) +// ].reduce((ans, item) => ans * item) +// } +// return res +// } + +// 方法二:两轮累计遍历 +function productExceptSelf(nums) { + const n = nums.length + const res = Array(n) + let ans = 1 + for(let i = 0; i < n; ++i) { + res[i] = ans + ans = ans * nums[i] + } + ans = 1 + for (let i = n - 1; i >= 0; --i) { + res[i] *= ans + ans *= nums[i] + } + return res +} + + +// ---- test case ---- +console.log(productExceptSelf([1,2,3,4])) From b4a1bc88c27142900583942435d117aa18629da6 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 11 Apr 2021 00:01:09 +0800 Subject: [PATCH 165/210] lcsq --- .../1143longestCommonSubsequence.js" | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" index 3c8b3510..313f4c4f 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/1143longestCommonSubsequence.js" @@ -3,8 +3,23 @@ * 1143. 最长公共子序列 | medium */ -function longestCommonSubsequence(s1, s2) { - +// 因为要用到dp[i-1][j-1]的值,所以dp开二维数组 +const longestCommonSubsequence = function(s1, s2) { + if (typeof s1 !== 'string' || typeof s2 !== 'string' || !s1.length || !s2.length) return 0 + const m = s1.length, n = s2.length + const dp = Array(m + 1).fill(0).map( + _ => Array(n + 1).fill(0)) + + for (let i = 1; i <= m; ++i) { + for (let j = 1; j <= n; ++j) { + if (s1[i - 1] === s2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1 + } else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + } + } + } + return dp[m][n] } // ---- test case ---- From 08b18626722b387d3401b94a9ac7183977c4a6cd Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 11 Apr 2021 15:58:48 +0800 Subject: [PATCH 166/210] =?UTF-8?q?add=20=E6=AF=95=E4=B8=9A=E5=88=B7?= =?UTF-8?q?=E9=A2=98=E8=B7=AF=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\232\346\200\273\347\273\223.textClipping" | Bin 195 -> 0 bytes .../road.md" | 111 ++++++++++++++++++ .../summary.md" | 3 + 3 files changed, 114 insertions(+) delete mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/10\346\257\225\344\270\232\346\200\273\347\273\223.textClipping" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/road.md" create mode 100644 "Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/10\346\257\225\344\270\232\346\200\273\347\273\223.textClipping" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/10\346\257\225\344\270\232\346\200\273\347\273\223.textClipping" deleted file mode 100644 index 6e67767cea7da5d7bd2738da8e78bbbcfc953f67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 195 zcmYc)$jK}&F)+Bu$P^J8;;HMBSdw^|nT3^&og-dAB{@G=FR`E?CsnVcC^03oBr`uR zF-JEyF { + return { + title: item.innerText, + href: item.href + } +}) +var ret = '' +for (let i = 0; i < a.length; ++i) { + ret += `+ [${a[i].title}](${a[i].href})\n` +} + +console.log(ret) +``` + +## 77题(“左耳朵耗子”陈皓老师和超哥分享的毕业刷题路线) + +### 一、 基础 + ++ [两数之和](http://leetcode-cn.com/problems/two-sum) ++ [有效的括号](http://leetcode-cn.com/problems/valid-parentheses/) ++ [字符串解码](http://leetcode-cn.com/problems/decode-string/) ++ [ LRU 缓存机制](http://leetcode-cn.com/problems/lru-cache/submissions/) ++ [实现 Trie(前缀树)](http://leetcode-cn.com/problems/implement-trie-prefix-tree/) ++ [添加与搜索单词 - 数据结构设计](http://leetcode-cn.com/problems/add-and-search-word-data-structure-design/) ++ [单词搜索 II ](http://leetcode-cn.com/problems/word-search-ii/) ++ [找不同](http://leetcode-cn.com/problems/find-the-difference/) ++ [单词规律](http://leetcode-cn.com/problems/word-pattern/) ++ [字符串中的第一个唯一字符](http://leetcode-cn.com/problems/first-unique-character-in-a-string) ++ [无重复字符的最长子串](http://leetcode-cn.com/problems/longest-substring-without-repeating-characters) ++ [最小覆盖子串](http://leetcode-cn.com/problems/minimum-window-substring/) ++ [合并两个有序链表](http://leetcode-cn.com/problems/merge-two-sorted-lists) ++ [环形链表](http://leetcode-cn.com/problems/linked-list-cycle) ++ [环形链表 II ](http://leetcode-cn.com/problems/linked-list-cycle-ii) ++ [反转链表](http://leetcode-cn.com/problems/reverse-linked-list) ++ [反转链表 II ](http://leetcode-cn.com/problems/reverse-linked-list-ii) ++ [旋转链表](http://leetcode-cn.com/problems/rotate-list) ++ [排序链表](http://leetcode-cn.com/problems/sort-list/) ++ [链表中倒数第 k 个节点](http://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/) ++ [两两交换链表中的节点](http://leetcode-cn.com/problems/swap-nodes-in-pairs) ++ [按奇偶排序数组](http://leetcode-cn.com/problems/sort-array-by-parity/) ++ [按奇偶排序数组 II ](http://leetcode-cn.com/problems/sort-array-by-parity-ii/) ++ [有序数组的平方](http://leetcode-cn.com/problems/squares-of-a-sorted-array/) ++ [山脉数组的峰顶索引](http://leetcode-cn.com/problems/peak-index-in-a-mountain-array) ++ [搜索旋转排序数组](http://leetcode-cn.com/problems/search-in-rotated-sorted-array) ++ [搜索旋转排序数组 II ](http://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/) ++ [寻找旋转排序数组中的最小值](http://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/) ++ [寻找旋转排序数组中的最小值 II ](http://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/) ++ [搜索二维矩阵](http://leetcode-cn.com/problems/search-a-2d-matrix) ++ [等式方程的可满足性](http://leetcode-cn.com/problems/satisfiability-of-equality-equations/) ++ [朋友圈](http://leetcode-cn.com/problems/friend-circles/) ++ [账户合并](http://leetcode-cn.com/problems/accounts-merge/) + +### 二、DFS + ++ [二叉树的最大深度](http://leetcode-cn.com/problems/maximum-depth-of-binary-tree) ++ [路径总和](http://leetcode-cn.com/problems/path-sum/) ++ [路径总和 II ](http://leetcode-cn.com/problems/path-sum-ii/) ++ [被围绕的区域](http://leetcode-cn.com/problems/surrounded-regions/) ++ [岛屿数量](http://leetcode-cn.com/problems/number-of-islands/) ++ [岛屿的最大面积](http://leetcode-cn.com/problems/max-area-of-island/) ++ [在二叉树中分配硬币](http://leetcode-cn.com/problems/distribute-coins-in-binary-tree/) + +### 三、回溯 + ++ [括号生成](http://leetcode-cn.com/problems/generate-parentheses/) ++ [ N 皇后](http://leetcode-cn.com/problems/n-queens/) ++ [ N 皇后 II ](http://leetcode-cn.com/problems/n-queens-ii/) ++ [解数独](http://leetcode-cn.com/problems/sudoku-solver/) ++ [不同路径 III ](http://leetcode-cn.com/problems/unique-paths-iii/) ++ [单词搜索](http://leetcode-cn.com/problems/word-search/) + +### 四、分治 + ++ [搜索二维矩阵 II ](http://leetcode-cn.com/problems/search-a-2d-matrix-ii/) ++ [合并 K 个排序链表](http://leetcode-cn.com/problems/merge-k-sorted-lists) ++ [为运算表达式设计优先级](http://leetcode-cn.com/problems/different-ways-to-add-parentheses) ++ [给表达式添加运算符](http://leetcode-cn.com/problems/expression-add-operators) ++ [数组中的第 K 个最大元素](http://leetcode-cn.com/problems/kth-largest-element-in-an-array) ++ [最接近原点的 K 个点](http://leetcode-cn.com/problems/k-closest-points-to-origin/) ++ [鸡蛋掉落](http://leetcode-cn.com/problems/super-egg-drop/) + +### 五、动态规划 + ++ [使用最小花费爬楼梯](http://leetcode-cn.com/problems/min-cost-climbing-stairs) ++ [爬楼梯](http://leetcode-cn.com/problems/climbing-stairs) ++ [不同路径](http://leetcode-cn.com/problems/unique-paths/) ++ [最小路径和](http://leetcode-cn.com/problems/minimum-path-sum/) ++ [最大子序和](http://leetcode-cn.com/problems/maximum-subarray/) ++ [乘积最大子数组](http://leetcode-cn.com/problems/maximum-product-subarray/) ++ [买卖股票的最佳时机](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock) ++ [买卖股票的最佳时机 II ](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/) ++ [买卖股票的最佳时机 III ](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/) ++ [买卖股票的最佳时机 IV ](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/) ++ [最佳买卖股票时机含冷冻期](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) ++ [买卖股票的最佳时机含手续费](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee) ++ [零钱兑换](http://leetcode-cn.com/problems/coin-change) ++ [零钱兑换 II ](http://leetcode-cn.com/problems/coin-change-2) ++ [编辑距离](http://leetcode-cn.com/problems/edit-distance) ++ [不同的子序列](http://leetcode-cn.com/problems/distinct-subsequences/) ++ [柱状图中最大的矩形](http://leetcode-cn.com/problems/largest-rectangle-in-histogram/) ++ [最大矩形](http://leetcode-cn.com/problems/maximal-rectangle/) ++ [最大正方形](http://leetcode-cn.com/problems/maximal-square/) ++ [最低票价](http://leetcode-cn.com/problems/minimum-cost-for-tickets/) ++ [区域和检索 - 数组不可变](http://leetcode-cn.com/problems/range-sum-query-immutable/) ++ [二维区域和检索 - 矩阵不可变](http://leetcode-cn.com/problems/range-sum-query-2d-immutable/) ++ [最长上升子序列](http://leetcode-cn.com/problems/longest-increasing-subsequence) ++ [鸡蛋掉落](http://leetcode-cn.com/problems/super-egg-drop/) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" new file mode 100644 index 00000000..9b7d1576 --- /dev/null +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" @@ -0,0 +1,3 @@ +# 毕业总结 + +> [毕业刷题路线](./road.md) From 354f995c7227f50307c27dcc4b808d4dba632778 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 11 Apr 2021 22:27:34 +0800 Subject: [PATCH 167/210] refactor road.md --- README.md | 8 +- .../road.md" | 188 ++++++++++-------- .../summary.md" | 30 +++ 3 files changed, 131 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index 69c5118c..c3344256 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,3 @@ # 算法训练 -## 链表系列 - -+ [单向链表实现](./linkedlist/LinkedList.js) -+ [反转链表](./linkedlist/206reverseList.js) -+ [合并两个有序链表](./linkedlist/021mergeTwoLists.js) -+ [环形链表](./linkedlist/141hasCycle.js) -+ [相交链表](./linkedlist/160getIntersectionNode.js) +[毕业刷题路线](./Week_10%20%E6%AF%95%E4%B8%9A%E6%80%BB%E7%BB%93/road.md) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/road.md" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/road.md" index b5aa7fb5..4b7f5943 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/road.md" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/road.md" @@ -1,111 +1,123 @@ # 毕业刷题路线 ```js -var list = document.querySelectorAll('.article-typo a') -var a = [...list].map(item => { - return { - title: item.innerText, - href: item.href +function getQuestionsArr () { + const list = document.querySelectorAll('.article-typo li') + return [...list].map((li, idx) => { + const href = li.childNodes[0].href // 题目地址 + const title = li.childNodes[0].innerText // 题目 + const level = li?.childNodes[1]?.nodeValue?.split(/[()()]/g)[1] || '' + console.log(idx, ':', href, title, level) // 难度级别 + return { + level, + title, + href, + } + }) +} +function getPrintTxt(quesArr) { + const map = { '简单':'😊', '中等':'🤔', '困难':'🤯' } + var txt = '' + for (let i = 0; i < quesArr.length; ++i) { + txt += `+ ${map[quesArr[i].level]} [${quesArr[i].title}](${quesArr[i].href})\n` } -}) -var ret = '' -for (let i = 0; i < a.length; ++i) { - ret += `+ [${a[i].title}](${a[i].href})\n` + return txt } - -console.log(ret) +var quesArr = getQuestionsArr() +var txt = getPrintTxt(quesArr) +console.log(txt) ``` ## 77题(“左耳朵耗子”陈皓老师和超哥分享的毕业刷题路线) ### 一、 基础 -+ [两数之和](http://leetcode-cn.com/problems/two-sum) -+ [有效的括号](http://leetcode-cn.com/problems/valid-parentheses/) -+ [字符串解码](http://leetcode-cn.com/problems/decode-string/) -+ [ LRU 缓存机制](http://leetcode-cn.com/problems/lru-cache/submissions/) -+ [实现 Trie(前缀树)](http://leetcode-cn.com/problems/implement-trie-prefix-tree/) -+ [添加与搜索单词 - 数据结构设计](http://leetcode-cn.com/problems/add-and-search-word-data-structure-design/) -+ [单词搜索 II ](http://leetcode-cn.com/problems/word-search-ii/) -+ [找不同](http://leetcode-cn.com/problems/find-the-difference/) -+ [单词规律](http://leetcode-cn.com/problems/word-pattern/) -+ [字符串中的第一个唯一字符](http://leetcode-cn.com/problems/first-unique-character-in-a-string) -+ [无重复字符的最长子串](http://leetcode-cn.com/problems/longest-substring-without-repeating-characters) -+ [最小覆盖子串](http://leetcode-cn.com/problems/minimum-window-substring/) -+ [合并两个有序链表](http://leetcode-cn.com/problems/merge-two-sorted-lists) -+ [环形链表](http://leetcode-cn.com/problems/linked-list-cycle) -+ [环形链表 II ](http://leetcode-cn.com/problems/linked-list-cycle-ii) -+ [反转链表](http://leetcode-cn.com/problems/reverse-linked-list) -+ [反转链表 II ](http://leetcode-cn.com/problems/reverse-linked-list-ii) -+ [旋转链表](http://leetcode-cn.com/problems/rotate-list) -+ [排序链表](http://leetcode-cn.com/problems/sort-list/) -+ [链表中倒数第 k 个节点](http://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/) -+ [两两交换链表中的节点](http://leetcode-cn.com/problems/swap-nodes-in-pairs) -+ [按奇偶排序数组](http://leetcode-cn.com/problems/sort-array-by-parity/) -+ [按奇偶排序数组 II ](http://leetcode-cn.com/problems/sort-array-by-parity-ii/) -+ [有序数组的平方](http://leetcode-cn.com/problems/squares-of-a-sorted-array/) -+ [山脉数组的峰顶索引](http://leetcode-cn.com/problems/peak-index-in-a-mountain-array) -+ [搜索旋转排序数组](http://leetcode-cn.com/problems/search-in-rotated-sorted-array) -+ [搜索旋转排序数组 II ](http://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/) -+ [寻找旋转排序数组中的最小值](http://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/) -+ [寻找旋转排序数组中的最小值 II ](http://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/) -+ [搜索二维矩阵](http://leetcode-cn.com/problems/search-a-2d-matrix) -+ [等式方程的可满足性](http://leetcode-cn.com/problems/satisfiability-of-equality-equations/) -+ [朋友圈](http://leetcode-cn.com/problems/friend-circles/) -+ [账户合并](http://leetcode-cn.com/problems/accounts-merge/) ++ 😊 [两数之和](http://leetcode-cn.com/problems/two-sum) ++ 😊 [有效的括号](http://leetcode-cn.com/problems/valid-parentheses/) ++ 🤔 [字符串解码](http://leetcode-cn.com/problems/decode-string/) ++ 🤯 [ LRU 缓存机制](http://leetcode-cn.com/problems/lru-cache/submissions/) ++ 🤔 [实现 Trie(前缀树)](http://leetcode-cn.com/problems/implement-trie-prefix-tree/) ++ 🤔 [添加与搜索单词 - 数据结构设计](http://leetcode-cn.com/problems/add-and-search-word-data-structure-design/) ++ 🤯 [单词搜索 II ](http://leetcode-cn.com/problems/word-search-ii/) ++ 😊 [找不同](http://leetcode-cn.com/problems/find-the-difference/) ++ 😊 [单词规律](http://leetcode-cn.com/problems/word-pattern/) ++ 😊 [字符串中的第一个唯一字符](http://leetcode-cn.com/problems/first-unique-character-in-a-string) ++ 🤔 [无重复字符的最长子串](http://leetcode-cn.com/problems/longest-substring-without-repeating-characters) ++ 🤯 [最小覆盖子串](http://leetcode-cn.com/problems/minimum-window-substring/) ++ 😊 [合并两个有序链表](http://leetcode-cn.com/problems/merge-two-sorted-lists) ++ 😊 [环形链表](http://leetcode-cn.com/problems/linked-list-cycle) ++ 🤔 [环形链表 II ](http://leetcode-cn.com/problems/linked-list-cycle-ii) ++ 😊 [反转链表](http://leetcode-cn.com/problems/reverse-linked-list) ++ 🤔 [反转链表 II ](http://leetcode-cn.com/problems/reverse-linked-list-ii) ++ 🤔 [旋转链表](http://leetcode-cn.com/problems/rotate-list) ++ 🤔 [排序链表](http://leetcode-cn.com/problems/sort-list/) ++ 😊 [链表中倒数第 k 个节点](http://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/) ++ 🤔 [两两交换链表中的节点](http://leetcode-cn.com/problems/swap-nodes-in-pairs) ++ 😊 [按奇偶排序数组](http://leetcode-cn.com/problems/sort-array-by-parity/) ++ 😊 [按奇偶排序数组 II ](http://leetcode-cn.com/problems/sort-array-by-parity-ii/) ++ 😊 [有序数组的平方](http://leetcode-cn.com/problems/squares-of-a-sorted-array/) ++ 😊 [山脉数组的峰顶索引](http://leetcode-cn.com/problems/peak-index-in-a-mountain-array) ++ 🤯 [搜索旋转排序数组](http://leetcode-cn.com/problems/search-in-rotated-sorted-array) ++ 🤔 [搜索旋转排序数组 II ](http://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/) ++ 🤔 [寻找旋转排序数组中的最小值](http://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/) ++ 🤯 [寻找旋转排序数组中的最小值 II ](http://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/) ++ 🤔 [搜索二维矩阵](http://leetcode-cn.com/problems/search-a-2d-matrix) ++ 🤔 [等式方程的可满足性](http://leetcode-cn.com/problems/satisfiability-of-equality-equations/) ++ 🤔 [朋友圈](http://leetcode-cn.com/problems/friend-circles/) ++ 🤔 [账户合并](http://leetcode-cn.com/problems/accounts-merge/) ### 二、DFS -+ [二叉树的最大深度](http://leetcode-cn.com/problems/maximum-depth-of-binary-tree) -+ [路径总和](http://leetcode-cn.com/problems/path-sum/) -+ [路径总和 II ](http://leetcode-cn.com/problems/path-sum-ii/) -+ [被围绕的区域](http://leetcode-cn.com/problems/surrounded-regions/) -+ [岛屿数量](http://leetcode-cn.com/problems/number-of-islands/) -+ [岛屿的最大面积](http://leetcode-cn.com/problems/max-area-of-island/) -+ [在二叉树中分配硬币](http://leetcode-cn.com/problems/distribute-coins-in-binary-tree/) ++ 😊 [二叉树的最大深度](http://leetcode-cn.com/problems/maximum-depth-of-binary-tree) ++ 😊 [路径总和](http://leetcode-cn.com/problems/path-sum/) ++ 🤔 [路径总和 II ](http://leetcode-cn.com/problems/path-sum-ii/) ++ 🤔 [被围绕的区域](http://leetcode-cn.com/problems/surrounded-regions/) ++ 🤔 [岛屿数量](http://leetcode-cn.com/problems/number-of-islands/) ++ 🤔 [岛屿的最大面积](http://leetcode-cn.com/problems/max-area-of-island/) ++ 🤔 [在二叉树中分配硬币](http://leetcode-cn.com/problems/distribute-coins-in-binary-tree/) ### 三、回溯 -+ [括号生成](http://leetcode-cn.com/problems/generate-parentheses/) -+ [ N 皇后](http://leetcode-cn.com/problems/n-queens/) -+ [ N 皇后 II ](http://leetcode-cn.com/problems/n-queens-ii/) -+ [解数独](http://leetcode-cn.com/problems/sudoku-solver/) -+ [不同路径 III ](http://leetcode-cn.com/problems/unique-paths-iii/) -+ [单词搜索](http://leetcode-cn.com/problems/word-search/) ++ 🤔 [括号生成](http://leetcode-cn.com/problems/generate-parentheses/) ++ 🤯 [ N 皇后](http://leetcode-cn.com/problems/n-queens/) ++ 🤯 [ N 皇后 II ](http://leetcode-cn.com/problems/n-queens-ii/) ++ 🤔 [解数独](http://leetcode-cn.com/problems/sudoku-solver/) ++ 🤯 [不同路径 III ](http://leetcode-cn.com/problems/unique-paths-iii/) ++ 🤔 [单词搜索](http://leetcode-cn.com/problems/word-search/) ### 四、分治 -+ [搜索二维矩阵 II ](http://leetcode-cn.com/problems/search-a-2d-matrix-ii/) -+ [合并 K 个排序链表](http://leetcode-cn.com/problems/merge-k-sorted-lists) -+ [为运算表达式设计优先级](http://leetcode-cn.com/problems/different-ways-to-add-parentheses) -+ [给表达式添加运算符](http://leetcode-cn.com/problems/expression-add-operators) -+ [数组中的第 K 个最大元素](http://leetcode-cn.com/problems/kth-largest-element-in-an-array) -+ [最接近原点的 K 个点](http://leetcode-cn.com/problems/k-closest-points-to-origin/) -+ [鸡蛋掉落](http://leetcode-cn.com/problems/super-egg-drop/) ++ 🤔 [搜索二维矩阵 II ](http://leetcode-cn.com/problems/search-a-2d-matrix-ii/) ++ 🤔 [合并 K 个排序链表](http://leetcode-cn.com/problems/merge-k-sorted-lists) ++ 🤔 [为运算表达式设计优先级](http://leetcode-cn.com/problems/different-ways-to-add-parentheses) ++ 🤯 [给表达式添加运算符](http://leetcode-cn.com/problems/expression-add-operators) ++ 🤔 [数组中的第 K 个最大元素](http://leetcode-cn.com/problems/kth-largest-element-in-an-array) ++ 🤔 [最接近原点的 K 个点](http://leetcode-cn.com/problems/k-closest-points-to-origin/) ++ 🤯 [鸡蛋掉落](http://leetcode-cn.com/problems/super-egg-drop/) ### 五、动态规划 -+ [使用最小花费爬楼梯](http://leetcode-cn.com/problems/min-cost-climbing-stairs) -+ [爬楼梯](http://leetcode-cn.com/problems/climbing-stairs) -+ [不同路径](http://leetcode-cn.com/problems/unique-paths/) -+ [最小路径和](http://leetcode-cn.com/problems/minimum-path-sum/) -+ [最大子序和](http://leetcode-cn.com/problems/maximum-subarray/) -+ [乘积最大子数组](http://leetcode-cn.com/problems/maximum-product-subarray/) -+ [买卖股票的最佳时机](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock) -+ [买卖股票的最佳时机 II ](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/) -+ [买卖股票的最佳时机 III ](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/) -+ [买卖股票的最佳时机 IV ](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/) -+ [最佳买卖股票时机含冷冻期](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) -+ [买卖股票的最佳时机含手续费](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee) -+ [零钱兑换](http://leetcode-cn.com/problems/coin-change) -+ [零钱兑换 II ](http://leetcode-cn.com/problems/coin-change-2) -+ [编辑距离](http://leetcode-cn.com/problems/edit-distance) -+ [不同的子序列](http://leetcode-cn.com/problems/distinct-subsequences/) -+ [柱状图中最大的矩形](http://leetcode-cn.com/problems/largest-rectangle-in-histogram/) -+ [最大矩形](http://leetcode-cn.com/problems/maximal-rectangle/) -+ [最大正方形](http://leetcode-cn.com/problems/maximal-square/) -+ [最低票价](http://leetcode-cn.com/problems/minimum-cost-for-tickets/) -+ [区域和检索 - 数组不可变](http://leetcode-cn.com/problems/range-sum-query-immutable/) -+ [二维区域和检索 - 矩阵不可变](http://leetcode-cn.com/problems/range-sum-query-2d-immutable/) -+ [最长上升子序列](http://leetcode-cn.com/problems/longest-increasing-subsequence) -+ [鸡蛋掉落](http://leetcode-cn.com/problems/super-egg-drop/) ++ 😊 [使用最小花费爬楼梯](http://leetcode-cn.com/problems/min-cost-climbing-stairs) ++ 😊 [爬楼梯](http://leetcode-cn.com/problems/climbing-stairs) ++ 😊 [不同路径](http://leetcode-cn.com/problems/unique-paths/) ++ 🤔 [最小路径和](http://leetcode-cn.com/problems/minimum-path-sum/) ++ 😊 [最大子序和](http://leetcode-cn.com/problems/maximum-subarray/) ++ 🤔 [乘积最大子数组](http://leetcode-cn.com/problems/maximum-product-subarray/) ++ 😊 [买卖股票的最佳时机](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock) ++ 😊 [买卖股票的最佳时机 II ](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/) ++ 🤯 [买卖股票的最佳时机 III ](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/) ++ 🤯 [买卖股票的最佳时机 IV ](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/) ++ 🤔 [最佳买卖股票时机含冷冻期](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) ++ 🤔 [买卖股票的最佳时机含手续费](http://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee) ++ 🤔 [零钱兑换](http://leetcode-cn.com/problems/coin-change) ++ 🤔 [零钱兑换 II ](http://leetcode-cn.com/problems/coin-change-2) ++ 🤯 [编辑距离](http://leetcode-cn.com/problems/edit-distance) ++ 🤯 [不同的子序列](http://leetcode-cn.com/problems/distinct-subsequences/) ++ 🤯 [柱状图中最大的矩形](http://leetcode-cn.com/problems/largest-rectangle-in-histogram/) ++ 🤯 [最大矩形](http://leetcode-cn.com/problems/maximal-rectangle/) ++ 🤔 [最大正方形](http://leetcode-cn.com/problems/maximal-square/) ++ 🤔 [最低票价](http://leetcode-cn.com/problems/minimum-cost-for-tickets/) ++ 😊 [区域和检索 - 数组不可变](http://leetcode-cn.com/problems/range-sum-query-immutable/) ++ 🤔 [二维区域和检索 - 矩阵不可变](http://leetcode-cn.com/problems/range-sum-query-2d-immutable/) ++ 🤔 [最长上升子序列](http://leetcode-cn.com/problems/longest-increasing-subsequence) ++ 🤯 [鸡蛋掉落](http://leetcode-cn.com/problems/super-egg-drop/) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" index 9b7d1576..6323023a 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" @@ -1,3 +1,33 @@ # 毕业总结 > [毕业刷题路线](./road.md) +> [visualgo](visualgo.net) +> [常见的复杂度](https://www.bigocheatsheet.com/) + +## 知识点 + +**基础** + ++ Array 数组 - 按下标访问 ++ Linked list 链表 ++ Stack 栈 - 括号匹配、水槽接水 ++ Queue 队列 - BFS、滑动窗口 ++ HashTable 哈希表 ++ Set、Map - HashMap、TreeMap ++ BinaryTree 二叉树 - 递归 ++ BST 二叉搜索树 ++ Search 搜索 ++ Recursion 递归 ++ DFS 深度优先搜索 ++ BFS 广度优先搜索 ++ Divide & Conquer 分治 ++ Backtracking 回溯 ++ Greedy 贪心 ++ Binary Search 二分查找 + +**进阶** + ++ Trie Tree 字典树 ++ Disjoint Set 并查集 ++ Bloom Filter 布隆过滤器(不能删除,只能清空) ++ LRU Cache(LFU、ARC) -> [cache基础知识](https://www.jianshu.com/p/8dee805a5c89) From 4d22793c323cb5acd87af97d0b9440973928ae20 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 12 Apr 2021 00:02:24 +0800 Subject: [PATCH 168/210] summary --- README.md | 2 +- .../summary.md" | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c3344256..4018551a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # 算法训练 -[毕业刷题路线](./Week_10%20%E6%AF%95%E4%B8%9A%E6%80%BB%E7%BB%93/road.md) +[刷题路线](./Week_10%20%E6%AF%95%E4%B8%9A%E6%80%BB%E7%BB%93/road.md) diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" index 6323023a..50924bee 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" @@ -1,9 +1,21 @@ # 毕业总结 > [毕业刷题路线](./road.md) + > [visualgo](visualgo.net) + > [常见的复杂度](https://www.bigocheatsheet.com/) +**一些JS的算法资料** + +> [awesome-coding-js](http://www.conardli.top/docs/) + +> [javascript-algorithms](https://github.com/trekhleb/javascript-algorithms/blob/master/README.zh-CN.md) + +**感言** + +算法这东西,其实没啥感悟好写的,算法无非是熟练、熟练、再熟练。总结,多过遍数。工作、生活场景中,多想想算法的运用场景。立个flag,工作期间也要每天刷一题leetcode,早日刷穿题库。 + ## 知识点 **基础** From 3effaa88c8a68f8589dddc86ee89ab3391b5b3a0 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 12 Apr 2021 21:12:36 +0800 Subject: [PATCH 169/210] =?UTF-8?q?=E5=BC=80=E5=A7=8B=E5=88=B7=E9=A2=98?= =?UTF-8?q?=EF=BC=9A=E6=AF=95=E4=B8=9A=E8=B7=AF=E5=BE=8401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../summary.md" | 35 +++++++++++++++++++ road/01twoSum.js | 23 ++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 road/01twoSum.js diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" index 50924bee..847bd09b 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/summary.md" @@ -16,6 +16,41 @@ 算法这东西,其实没啥感悟好写的,算法无非是熟练、熟练、再熟练。总结,多过遍数。工作、生活场景中,多想想算法的运用场景。立个flag,工作期间也要每天刷一题leetcode,早日刷穿题库。 + +**算法练习注意事项** + ++ 可以记忆算法模版,但不要背诵题目代码 ++ 尽量理解算法细节,但尽量避免单步调试 + - 多练习输出调试和纸上模拟调试 ++ 平衡看题解和自己想出的时间 + - 20分钟想不出,可以看题解,根据个人情况调整 ++ 学习他人优秀解法,但不找他人帮忙查错 + - 学会构造测试数据,学会“对拍” + +**科学“三遍刷题法”** + ++ 初学分类刷 -> 后期综合刷 ++ 一刷 + - 每个“小类别”的代表性题目,各刷几道 + - 此时需要看题解,很正常 ++ 二刷 + - 复习“代表性”题目 + - “小类别”合成“大类别”,刷该分类更多的题目,聚义反三,在尽量少的提示下完成 ++ 三刷 + - 综合性题目,尽量独立实现+测试 + +**科学“五步刷题法”** + +1. 理解题面 +2. 朴素实现/部分实现 + - 尽量让自己的解法更优,覆盖更多的场景 +3. 有提示解答 + - 看题解 vs 看提示 +4. 独立解答 + - 同时注意测试 +5. 写题解 + - 讲给别人有助于加深自己的理解,同时与别人的做法对比 + ## 知识点 **基础** diff --git a/road/01twoSum.js b/road/01twoSum.js new file mode 100644 index 00000000..b7dbad0d --- /dev/null +++ b/road/01twoSum.js @@ -0,0 +1,23 @@ +/** + * https://leetcode-cn.com/problems/two-sum/ + * 1. 两数之和 | easy + */ + +// 解法:哈希表 O(n) +function twoSum(nums, target) { + const map = new Map() + for (let i = 0; i < nums.length; ++i) { + const num = nums[i] + if (map.has(num)) { + return [map.get(num), i] + } else { + map.set(target - num, i) + } + } + return [] +} + +// ---- test case ---- +console.log(twoSum([2, 7, 11, 15], 9)) +console.log(twoSum([3, 2, 4], 6)) +console.log(twoSum([3, 3], 6)) From 8505dad431927b225c49f6f0578012180828c8f2 Mon Sep 17 00:00:00 2001 From: WilliamChew Date: Thu, 23 Nov 2023 02:02:41 +0800 Subject: [PATCH 170/210] array --- Week_01/001twoSum.js | 12 +++--- Week_01/015threeSum.js | 69 +++++++++++++++----------------- shanyue_official_account/1108.js | 38 ++++++++++++++++++ 3 files changed, 77 insertions(+), 42 deletions(-) create mode 100644 shanyue_official_account/1108.js diff --git a/Week_01/001twoSum.js b/Week_01/001twoSum.js index 991d7454..f8063b7a 100644 --- a/Week_01/001twoSum.js +++ b/Week_01/001twoSum.js @@ -6,13 +6,13 @@ const twoSum = function(nums, target) { if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 2) return [] - const m = new Map() + const map = new Map() for(let i = 0; i < nums.length; ++i) { - if (m.has(nums[i])) { - return [m.get(nums[i]), i] - } else { - m.set(target - nums[i], i) - } + if (!map.has(nums[i])) { + map.set(target - nums[i], i) + } else { + return [map.get(nums[i]), i] + } } return [] } diff --git a/Week_01/015threeSum.js b/Week_01/015threeSum.js index 9631db94..4d130e26 100644 --- a/Week_01/015threeSum.js +++ b/Week_01/015threeSum.js @@ -1,5 +1,5 @@ /** - * https://leetcode.com/problems/3sum/ + * https://leetcode-cn.com/problems/3sum/ * 015 三数之和 medium * * 思路: @@ -10,26 +10,24 @@ // 解法2 O(n^2) // trick: 用set 和 JSON.stringify 去重 -let threeSum2 = function (nums) { - if (Object.prototype.toString.apply(nums) !== '[object Array]' || nums.length < 3) return [] - nums.sort((a, b) => a - b) - let resSet = new Set(), - res = [] - for (let i = 0; i < nums.length - 2; ++i) { - let target = -nums[i], - hashmap = {} - for (let j = i + 1; j < nums.length; ++j) { - if (hashmap[nums[j]] === void(0)) { - hashmap[target - nums[j]] = j - } else { - let curItem = [-target, nums[hashmap[nums[j]]], nums[j]] - let sCurItem = JSON.stringify(curItem) - if (!resSet.has(sCurItem)) { - resSet.add(sCurItem) - res.push(curItem) - } +var threeSum2 = function(nums) { + if (!Array.isArray(nums) || nums.length < 3) return [] + nums.sort((x, y) => x - y) + const resSet = new Set(), res = [] + for (let k = 0; k < nums.length - 2 && nums[k] <= 0; ++k) { + const target = -nums[k], map = new Map() + for (let i = k + 1; i < nums.length; ++i) { + if (!map.has(nums[i])) { + map.set(target - nums[i], i) + } else { + const resItem = [k, map.get(nums[i]), i].map(x => nums[x]) + const strItem = resItem.join(',') + if (!resSet.has(strItem)) { + resSet.add(strItem) + res.push(resItem) + } + } } - } } return res }; @@ -47,25 +45,24 @@ function threeSum(nums) { if (!Array.isArray(nums) || nums.length < 3) return [] nums.sort((x, y) => x - y) const res = [] - for (let k = 0; k < nums.length - 2; ++k) { - if (nums[k] > 0) break - if (k > 0 && nums[k] === nums[k - 1]) continue - let l = k + 1, r = nums.length - 1 - while (l < r) { - const sum = nums[k] + nums[l] + nums[r] - if (sum < 0) { - while (l < r && nums[l] === nums[++l]) {} - } else if (sum > 0) { - while (l < r && nums[r] === nums[--r]) {} - } else { - res.push([nums[k], nums[l], nums[r]]) - while (l < r && nums[l] === nums[++l]) {} - while (l < r && nums[r] === nums[--r]) {} + for (let k = 0; k < nums.length - 2 && nums[k] <= 0; ++k) { + if (k > 0 && nums[k] === nums[k - 1]) continue + for (let l = k + 1, r = nums.length - 1; l < r; ) { + const sum = nums[k] + nums[l] + nums[r] + if (sum === 0) { + res.push([k, l, r].map(x => nums[x])) + while(l < r && nums[l] === nums[++l]) {} + while(l < r && nums[r] === nums[--r]) {} + } else if (sum < 0) { + while(l < r && nums[l] === nums[++l]) {} + } else { + while(l < r && nums[r] === nums[--r]) {} + } } - } + } return res } -console.log('solution 2: ', threeSum([-1, 0, 1, 2, -1, -4])) +console.log('solution 2: ', threeSum([-1, 0, 1, 2, -1])) console.log('solution 2: ', threeSum([-2, 0, 0, 2, 2])) diff --git a/shanyue_official_account/1108.js b/shanyue_official_account/1108.js new file mode 100644 index 00000000..549b134f --- /dev/null +++ b/shanyue_official_account/1108.js @@ -0,0 +1,38 @@ +const data = [ + { userId: 8, title: 'title1' }, + { userId: 11, title: 'other' }, + { userId: 15, title: null }, + { userId: 19, title: 'title2' }, +] + +const result = find(data).where({ + "title": /\d$/, + // "userId": 19, +}).orderBy('userId', 'desc'); + +console.log(result.value); + + +// 实现 find +function find(data) { + return { + value: data, + where(match) { + this.value = this.value.filter( + item => Object.entries(match).every(([key, value]) => { + if (value instanceof RegExp) { + return value.test(item[key]) + } + return item[key] === value + }) + ); + return this; + }, + orderBy(key, type) { + this.value.sort((x, y) => type === 'desc' ? y[key] - x[key] : x[key] - y[key]); + return this; + } + } +} + + From ab6b055e83f84ebf37128559ccbd51afac2d7674 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 23 Nov 2023 02:13:56 +0800 Subject: [PATCH 171/210] doc: add a comment --- Week_01/015threeSum.js | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/Week_01/015threeSum.js b/Week_01/015threeSum.js index 4d130e26..d4943476 100644 --- a/Week_01/015threeSum.js +++ b/Week_01/015threeSum.js @@ -42,26 +42,27 @@ console.log('solution 1: ', threeSum2([-1, 0, 1, 2, -1, -4])) */ function threeSum(nums) { - if (!Array.isArray(nums) || nums.length < 3) return [] - nums.sort((x, y) => x - y) - const res = [] - for (let k = 0; k < nums.length - 2 && nums[k] <= 0; ++k) { - if (k > 0 && nums[k] === nums[k - 1]) continue - for (let l = k + 1, r = nums.length - 1; l < r; ) { - const sum = nums[k] + nums[l] + nums[r] - if (sum === 0) { - res.push([k, l, r].map(x => nums[x])) - while(l < r && nums[l] === nums[++l]) {} - while(l < r && nums[r] === nums[--r]) {} - } else if (sum < 0) { - while(l < r && nums[l] === nums[++l]) {} - } else { - while(l < r && nums[r] === nums[--r]) {} - } - } + if (!Array.isArray(nums) || nums.length < 3) return [] - } - return res + nums.sort((x, y) => x - y) + const res = [] + for (let k = 0; k < nums.length - 2 && nums[k] <= 0; ++k) { + if (k > 0 && nums[k] === nums[k - 1]) continue // 与上一轮 k 相同,不用在试 + for (let l = k + 1, r = nums.length - 1; l < r; ) { + const sum = nums[k] + nums[l] + nums[r] + if (sum === 0) { + // console.log(k, l, r) + res.push([k, l, r].map(x => nums[x])) + while(l < r && nums[l] === nums[++l]) {} + while(l < r && nums[r] === nums[--r]) {} + } else if (sum < 0) { + while(l < r && nums[l] === nums[++l]) {} + } else { + while(l < r && nums[r] === nums[--r]) {} + } + } + } + return res } console.log('solution 2: ', threeSum([-1, 0, 1, 2, -1])) From d87f12504272de898f0df8947b70c4ce6c2eaee7 Mon Sep 17 00:00:00 2001 From: si3ver Date: Mon, 4 Dec 2023 10:20:45 +0800 Subject: [PATCH 172/210] feat: array --- Week_01/018fourSum.js | 40 ----------- Week_01/042trap.js | 36 ---------- Week_01/066plusOne.js | 23 ------ Week_01/070climbStairs.js | 19 ----- Week_01/088merge.js | 15 ---- Week_01/{ => array}/001twoSum.js | 0 Week_01/{ => array}/011maxArea.js | 0 Week_01/{ => array}/015threeSum.js | 0 Week_01/array/018fourSum.js | 72 +++++++++++++++++++ Week_01/{ => array}/020isValid.js | 0 Week_01/{ => array}/026removeDuplicates.js | 0 Week_01/array/042trap.js | 38 ++++++++++ Week_01/array/066plusOne.js | 33 +++++++++ Week_01/array/070climbStairs.js | 25 +++++++ Week_01/{ => array}/075sortColors.js | 0 Week_01/array/088merge.js | 26 +++++++ .../hard}/084largestRectangleArea.js | 0 Week_01/{ => linklist}/021mergeTwoLists.js | 0 Week_01/{ => linklist}/024swapPairs.js | 4 +- Week_01/{ => linklist}/092reverseBetween.js | 0 Week_01/{ => linklist}/141hasCycle.js | 0 Week_01/{ => linklist}/142detectCycle.js | 0 22 files changed, 196 insertions(+), 135 deletions(-) delete mode 100644 Week_01/018fourSum.js delete mode 100644 Week_01/042trap.js delete mode 100644 Week_01/066plusOne.js delete mode 100644 Week_01/070climbStairs.js delete mode 100644 Week_01/088merge.js rename Week_01/{ => array}/001twoSum.js (100%) rename Week_01/{ => array}/011maxArea.js (100%) rename Week_01/{ => array}/015threeSum.js (100%) create mode 100644 Week_01/array/018fourSum.js rename Week_01/{ => array}/020isValid.js (100%) rename Week_01/{ => array}/026removeDuplicates.js (100%) create mode 100644 Week_01/array/042trap.js create mode 100644 Week_01/array/066plusOne.js create mode 100644 Week_01/array/070climbStairs.js rename Week_01/{ => array}/075sortColors.js (100%) create mode 100644 Week_01/array/088merge.js rename Week_01/{ => array/hard}/084largestRectangleArea.js (100%) rename Week_01/{ => linklist}/021mergeTwoLists.js (100%) rename Week_01/{ => linklist}/024swapPairs.js (89%) rename Week_01/{ => linklist}/092reverseBetween.js (100%) rename Week_01/{ => linklist}/141hasCycle.js (100%) rename Week_01/{ => linklist}/142detectCycle.js (100%) diff --git a/Week_01/018fourSum.js b/Week_01/018fourSum.js deleted file mode 100644 index 7854743b..00000000 --- a/Week_01/018fourSum.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * https://leetcode-cn.com/problems/4sum/ - * 18. 四数之和 | medium - */ - -// O(n^3) -const fourSum = function (nums, target) { - if (!Array.isArray(nums) || nums.length < 4) return [] - nums.sort((x, y) => x - y) - const res = [] - for (let i = 0; i < nums.length - 3; ++i) { - if (i > 0 && nums[i] === nums[i - 1]) continue // unique - for (let j = i + 1; j < nums.length - 2; ++j) { - if (j > i + 1 && nums[j] === nums[j - 1]) continue //unique - let l = j + 1, r = nums.length - 1 - while (l < r) { - const sum = nums[i] + nums[j] + nums[l] + nums[r] - if (sum < target) { - while (l < r && nums[l] === nums[++l]) { } - } else if (sum > target) { - while (l < r && nums[r] === nums[--r]) { } - } else { - res.push([nums[i], nums[j], nums[l], nums[r]]) - while (l < r && nums[l] === nums[++l]) { } - while (l < r && nums[r] === nums[--r]) { } - } - } - } - } - return res -} - - -// test case -console.time('fourSum') -console.log(fourSum([], 0)) -console.log(fourSum([1,0,-1,0,-2,2], 0)) -console.log(fourSum([1,0,-1,0,-2,2], 2)) -console.log(fourSum([1,-2,-5,-4,-3,3,3,5], -11)) -console.timeEnd('fourSum') diff --git a/Week_01/042trap.js b/Week_01/042trap.js deleted file mode 100644 index d8e1b093..00000000 --- a/Week_01/042trap.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * https://leetcode.com/problems/trapping-rain-water/ - * 11. 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) - * hard | leetcode-042 | array - * - * 思路: maxLo、maxHi 记录遍历过的柱子中,左右最高柱子 - */ - -function trap (A) { - let lo = 0, hi = A.length - 1 - let res = 0 - let maxLo = 0, maxHi = 0 - while (lo < hi) { - if (A[lo] <= A[hi]) { // 左边矮于右边 - if (A[lo] >= maxLo) { // 左边提高了 - maxLo = A[lo] - } else { // 左边没提高,可以积累高度差个雨水 - res += maxLo - A[lo] - } - ++lo - } else { - if (A[hi] >= maxHi) { - maxHi = A[hi] - } else { - res += maxHi - A[hi] - } - --hi - } - console.log(lo, hi, maxLo, maxHi, res) - } - return res -} - -// ---- test case ---- -console.log(trap([0,1,0,2,1,0,1,3,2,1,2,1])) -console.log(trap([4,2,0,3,2,5])) diff --git a/Week_01/066plusOne.js b/Week_01/066plusOne.js deleted file mode 100644 index 34954f29..00000000 --- a/Week_01/066plusOne.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * https://leetcode-cn.com/problems/plus-one/ - * 9. 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) - * easy | leetcode-066 | array - */ - -// 思路:从右往左遍历,遇9进位 -const plusOne = function(digits) { - if (Object.prototype.toString.call(digits) !== '[object Array]' || digits.length < 1) return [1] - - for(let i = digits.length - 1; i >= 0; --i) { - if (digits[i] < 9) { - ++digits[i] - break - } else { - digits[i] = 0 - } - } - if (digits[0] === 0) { - digits.unshift(1) - } - return digits -} diff --git a/Week_01/070climbStairs.js b/Week_01/070climbStairs.js deleted file mode 100644 index 58ad341e..00000000 --- a/Week_01/070climbStairs.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * https://leetcode-cn.com/problems/climbing-stairs/ - * 70. 爬楼梯 | easy - * dp - * f(n) = f(n - 1) + f(n - 2) - */ - -// 思路:fibnacci数列 -const climbStairs = function(n) { - if (typeof n !== 'number') return 0 - if (n < 3) return n - let f1 = 1, f2 = 2, f3 - for (let i = 3; i <= n; ++i) { - f3 = f1 + f2 - f1 = f2 - f2 = f3 - } - return f3 -} diff --git a/Week_01/088merge.js b/Week_01/088merge.js deleted file mode 100644 index a7868f8a..00000000 --- a/Week_01/088merge.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * https://leetcode-cn.com/problems/merge-sorted-array/ - * 6. 合并两个有序数组(Facebook 在半年内面试常考) - * easy | leetcode-088 | array - */ - -const merge = function(nums1, m, nums2, n) { - if (!Array.isArray(nums1) || !Array.isArray(nums2)) return - - let i = m - 1, j = n - 1, k = m + n - 1 - while (i >= 0 && j >= 0) { - nums1[k--] = nums1[i] > nums2[j] ? nums1[i--] : nums2[j--] - } - while (j >= 0) nums1[k--] = nums2[j--] -} diff --git a/Week_01/001twoSum.js b/Week_01/array/001twoSum.js similarity index 100% rename from Week_01/001twoSum.js rename to Week_01/array/001twoSum.js diff --git a/Week_01/011maxArea.js b/Week_01/array/011maxArea.js similarity index 100% rename from Week_01/011maxArea.js rename to Week_01/array/011maxArea.js diff --git a/Week_01/015threeSum.js b/Week_01/array/015threeSum.js similarity index 100% rename from Week_01/015threeSum.js rename to Week_01/array/015threeSum.js diff --git a/Week_01/array/018fourSum.js b/Week_01/array/018fourSum.js new file mode 100644 index 00000000..437a7d11 --- /dev/null +++ b/Week_01/array/018fourSum.js @@ -0,0 +1,72 @@ +/** + * https://leetcode-cn.com/problems/4sum/ + * 18. 四数之和 | medium + */ + +// O(n^3) +// const fourSum = function (nums, target) { +// if (!Array.isArray(nums) || nums.length < 4) return [] +// nums.sort((x, y) => x - y) +// const res = [] +// for (let i = 0; i < nums.length - 3; ++i) { +// if (i > 0 && nums[i] === nums[i - 1]) continue // unique +// for (let j = i + 1; j < nums.length - 2; ++j) { +// if (j > i + 1 && nums[j] === nums[j - 1]) continue //unique +// let l = j + 1, r = nums.length - 1 +// while (l < r) { +// const sum = nums[i] + nums[j] + nums[l] + nums[r] +// if (sum < target) { +// while (l < r && nums[l] === nums[++l]) { } +// } else if (sum > target) { +// while (l < r && nums[r] === nums[--r]) { } +// } else { +// res.push([nums[i], nums[j], nums[l], nums[r]]) +// while (l < r && nums[l] === nums[++l]) { } +// while (l < r && nums[r] === nums[--r]) { } +// } +// } +// } +// } +// return res +// } + +/** + * @param {number[]} nums + * @param {number} target + * @return {number[][]} + */ +var fourSum = function(nums, target) { + if (!Array.isArray(nums) || nums.length < 4) return []; + nums.sort((x, y) => x - y); + const res = []; + for (let i = 0; i < nums.length - 3 && nums[i] <= 0; ++i) { + if (i > 0 && nums[i] === nums[i - 1]) continue; + console.log('i>>>', i) + for (let j = i + 1; j < nums.length - 2; ++j) { + if (j > i + 1 && nums[j] === nums[j - 1]) continue; + console.log('j>>>', j) + for (let l = j + 1, r = nums.length - 1; l < r;) { + const sum = nums[i] + nums[j] + nums[l] + nums[r]; + console.log(i, j, l, r, sum) + if (sum === target) { + res.push([i, j, l, r].map(x => nums[x])); + while(l < r && nums[l] === nums[++l]) {}; + while(l < r && nums[r] === nums[--r]) {}; + } else if (sum < target) { + while(l < r && nums[l] === nums[++l]) {}; + } else { + while(l < r && nums[r] === nums[--r]) {}; + } + } + } + } + return res; +}; + +// test case +console.time('fourSum') +console.log(fourSum([], 0)) +console.log(fourSum([1,0,-1,0,-2,2], 0)) +console.log(fourSum([1,0,-1,0,-2,2], 2)) +console.log(fourSum([1,-2,-5,-4,-3,3,3,5], -11)) +console.timeEnd('fourSum') diff --git a/Week_01/020isValid.js b/Week_01/array/020isValid.js similarity index 100% rename from Week_01/020isValid.js rename to Week_01/array/020isValid.js diff --git a/Week_01/026removeDuplicates.js b/Week_01/array/026removeDuplicates.js similarity index 100% rename from Week_01/026removeDuplicates.js rename to Week_01/array/026removeDuplicates.js diff --git a/Week_01/array/042trap.js b/Week_01/array/042trap.js new file mode 100644 index 00000000..bae9b860 --- /dev/null +++ b/Week_01/array/042trap.js @@ -0,0 +1,38 @@ +/** + * https://leetcode.com/problems/trapping-rain-water/ + * 11. 接雨水(亚马逊、字节跳动、高盛集团、Facebook 在半年内面试常考) + * hard | leetcode-042 | array + * + * 思路: maxLo、maxHi 记录遍历过的柱子中,左右最高柱子 + */ + +/** + * @param {number[]} height + * @return {number} + */ +var trap = function(A) { + let res = 0; + for (let maxR = maxL = l = 0, r = A.length - 1; l < r;) { + if (A[l] < A[r]) { + if (maxL < A[l]) { + maxL = A[l]; + } else { + res += maxL - A[l]; + } + ++l; + } else { + if (maxR < A[r]) { + maxR = A[r]; + } else { + res += maxR - A[r]; + } + --r; + } + console.log('aaa', l, r, maxL, maxR, res) + } + return res; +}; + +// ---- test case ---- +console.log(trap([0,1,0,2,1,0,1,3,2,1,2,1])) +console.log(trap([4,2,0,3,2,5])) diff --git a/Week_01/array/066plusOne.js b/Week_01/array/066plusOne.js new file mode 100644 index 00000000..d281d81c --- /dev/null +++ b/Week_01/array/066plusOne.js @@ -0,0 +1,33 @@ +/** + * https://leetcode-cn.com/problems/plus-one/ + * 9. 加一(谷歌、字节跳动、Facebook 在半年内面试中考过) + * easy | leetcode-066 | array + */ + +// 思路:从右往左遍历,遇9进位 +/** + * @param {number[]} digits + * @return {number[]} + */ +var plusOne = function(digits) { + if (!Array.isArray(digits) || !digits.length) return [1]; + + for (let i = digits.length - 1; i >= 0; --i) { + if (digits[i] < 9) { + digits[i] += 1; + break; + } else { + digits[i] = 0; + } + } + if (digits[0] === 0) { + digits.unshift(1); + } + return digits; +}; + +console.time('plusOne') +console.log(plusOne([1, 2, 3])) +console.log(plusOne([8, 9, 9])) +console.log(plusOne([9, 9, 9])) +console.timeEnd('plusOne') diff --git a/Week_01/array/070climbStairs.js b/Week_01/array/070climbStairs.js new file mode 100644 index 00000000..556e64c5 --- /dev/null +++ b/Week_01/array/070climbStairs.js @@ -0,0 +1,25 @@ +/** + * https://leetcode-cn.com/problems/climbing-stairs/ + * 70. 爬楼梯 | easy + * dp + * f(n) = f(n - 1) + f(n - 2) + */ + +// 思路:fibnacci数列 +/** + * @param {number} n + * @return {number} + */ +var climbStairs = function(n) { + if (typeof n !== 'number') return 0; + + if (n < 3) return n; + + let f1 = 1, f2 = 2, f3; + for (let i = 3; i <= n; ++i) { + f3 = f1 + f2; + f1 = f2; + f2 = f3; + } + return f3; +}; diff --git a/Week_01/075sortColors.js b/Week_01/array/075sortColors.js similarity index 100% rename from Week_01/075sortColors.js rename to Week_01/array/075sortColors.js diff --git a/Week_01/array/088merge.js b/Week_01/array/088merge.js new file mode 100644 index 00000000..4d495f8c --- /dev/null +++ b/Week_01/array/088merge.js @@ -0,0 +1,26 @@ +/** + * https://leetcode-cn.com/problems/merge-sorted-array/ + * 6. 合并两个有序数组(Facebook 在半年内面试常考) + * easy | leetcode-088 | array + * + * 思路:O(n), 尾部比较,nums1[k--] = xxx + */ + +/** + * @param {number[]} nums1 + * @param {number} m + * @param {number[]} nums2 + * @param {number} n + * @return {void} Do not return anything, modify nums1 in-place instead. + */ +var merge = function(nums1, m, nums2, n) { + if (!Array.isArray(nums1) || !Array.isArray(nums1)) return; + + let i = m - 1, j = n - 1, k = m + n - 1; + while (i >= 0 && j >= 0) { + nums1[k--] = nums1[i] > nums2[j] ? nums1[i--] : nums2[j--]; + } + while(j >= 0) { + nums1[k--] = nums2[j--]; + } +}; diff --git a/Week_01/084largestRectangleArea.js b/Week_01/array/hard/084largestRectangleArea.js similarity index 100% rename from Week_01/084largestRectangleArea.js rename to Week_01/array/hard/084largestRectangleArea.js diff --git a/Week_01/021mergeTwoLists.js b/Week_01/linklist/021mergeTwoLists.js similarity index 100% rename from Week_01/021mergeTwoLists.js rename to Week_01/linklist/021mergeTwoLists.js diff --git a/Week_01/024swapPairs.js b/Week_01/linklist/024swapPairs.js similarity index 89% rename from Week_01/024swapPairs.js rename to Week_01/linklist/024swapPairs.js index e9dd1750..6c69b66e 100644 --- a/Week_01/024swapPairs.js +++ b/Week_01/linklist/024swapPairs.js @@ -5,7 +5,7 @@ */ // 思路1: 递归 -const swapPairs = function(head) { +const swapPairs1 = function(head) { // terminator if (!head || !head.next) return head // process & drill down @@ -17,7 +17,7 @@ const swapPairs = function(head) { } // 思路2: 非递归(空指针头) -const swapPairs = function(head) { +const swapPairs2 = function(head) { const dummy = new ListNode(-1, head) let prev = dummy while (prev.next && prev.next.next) { diff --git a/Week_01/092reverseBetween.js b/Week_01/linklist/092reverseBetween.js similarity index 100% rename from Week_01/092reverseBetween.js rename to Week_01/linklist/092reverseBetween.js diff --git a/Week_01/141hasCycle.js b/Week_01/linklist/141hasCycle.js similarity index 100% rename from Week_01/141hasCycle.js rename to Week_01/linklist/141hasCycle.js diff --git a/Week_01/142detectCycle.js b/Week_01/linklist/142detectCycle.js similarity index 100% rename from Week_01/142detectCycle.js rename to Week_01/linklist/142detectCycle.js From 539457c22c8713b96848410f5ca96dbb5fc66eb9 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 5 Dec 2023 00:07:42 +0800 Subject: [PATCH 173/210] feat: array --- Week_01/array/020isValid.js | 45 +++++++++++++++--------------- Week_01/{ => array}/155MinStack.js | 0 2 files changed, 22 insertions(+), 23 deletions(-) rename Week_01/{ => array}/155MinStack.js (100%) diff --git a/Week_01/array/020isValid.js b/Week_01/array/020isValid.js index 41dfd949..7c401fb0 100644 --- a/Week_01/array/020isValid.js +++ b/Week_01/array/020isValid.js @@ -1,31 +1,30 @@ /** * https://leetcode-cn.com/problems/valid-parentheses/ * 【stack】 - * + * */ -const isValid = function(s) { - const stack = [], - m = new Map([ - [')', '('], - [']', '['], - ['}', '{'] - ]) - - let res = true - for(let i = 0; i < s.length; ++i) { - const ch = s[i] - if (!m.has(ch)) { - stack.push(ch) - } else { - if (stack.length > 0 && stack[stack.length - 1] === m.get(ch)) { - stack.pop() +/** + * @param {string} s + * @return {boolean} + */ +var isValid = function(s) { + const m = new Map([ + ['(', ')'], + ['[', ']'], + ['{', '}'], + ]); + const stack = []; + let isMatch = true; + for (let i = 0; i < s.length; ++i) { + const ch = s[i]; + if (m.has(ch)) { + stack.push(m.get(ch)); + } else if (stack.length && stack[stack.length - 1] === ch) { + stack.pop(); } else { - res = false - break + isMatch = false; } - } } - - return stack.length ? false : res -} + return isMatch && stack.length === 0; +}; diff --git a/Week_01/155MinStack.js b/Week_01/array/155MinStack.js similarity index 100% rename from Week_01/155MinStack.js rename to Week_01/array/155MinStack.js From ca46f78d3717ea4e5709199a2eef57e0cb282e0b Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 5 Dec 2023 14:59:36 +0800 Subject: [PATCH 174/210] feat: array & trick & hot100 --- .editorconfig | 2 +- Week_01/189rotate.js | 24 ---------- Week_01/array/189rotate.js | 37 +++++++++++++++ Week_01/{ => array}/283moveZeros.js | 0 Week_01/{ => linklist}/206reverseList.js | 0 Week_02/049groupAnagram.js | 43 +++++++++-------- hot100/128longestConsecutive.js | 60 ++++++++++++++++++++++++ hot100/739dailyTemperatures.js | 26 ++++++++++ hot100/stack/394decodeString.js | 41 ++++++++++++++++ 9 files changed, 188 insertions(+), 45 deletions(-) delete mode 100644 Week_01/189rotate.js create mode 100644 Week_01/array/189rotate.js rename Week_01/{ => array}/283moveZeros.js (100%) rename Week_01/{ => linklist}/206reverseList.js (100%) create mode 100644 hot100/128longestConsecutive.js create mode 100644 hot100/739dailyTemperatures.js create mode 100644 hot100/stack/394decodeString.js diff --git a/.editorconfig b/.editorconfig index 7053c49a..a1879fcd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,5 @@ [*.{js,jsx,ts,tsx,vue}] indent_style = space -indent_size = 2 +indent_size = 4 trim_trailing_whitespace = true insert_final_newline = true diff --git a/Week_01/189rotate.js b/Week_01/189rotate.js deleted file mode 100644 index 2056d079..00000000 --- a/Week_01/189rotate.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * https://leetcode-cn.com/problems/rotate-array/ - * 4. 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) - * medium | leetcode-189 | array - * 思路:反转三次,时间复杂度O(n), 空间复杂度O(1) - */ - -// O(1)空间复杂度解法: 反转3次 -const rotate = function(nums, k) { - if (Object.prototype.toString.call(nums) !== '[object Array]' || nums.length < 2) return - - const reverse = (nums, start, end) => { - while(start < end) { - const tmp = nums[start] - nums[start++] = nums[end] - nums[end--] = tmp - } - } - - k %= nums.length - reverse(nums, 0, nums.length - 1) - reverse(nums, 0, k - 1) - reverse(nums, k, nums.length - 1) -} diff --git a/Week_01/array/189rotate.js b/Week_01/array/189rotate.js new file mode 100644 index 00000000..15449493 --- /dev/null +++ b/Week_01/array/189rotate.js @@ -0,0 +1,37 @@ +/** + * https://leetcode-cn.com/problems/rotate-array/ + * 4. 旋转数组(微软、亚马逊、PayPal 在半年内面试中考过) + * medium | leetcode-189 | array + * 思路:反转三次,时间复杂度O(n), 空间复杂度O(1) + */ + +// O(n) 时间复杂度,O(1)空间复杂度解法: 反转3次 +const rotate = function(nums, k) { + if (!Array.isArray(nums) || nums.length < 2) return; + + const reverse = (start, end) => { + while (start < end) { + const tmp = nums[start]; + nums[start++] = nums[end]; + nums[end--] = tmp; + } + } + + k = k % nums.length; + reverse(0, nums.length - 1); + reverse(0, k - 1); + reverse(k, nums.length - 1) +} + +// 方法二:splice 剪切法~ 空间复杂度 O(k) +const rotate2 = function (nums, k) { + k = k % nums.length; + nums.splice(0, 0, ...nums.splice(-k)); +} + +// ---- test ---- +var arr1 = [1,2,3,4,5,6,7], arr2 = Array.from(arr1), k = 3; +console.log('rotate:', arr1, arr2) +rotate(arr1, k); +rotate2(arr2, k); +console.log('rotate:', arr1, arr2) diff --git a/Week_01/283moveZeros.js b/Week_01/array/283moveZeros.js similarity index 100% rename from Week_01/283moveZeros.js rename to Week_01/array/283moveZeros.js diff --git a/Week_01/206reverseList.js b/Week_01/linklist/206reverseList.js similarity index 100% rename from Week_01/206reverseList.js rename to Week_01/linklist/206reverseList.js diff --git a/Week_02/049groupAnagram.js b/Week_02/049groupAnagram.js index 314529dc..dd0456ef 100644 --- a/Week_02/049groupAnagram.js +++ b/Week_02/049groupAnagram.js @@ -1,30 +1,33 @@ /** * https://leetcode-cn.com/problems/group-anagrams/ * 字母异位词分组 - * - * 【map】 - * + * + * 【hashmap】 + * */ -const groupAnagrams = function(strs) { - if (!Object.prototype.toString.apply(strs) === '[object Array]' - || strs.length < 1 - ) return [] - const m = {}, startCodePoint = 'a'.codePointAt(0) +/** + * @param {string[]} strs + * @return {string[][]} + */ +var groupAnagrams = function(strs) { + if (!Array.isArray(strs) || strs.length < 1) return [] + + const m = new Map(), startCp = 'a'.codePointAt(0); strs.forEach(str => { - const cntArr = new Array(26).fill(0) - for(let i = 0; i < str.length; ++i) { - ++cntArr[str.codePointAt(i) - startCodePoint] - } - const key = cntArr.toString() - if (m[key] === void(0)) { - m[key] = [str] - } else { - m[key].push(str) - } + const cntArr = Array(26).fill(0); + for (let i = 0; i < str.length; ++i) { + cntArr[str.codePointAt(i) - startCp] += 1; + } + const key = cntArr.toString(); + if (!m.has(key)) { + m.set(key, [str]) + } else { + m.set(key, [...m.get(key), str]) + } }) - return Object.values(m) -} + return Array.from(m.values()); +}; // ---- test case ---- diff --git a/hot100/128longestConsecutive.js b/hot100/128longestConsecutive.js new file mode 100644 index 00000000..abb38c4b --- /dev/null +++ b/hot100/128longestConsecutive.js @@ -0,0 +1,60 @@ +/** + * https://leetcode.cn/problems/longest-consecutive-sequence + * 128. 最长连续序列 + * + * 【map】 + * + */ +// /** +// * @param {number[]} nums +// * @return {number} +// * 思路一:排序后,检查连续性 O(nlogn) +// */ +// var longestConsecutive = function(nums) { +// if (!Array.isArray(nums) || nums.length < 1) return 0; + +// nums.sort((x, y) => x - y); + +// let count = 1, max = 1; +// for (let i = 1; i < nums.length; ++i) { +// if (nums[i] === nums[i - 1]) { +// continue; +// } else if (nums[i] === nums[i - 1] + 1) { +// count++; +// max = Math.max(max, count); +// } else { +// count = 1; +// } +// } +// return max; +// }; + + +/** + * @param {number[]} nums + * @return {number} + * 思路二:set 去重,遍历set,判断是起点则往后找, O(n) + */ +var longestConsecutive = function(nums) { + if (!Array.isArray(nums) || nums.length < 1) return 0; + + const set = new Set(nums); + let maxCount = 0; + for (const num of set) { + if (!set.has(num - 1)) { + let currentNum = num; + let count = 1; + while (set.has(currentNum + 1)) { + currentNum += 1; + count += 1; + } + maxCount = Math.max(maxCount, count); + } + } + return maxCount; +}; + +// ---- test case ---- +console.log(longestConsecutive([100,4,200,1,3,2])) // 4 +console.log(longestConsecutive([0,3,7,2,5,8,4,6,0,1])) // 9 +console.log(longestConsecutive([1, 2, 0, 1])) // 3 diff --git a/hot100/739dailyTemperatures.js b/hot100/739dailyTemperatures.js new file mode 100644 index 00000000..ba53324e --- /dev/null +++ b/hot100/739dailyTemperatures.js @@ -0,0 +1,26 @@ +/** + * https://leetcode.cn/problems/longest-consecutive-sequence + * 每日温度 + * + * 单调递减栈:遍历整个数组,如果栈不空,且当前数字大于栈顶元素,那么如果直接入栈的话就不是 递减栈 ,所以需要取出栈顶元素,由于当前数字大于栈顶元素的数字,而且一定是第一个大于栈顶元素的数,直接求出下标差就是二者的距离。 + * + * 思路: + */ + +/** + * @param {number[]} temperatures + * @return {number[]} + */ +var dailyTemperatures = function(A) { + const stack = [], res = Array(A.length).fill(0); + for (let i = 0; i < A.length; ++i) { + while(stack.length && A[i] > A[stack[stack.length - 1]]) { + const topIndex = stack.pop(); + res[topIndex] = i - topIndex; + } + stack.push(i); + } + return res; +}; + +// ---- test ---- diff --git a/hot100/stack/394decodeString.js b/hot100/stack/394decodeString.js new file mode 100644 index 00000000..9eae954f --- /dev/null +++ b/hot100/stack/394decodeString.js @@ -0,0 +1,41 @@ +/** + * https://leetcode.cn/problems/decode-string + * 字符串解码 + * + * 【stack】 + * + */ + +/** + * @param {string} s + * @return {string} + * + * 解法:辅助栈 item 存 [multi, res] + */ +var decodeString = function(s) { + const stack = []; + let res = '', multi = 0; + for (const ch of s) { + const isNumber = !Number.isNaN(Number(ch)); + if (isNumber) { + multi = multi * 10 + Number(ch); + } else if (ch === '[') { + stack.push([res, multi]); + res = ''; + multi = 0; + } else if (ch === ']') { + const [lastRes, curMulti] = stack.pop(); + res = lastRes + res.repeat(curMulti); + } else { + res = `${res}${ch}`; + } + console.log(ch, res); + } + return res; +}; + +// ---- test ---- +console.log(decodeString('3[a]2[bc]')); +console.log(decodeString('3[a2[c]]')); +console.log(decodeString('2[abc]3[cd]ef')); +console.log(decodeString('abc3[cd]xyz')); From 0f60ca714d658fc8108a0d1ac29767adca7afc33 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 5 Dec 2023 22:26:20 +0800 Subject: [PATCH 175/210] feat: hot100 --- hot100/031nextPermutation.js | 52 ++++++++++++++++++++++++++++++++++++ hot100/287findDuplicate.js | 29 ++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 hot100/031nextPermutation.js create mode 100644 hot100/287findDuplicate.js diff --git a/hot100/031nextPermutation.js b/hot100/031nextPermutation.js new file mode 100644 index 00000000..9edd95c2 --- /dev/null +++ b/hot100/031nextPermutation.js @@ -0,0 +1,52 @@ +/** + * https://leetcode.cn/problems/next-permutation/description/ + * + * 下一个排列 + * + * 思路:找升序对,交换来个大一点儿的,后半部份逆序为升序。 + */ + + +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +var nextPermutation = function(nums) { + if (!Array.isArray(nums) || nums.length < 1) return; + + // Step1: 从后往前,找到连续的升序对 A[pos] < A[pos + 1] + let pos = - 1; + for (let i = nums.length - 2; i >= 0; --i) { + if (nums[i] < nums[i + 1]) { // 升序对 + pos = i; + break; + } + } + if (pos === -1) { + nums.reverse(); + return + } + + // Step2: 从后往前,找到第一个大于 A[pos] 的值交换,如 12354 -> 12453 + for (let i = nums.length - 1; i > pos; --i) { + if (nums[i] > nums[pos]) { + const tmp = nums[pos]; + nums[pos] = nums[i]; + nums[i] = tmp; + break; + } + } + + // Step3: 逆置 pos+1, end + for (let l = pos + 1, r = nums.length -1; l < r; ++l, --r) { + const tmp = nums[l]; + nums[l] = nums[r]; + nums[r] = tmp; + } +}; + +// ---- test ---- +const arr1 = [1, 2, 3, 5, 4]; +nextPermutation(arr1); +console.log(arr1); // [1, 2, 4, 3, 5] + diff --git a/hot100/287findDuplicate.js b/hot100/287findDuplicate.js new file mode 100644 index 00000000..43f2d498 --- /dev/null +++ b/hot100/287findDuplicate.js @@ -0,0 +1,29 @@ +/** + * https://leetcode.cn/problems/find-the-duplicate-number/ + * + * trick + * + * 思考,元素的范围是 1 ~ len-1,这些数可以看作下标,构成一个有环链表。 + * 思路:快慢指针变种 + */ + + +/** + * @param {number[]} nums + * @return {number} + */ +var findDuplicate = function(nums) { + let slow = fast = 0, hasCycle = false; + do { + slow = nums[slow]; + fast = nums[nums[fast]]; + } while (slow !== fast); + + fast = 0; + do { + slow = nums[slow]; + fast = nums[fast]; + } while (slow !== fast); + + return fast; +}; From e5e2a4803f2619915addaa90959816f26024e873 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 6 Dec 2023 23:33:58 +0800 Subject: [PATCH 176/210] feat: hot100 --- Week_04/074searchMatrix.js | 10 +++--- Week_04/240searchMatrix.js | 37 +++++++++++++++++++++++ codetop/054spiralOrder.js | 62 +++++++++++++++++++++----------------- hot100/035searchInsert.js | 25 +++++++++++++++ hot100/048rotate.js | 31 +++++++++++++++++++ hot100/118generate.js | 28 +++++++++++++++++ 6 files changed, 161 insertions(+), 32 deletions(-) create mode 100644 Week_04/240searchMatrix.js create mode 100644 hot100/035searchInsert.js create mode 100644 hot100/048rotate.js create mode 100644 hot100/118generate.js diff --git a/Week_04/074searchMatrix.js b/Week_04/074searchMatrix.js index 227c6333..68b2f82b 100644 --- a/Week_04/074searchMatrix.js +++ b/Week_04/074searchMatrix.js @@ -1,15 +1,17 @@ /** * https://leetcode-cn.com/problems/search-a-2d-matrix/ - * + * * 74. 搜索二维矩阵 - * + * * 0 1 2 3 4 5 6 7 8 9 10 11 * 00 01 02 03, 10 11 12 13, 20 21 22 23 * m = 3, n = 4 - * + * * x -> i, j - * + * * i = Math.floor(x / n), j = x % n + * + * 复杂度 log(mn) = log(m) + log(n) < logm * logn < O(m + n) < O(mn) */ const searchMatrix = function(matrix, target) { diff --git a/Week_04/240searchMatrix.js b/Week_04/240searchMatrix.js new file mode 100644 index 00000000..8a33d495 --- /dev/null +++ b/Week_04/240searchMatrix.js @@ -0,0 +1,37 @@ +/** + * https://leetcode.cn/problems/search-a-2d-matrix-ii + * + * 搜索二维矩阵 II + * + */ + +const searchMatrix = function(matrix, target) { + const _getVal = (idx) => { + const x = Math.floor(idx / n) + const y = idx % n + return matrix[x][y] + } + const m = matrix.length, n = matrix[0].length + let lo = 0, hi = m * n - 1 + while (lo <= hi) { + const mid = lo + ((hi - lo) >> 1) + const val = _getVal(mid) + if (val === target) { + return true + } else if (val > target){ + hi = mid - 1 + } else { + lo = mid + 1 + } + } + return false + } + + // ---- test case ---- + const matrix = [ + [ 1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 60], + ] + console.log(searchMatrix(matrix, 3)) + console.log(searchMatrix(matrix, 13)) diff --git a/codetop/054spiralOrder.js b/codetop/054spiralOrder.js index 6aa028b9..85771b2c 100644 --- a/codetop/054spiralOrder.js +++ b/codetop/054spiralOrder.js @@ -3,28 +3,34 @@ * 54. 螺旋矩阵 | medium */ -function spiralOrder (A) { - const m = A.length, n = A[0].length - const visited = [...Array(m)].map(() => Array(n).fill(0)) - let dir = 0, c = 0, r = 0 - const dr = [0, 1, 0, -1] - const dc = [1, 0, -1, 0] - const res = [] - for (let i = 0; i < m * n; ++i) { - res.push(A[r][c]) - visited[r][c] = 1 - let nr = r + dr[dir] - let nc = c + dc[dir] - if (nr < 0 || nr >= m || nc < 0 || nc >= n || visited[nr][nc] === 1) { - dir = (dir + 1) % 4 - nr = r + dr[dir] - nc = c + dc[dir] +/** + * @param {number[][]} matrix + * @return {number[]} + */ +var spiralOrder = function(matrix) { + const m = matrix.length; n = matrix[0].length; + const visited = Array(m).fill(true).map(() => Array(n).fill(false)); + + let dir = 0, r = 0, c = 0; // dir 指方向,0 右 1 下 2 左 3 上 + const dr = [0, 1, 0, -1]; + const dc = [1, 0, -1, 0]; + const res = []; + for (let i = 0; i < m * n; ++i) { + res.push(matrix[r][c]); + + visited[r][c] = true; + let nextR = r + dr[dir]; + let nextC = c + dc[dir]; + if (nextR < 0 || nextR >= m || nextC < 0 || nextC >= n || visited[nextR][nextC]) { + dir = (dir + 1) % 4; + nextR = r + dr[dir]; + nextC = c + dc[dir]; + } + r = nextR; + c = nextC; } - r = nr - c = nc - } - return res -} + return res; +}; // ---- test case ---- console.log(spiralOrder( @@ -34,10 +40,10 @@ console.log(spiralOrder( [7,8,9] ] )) -console.log(spiralOrder( - [ - [1, 2, 3, 4], - [5, 6, 7, 8], - [9,10,11,12] - ] -)) +// console.log(spiralOrder( +// [ +// [1, 2, 3, 4], +// [5, 6, 7, 8], +// [9,10,11,12] +// ] +// )) diff --git a/hot100/035searchInsert.js b/hot100/035searchInsert.js new file mode 100644 index 00000000..81dd2d41 --- /dev/null +++ b/hot100/035searchInsert.js @@ -0,0 +1,25 @@ +/** + * https://leetcode.cn/problems/search-insert-position + * + * 搜索插入位置 + * + * 思路:二分查找 + */ + +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var searchInsert = function(nums, target) { + let lo = 0, hi = nums.length - 1; + while (lo <= hi) { + const mid = lo + ((hi - lo) >> 1); + if (nums[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return lo; +}; diff --git a/hot100/048rotate.js b/hot100/048rotate.js new file mode 100644 index 00000000..b1b7efa1 --- /dev/null +++ b/hot100/048rotate.js @@ -0,0 +1,31 @@ +/** + * https://leetcode.cn/problems/rotate-image + * + * 旋转图像 + * + * 思路:上下翻转 + 对角线翻转 + */ + +/** + * @param {number[][]} matrix + * @return {void} Do not return anything, modify matrix in-place instead. + */ +var rotate = function(matrix) { + const swap = (i, j, k, l) => { + const tmp = matrix[i][j]; + matrix[i][j] = matrix[k][l]; + matrix[k][l] = tmp; + } + + const n = matrix.length; + for (let i = 0; i < (n >> 1); ++i) { + for (let j = 0; j < n; ++j) { + swap(i, j, n - i - 1 ,j); + } + } + for (let i = 1; i < n; ++i) { + for (let j = 0; j < i; ++j) { + swap(i, j, j, i); + } + } +}; diff --git a/hot100/118generate.js b/hot100/118generate.js new file mode 100644 index 00000000..71f3f75c --- /dev/null +++ b/hot100/118generate.js @@ -0,0 +1,28 @@ +/** + * https://leetcode.cn/problems/pascals-triangle + * + * 杨辉三角 + * + * 思路:生成器,f(i, j) = f(i-1, j-1) + f(i-1, j) + */ + +/** + * @param {number} numRows + * @return {number[][]} + */ +var generate = function(numRows) { + const res = []; + for (let i = 0; i < numRows; ++i) { + const row = Array(i + 1).fill(1); + for (let j = 1; j < i; ++j) { + row[j] = res[i - 1][j - 1] + res[i - 1][j]; + // console.log('inner', i, j, res[i - 1], row) + } + // console.log(row) + res.push(row); + } + return res; +}; + +// --- test --- +console.log(generate(5)) From fdd6bc5789f750da3990b94fa3bb56ca3e56749e Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 7 Dec 2023 16:34:39 +0800 Subject: [PATCH 177/210] feat: solve leet --- Week_02/094inorderTraversal.js | 48 +++++++++++++------------- Week_02/104.js | 11 ------ Week_02/104maxDepth.js | 25 ++++++++++++++ Week_03/104maxDepth.js | 2 +- Week_03/226invertTree.js | 19 ++++++++++ Week_04/102levelOrder.js | 32 ++++++++--------- hot100/tree/101isSymmetric.js | 38 ++++++++++++++++++++ hot100/tree/543diameterOfBinaryTree.js | 11 ++++++ 8 files changed, 134 insertions(+), 52 deletions(-) delete mode 100644 Week_02/104.js create mode 100644 Week_02/104maxDepth.js create mode 100644 hot100/tree/101isSymmetric.js create mode 100644 hot100/tree/543diameterOfBinaryTree.js diff --git a/Week_02/094inorderTraversal.js b/Week_02/094inorderTraversal.js index 74f93dae..dd4d87ff 100644 --- a/Week_02/094inorderTraversal.js +++ b/Week_02/094inorderTraversal.js @@ -3,30 +3,30 @@ */ // 1. 递归DFS -const inorderTraversal1 = function(root) { - if (root == null) return [] - const res = [] - const dfs = (p) => { - if(p.left) dfs(p.left) - res.push(p.val) - if(p.right) dfs(p.right) - } - dfs(root) - return res -} +var inorderTraversal = function(root) { + if (root == null) return [] + const res = []; + const dfs = (p) => { + if (p.left) dfs(p.left); + res.push(p.val); + if (p.right) dfs(p.right); + } + dfs(root); + return res; +}; // 2. 非递归,手动维护stack -const inorderTraversal = function(root) { - if (root == null) return [] - const res = [], stack = [] - while(root || stack.length) { - while (root) { // 往左一直寻找,压栈 - stack.push(root) - root = root.left +var inorderTraversal = function(root) { + if (root == null) return []; + const res = [], stack = []; + while (root || stack.length) { + while (root) { // 往左找到底 + stack.push(root); + root = root.left; + } + root = stack.pop(); // 根 + res.push(root.val); + root = root.right; // 右 } - root = stack.pop() - res.push(root.val) - root = root.right - } - return res -} + return res; +}; diff --git a/Week_02/104.js b/Week_02/104.js deleted file mode 100644 index d794ba94..00000000 --- a/Week_02/104.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/submissions/ - * 思路:递归遍历左右子树 - */ - -var maxDepth = function(root) { - if (!root) return 0 - const left = maxDepth(root.left) - const right = maxDepth(root.right) - return Math.max(left, right) + 1 -}; diff --git a/Week_02/104maxDepth.js b/Week_02/104maxDepth.js new file mode 100644 index 00000000..cadfd71a --- /dev/null +++ b/Week_02/104maxDepth.js @@ -0,0 +1,25 @@ +/** + * https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/submissions/ + * 思路:递归遍历左右子树 + */ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ + +/** + * @param {TreeNode} root + * @return {number} + * // 1 递归 + */ +var maxDepth = function(root) { + if (!root) return 0; + const left = maxDepth(root.left); + const right = maxDepth(root.right); + return Math.max(left, right) + 1; +}; + diff --git a/Week_03/104maxDepth.js b/Week_03/104maxDepth.js index 1f76a557..14ad4e15 100644 --- a/Week_03/104maxDepth.js +++ b/Week_03/104maxDepth.js @@ -1,7 +1,7 @@ /** * https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/ * https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/ - * + * * 剑指 Offer 55 - I. 二叉树的深度 */ diff --git a/Week_03/226invertTree.js b/Week_03/226invertTree.js index 0c8b8023..f2a2f26e 100644 --- a/Week_03/226invertTree.js +++ b/Week_03/226invertTree.js @@ -28,3 +28,22 @@ const invertTree = function(root) { // revert states return root } + +// queue + bfs +var invertTree2 = function(root) { + if (!root) return root; + let queue = [root]; + while (queue.length) { + const node = queue.pop(); + const tmp = node.left; + node.left = node.right; + node.right = tmp; + if (node.left) { + queue.unshift(node.left); + } + if (node.right) { + queue.unshift(node.right); + } + } + return root; +}; diff --git a/Week_04/102levelOrder.js b/Week_04/102levelOrder.js index fc78259f..108e05d1 100644 --- a/Week_04/102levelOrder.js +++ b/Week_04/102levelOrder.js @@ -1,24 +1,24 @@ /** * https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ - * 102. 二叉树的层序遍历 - * + * 二叉树的层序遍历 + * * 思路:【BFS】 * 手动维护queue (push + unshift) * 内层维护一个循环,循环当前queue的size,为一层(null不要加入queue) */ -function levelOrder(root) { - if (root == null) return [] - const res = [], queue = [root] - while (queue.length > 0) { - const size = queue.length, line = [] - for (let i = 0; i < size; ++i) { - const node = queue.pop() - if (node.left) queue.unshift(node.left) - if (node.right) queue.unshift(node.right) - line.push(node.val) +var levelOrder = function(root) { + if (!root) return []; + const queue = [root], res = []; + while (queue.length) { + const size = queue.length, row = []; + for (let i = 0; i < size; ++i) { + const node = queue.pop(); + if (node.left) queue.unshift(node.left); + if (node.right) queue.unshift(node.right); + row.push(node.val); + } + res.push(row); } - res.push(line) - } - return res -} + return res; +}; diff --git a/hot100/tree/101isSymmetric.js b/hot100/tree/101isSymmetric.js new file mode 100644 index 00000000..3bb1f0b6 --- /dev/null +++ b/hot100/tree/101isSymmetric.js @@ -0,0 +1,38 @@ +/** + * https://leetcode.cn/problems/symmetric-tree + * + * 对称二叉树 + * + * 思路:递归比较两颗子树 + */ + +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {boolean} + */ +var isSymmetric = function(root) { + if (!root) return true; + return dfs(root.left, root.right); +}; + +function dfs(left, right) { + if (!left && !right) { + return true; + } + if (!left || !right) { + return false; + } + if (left.val !== right.val) { + return false; + } + + return dfs(left.left, right.right) && dfs(left.right, right.left); +} diff --git a/hot100/tree/543diameterOfBinaryTree.js b/hot100/tree/543diameterOfBinaryTree.js new file mode 100644 index 00000000..0fdfd5f5 --- /dev/null +++ b/hot100/tree/543diameterOfBinaryTree.js @@ -0,0 +1,11 @@ +/** + * https://leetcode.cn/problems/diameter-of-binary-tree + * + * 二叉树的直径 + * + * 思路: + */ + +var diameterOfBinaryTree = function(root) { + +}; From 3599cff8a9a0147614b17696b22484105bdbb68b Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 9 Dec 2023 00:08:01 +0800 Subject: [PATCH 178/210] feat: solve --- Week_09/056merge.js | 41 ++++++++++++++------------ codetop/238productExceptSelf.js | 49 ++++++++++++------------------- hot100/041firstMissingPositive.js | 31 +++++++++++++++++++ js_basic/01basic.html | 14 +++++++++ 4 files changed, 86 insertions(+), 49 deletions(-) create mode 100644 hot100/041firstMissingPositive.js create mode 100644 js_basic/01basic.html diff --git a/Week_09/056merge.js b/Week_09/056merge.js index 3b4d41e0..0b531095 100644 --- a/Week_09/056merge.js +++ b/Week_09/056merge.js @@ -3,26 +3,31 @@ * 56. 合并区间 | medium */ -// O(nlogn) -function merge(A) { - if (A.length < 2) return A - A.sort(([start1, dest1], [start2, dest2]) => { // 优先级排序,优先按起点排序,起点相同则按终点排序 O(nlogn) - return start1 === start2 ? dest1 - dest2 : start1 - start2 - }) +// O(nlogn) ✅ +var merge = function(A) { + if (!Array.isArray(A) || A.length < 2) return A; - let prev = A[0] // 上一个区间 - const res = [prev] - for (let i = 1; i < A.length; ++i) { - const curr = A[i] - if (curr[0] <= prev[1]) { // 当前区间可以与上一区间合并 - prev[1] = Math.max(prev[1], curr[1]) - } else { // 无法合并,推入res - res.push(curr) - prev = curr + A.sort(([s1, d1], [s2, d2]) => s1 === s2 ? d1 - d2 : s1 - s2); + let prev = A[0]; + const res = [prev]; + for (let i = 1; i < A.length; ++i) { + const curr = A[i]; + if (curr[0] <= prev[1]) { // 可以合并 + prev[1] = Math.max(prev[1], curr[1]); + } else { + res.push(curr); + prev = curr + } } - } - return res -} + return res; +}; + +// // O(n) +// var merge2 = function (A) { +// return A.reduce(([prevStart, prevEnd], [currStart, currEnd]) => { +// if +// }, []) +// } // ---- test case ---- console.log(merge([[1,3],[2,6],[8,10],[15,18]])) diff --git a/codetop/238productExceptSelf.js b/codetop/238productExceptSelf.js index 8c44a110..9ab2d47d 100644 --- a/codetop/238productExceptSelf.js +++ b/codetop/238productExceptSelf.js @@ -1,38 +1,25 @@ /** * https://leetcode-cn.com/problems/product-of-array-except-self/ * 238. 除自身以外数组的乘积 + * O(n) + O(1) + * + * trick */ -// // 方法一:暴力 O(n^2) -// function productExceptSelf(nums) { -// const n = nums.length -// const res = Array(n) -// for(let i = 0; i < n; ++i) { -// res[i] = [ -// ...nums.slice(0, i), -// ...nums.slice(i + 1) -// ].reduce((ans, item) => ans * item) -// } -// return res -// } - -// 方法二:两轮累计遍历 -function productExceptSelf(nums) { - const n = nums.length - const res = Array(n) - let ans = 1 - for(let i = 0; i < n; ++i) { - res[i] = ans - ans = ans * nums[i] - } - ans = 1 - for (let i = n - 1; i >= 0; --i) { - res[i] *= ans - ans *= nums[i] - } - return res -} - +// 方法:第一轮从左往右,存储下标左边元素乘积; 第二轮从右往左,乘上右边的元素乘积 +var productExceptSelf = function(nums) { + const res = []; + for (let i = 0, k = 1; i < nums.length; ++i) { + res.push(k); // res 存储当前下标左边的元素的乘积 + k *= nums[i]; + } + for(let i = nums.length - 1, k = 1; i >= 0; --i) { + res[i] *= k; + k *= nums[i]; + } + return res; +}; // ---- test case ---- -console.log(productExceptSelf([1,2,3,4])) +console.log(productExceptSelf([1,2,3,4])) // [1, 1, 2, 6] -> [24, 12, 8, 6] +console.log(productExceptSelf([-1, 1, 0, -3, 3])) // -1, -1, 0, 0, 0 diff --git a/hot100/041firstMissingPositive.js b/hot100/041firstMissingPositive.js new file mode 100644 index 00000000..9d54e6b4 --- /dev/null +++ b/hot100/041firstMissingPositive.js @@ -0,0 +1,31 @@ +/** + * 缺失的第一个正数 + * + * 要求,不能开新空间 + * 思路:利用数组空间,原地置换 + */ + +var firstMissingPositive = function (nums) { + + const swap = (i, j) => { + if (i !== j) { + const tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; + } + } + + const n = nums.length; + for (let i = 0; i < n; ++i) { + while (nums[i] > 0 && nums[i] <= n && nums[i] !== nums[nums[i] - 1]) { + swap(i, nums[i] - 1); // 放到正确的位置上 -> [1, ..., n] + } + } + + for(let i = 0; i < n; ++i) { + if (nums[i] !== i + 1) { + return i + 1; + } + } + return n + 1; +} diff --git a/js_basic/01basic.html b/js_basic/01basic.html new file mode 100644 index 00000000..a9d845cc --- /dev/null +++ b/js_basic/01basic.html @@ -0,0 +1,14 @@ + \ No newline at end of file From 302f502a04d72fa856e381187fa484b51f736938 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sat, 9 Dec 2023 01:03:26 +0800 Subject: [PATCH 179/210] feat: solve --- hot100/073setZeros.js | 98 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 hot100/073setZeros.js diff --git a/hot100/073setZeros.js b/hot100/073setZeros.js new file mode 100644 index 00000000..16dc7c16 --- /dev/null +++ b/hot100/073setZeros.js @@ -0,0 +1,98 @@ +/** + * 矩阵置零 + * + * 思路: + * + */ + + +// 方法一:第一遍记录行号数组i, 列号数组j,第二遍置零。 其实也 ✅ +var setZeroes = function (matrix) { + const m = matrix.length, n = matrix[0].length; + const rows = new Set(), cols = new Set(); + + for (let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + if (matrix[i][j] === 0) { + rows.add(i); + cols.add(j); + } + } + } + // console.log(rows, cols); + + for (const r of rows) { + for (let j = 0; j < n; ++j) { + matrix[r][j] = 0; + } + } + + for (const c of cols) { + for (let i = 0; i < m; ++i) { + matrix[i][c] = 0; + } + } +} + +// 方法二:优化空间复杂度为 O(1)。 用首行 0 标记该行有 0,首列 0 标记该列有 0。 +var setZeroes2 = function (matrix) { + const m = matrix.length, n = matrix[0].length; + + // Step1, 遍历首行,记录首行是否有零 + let isFirstRowHasZero = false; + for (let j = 0; j < n; ++j) { + console.log('...', j, matrix[0][j]) + if (matrix[0][j] === 0) { + isFirstRowHasZero = true; + break; + } + } + + // Step2, 遍历首列,记录首列是否有零 + let isFirstColHasZero = false; + for (let i = 0; i < m; ++i) { + console.log('...', i, matrix[i][0]) + if (matrix[i][0] === 0) { + isFirstColHasZero = true; + break; + } + } + console.log(isFirstRowHasZero, isFirstColHasZero); + // Step3: 遍历除首行首列的矩阵,用首行首列记录 + for (let i = 1; i < m; ++i) { + for (let j = 1; j < n; ++j) { + if (matrix[i][j] === 0) { + matrix[i][0] = 0; // 表示 i 行有零 + matrix[0][j] = 0; // 表示 j 行有零 + } + } + } + console.log(matrix); + // Step4: 置零 + for (let i = 1; i < m; ++i) { + for (let j = 1; j < n; ++j) { + if (matrix[i][0] === 0 || matrix[0][j] === 0) { + matrix[i][j] = 0; + } + } + } + + // Step5: 处理首行首列 + if (isFirstRowHasZero) { + for (let j = 0; j < n; ++j) { + matrix[0][j] = 0; + } + } + if (isFirstColHasZero) { + for (let i = 0; i < m; ++i) { + matrix[i][0] = 0; + } + } +} + +// ---- test ---- +// const matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]; +const matrix = [[1, 0]] +setZeroes2(matrix); +console.log(matrix); + From 533376a33f1cc595cf31720c678c2cd5b3db8ddd Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 10 Dec 2023 00:23:57 +0800 Subject: [PATCH 180/210] feat: solve --- Week_01/linklist/021mergeTwoLists.js | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Week_01/linklist/021mergeTwoLists.js b/Week_01/linklist/021mergeTwoLists.js index fe14876c..4f82b2c2 100644 --- a/Week_01/linklist/021mergeTwoLists.js +++ b/Week_01/linklist/021mergeTwoLists.js @@ -3,24 +3,24 @@ * easy | leetcode-021 | link-list */ -/** +/** * 21. 合并两个有序链表 * 思路: 类似归并排序的归并过程 * 思路: 声明一个空指针头,遍历l1 和 l2,谁的值比较小就把谁拼接在后面 */ -function mergeTwoLists(l1, l2) { - const dummy = new ListNode(-1) - let p = dummy - while (l1 && l2) { - if (l1.val <= l2.val) { - p.next = l1 - l1 = l1.next - } else { - p.next = l2 - l2 = l2.next +var mergeTwoLists = function(l1, l2) { + const dummyHead = new ListNode(-1); + let p = dummyHead; + while (l1 && l2) { + if (l1.val <= l2.val) { + p.next = l1; + l1 = l1.next; + } else { + p.next = l2; + l2 = l2.next; + } + p = p.next; } - p = p.next - } - p.next = l1 || l2 - return dummy.next -} + p.next = l1 || l2; + return dummyHead.next; +}; From 9940b86debb1675f3e763634bcfd65c2b09ba59c Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 10 Dec 2023 01:18:39 +0800 Subject: [PATCH 181/210] feat: solve linklist --- hot100/linklist/002addTwoNumbers.js | 29 +++++++++++++++++++++++++++++ hot100/linklist/234isPalindrome.js | 22 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 hot100/linklist/002addTwoNumbers.js create mode 100644 hot100/linklist/234isPalindrome.js diff --git a/hot100/linklist/002addTwoNumbers.js b/hot100/linklist/002addTwoNumbers.js new file mode 100644 index 00000000..4bb47079 --- /dev/null +++ b/hot100/linklist/002addTwoNumbers.js @@ -0,0 +1,29 @@ +/** + * https://leetcode.cn/problems/add-two-numbers/ + * + * 两数相加 + * + * carry 存进位 + */ + +var addTwoNumbers = function(l1, l2) { + let p = dummy = new ListNode(-1); + let carry = 0; + + while (l1 || l2) { + const x = l1 ? l1.val : 0; + const y = l2 ? l2.val : 0; + let sum = x + y + carry; + carry = Math.floor(sum / 10); + sum = sum % 10; + + p.next = new ListNode(sum); + p = p.next; + l1 = l1 ? l1.next : null; + l2 = l2 ? l2.next : null; + } + if (carry) { + p.next = new ListNode(carry); + } + return dummy.next; +}; diff --git a/hot100/linklist/234isPalindrome.js b/hot100/linklist/234isPalindrome.js new file mode 100644 index 00000000..1fd09c8e --- /dev/null +++ b/hot100/linklist/234isPalindrome.js @@ -0,0 +1,22 @@ +/** + * https://leetcode.cn/problems/palindrome-linked-list + * + * 回文链表 + * + * 思路:推进数组 + 双指针 O(n) + O(n) + */ + +var isPalindrome = function(head) { + const vals = []; + + while (head) { + vals.push(head.val); + head = head.next + } + for (let l = 0, r = vals.length - 1; l < r; ++l, --r) { + if (vals[l] !== vals[r]) { + return false; + } + } + return true; +}; From d56f183db9cdfc5f672e87817d48c49837495912 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 10 Dec 2023 17:43:52 +0800 Subject: [PATCH 182/210] feat: solve leet --- Week_01/linklist/024swapPairs.js | 30 +++++++++++----------- Week_01/linklist/025reverseKGroup.js | 38 ++++++++++++++++++++++++++++ Week_01/linklist/206reverseList.js | 18 ++++++------- Week_03/098isValidBST.js | 2 ++ hot100/linklist/138copyRandomList.js | 26 +++++++++++++++++++ hot100/tree/108sortedArrayToBST.js | 16 ++++++++++++ 6 files changed, 106 insertions(+), 24 deletions(-) create mode 100644 Week_01/linklist/025reverseKGroup.js create mode 100644 hot100/linklist/138copyRandomList.js create mode 100644 hot100/tree/108sortedArrayToBST.js diff --git a/Week_01/linklist/024swapPairs.js b/Week_01/linklist/024swapPairs.js index 6c69b66e..46c7193a 100644 --- a/Week_01/linklist/024swapPairs.js +++ b/Week_01/linklist/024swapPairs.js @@ -1,7 +1,7 @@ -/** +/** * https://leetcode-cn.com/problems/swap-nodes-in-pairs/ * 24. 两两交换链表中的节点 - * + * */ // 思路1: 递归 @@ -17,16 +17,16 @@ const swapPairs1 = function(head) { } // 思路2: 非递归(空指针头) -const swapPairs2 = function(head) { - const dummy = new ListNode(-1, head) - let prev = dummy - while (prev.next && prev.next.next) { - const curr = prev.next, - then = curr.next - curr.next = then.next - then.next = curr - prev.next = then - prev = curr - } - return dummy.next -} +var swapPairs2 = function(head) { + const dummy = new ListNode(-1, head); + let prev = dummy; + + while (prev.next && prev.next.next) { + const curr = prev.next, then = curr.next; + curr.next = then.next; + then.next = curr; + prev.next = then; + prev = curr; + } + return dummy.next; +}; diff --git a/Week_01/linklist/025reverseKGroup.js b/Week_01/linklist/025reverseKGroup.js new file mode 100644 index 00000000..0ae9be73 --- /dev/null +++ b/Week_01/linklist/025reverseKGroup.js @@ -0,0 +1,38 @@ +/** + * https://leetcode.cn/problems/reverse-nodes-in-k-group + * + * k 个一组翻转链表 + */ + +var reverseKGroup = function(head, k) { + const dummy = new ListNode(-1, head); + let pre = end = dummy; + + while (end.next) { + for (let i = 0; i < k && end; ++i) { + end = end.next; + } + if (!end) break; + const start = pre.next; + const next = end.next; + + end.next = null; + pre.next = reverse(start); + start.next = next; + + pre = start; + end = pre; + } + return dummy.next; +}; + +function reverse(head) { + let prev = null; + while (head) { + const curr = head; + head = head.next; + curr.next = prev; + prev = curr; + } + return prev; +} diff --git a/Week_01/linklist/206reverseList.js b/Week_01/linklist/206reverseList.js index dba8c129..0100eddb 100644 --- a/Week_01/linklist/206reverseList.js +++ b/Week_01/linklist/206reverseList.js @@ -2,18 +2,18 @@ * https://leetcode-cn.com/problems/reverse-linked-list/ * https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/submissions/ * 思路:维护好 prev,cur - * + * * @param {ListNode} head * @return {ListNode} */ const reverseList = function(head) { - let prev = null - while(head) { - const cur = head - head = head.next - cur.next = prev - prev = cur - } - return prev + let prev = null; + while (head) { + const curr = head; + head = head.next; + curr.next = prev; + prev = curr; + } + return prev; } diff --git a/Week_03/098isValidBST.js b/Week_03/098isValidBST.js index 90531604..b51fb444 100644 --- a/Week_03/098isValidBST.js +++ b/Week_03/098isValidBST.js @@ -17,6 +17,8 @@ * @param {TreeNode} root * @return {boolean} */ + +// 递归版 const isValidBST = function(root) { function helper(root, lower, upper) { // terminator diff --git a/hot100/linklist/138copyRandomList.js b/hot100/linklist/138copyRandomList.js new file mode 100644 index 00000000..c403c042 --- /dev/null +++ b/hot100/linklist/138copyRandomList.js @@ -0,0 +1,26 @@ +/** + * https://leetcode.cn/problems/copy-list-with-random-pointer + * + * 随机链表的复制 + * + * 思路:第一轮存入 hash 表(oldNode -> newNode),第二轮连指针 + * O(n), O(n) + * + */ + +var copyRandomList = function (head) { + const map = new Map(); + // 第一轮遍历:创建节点,并存入 map(oldNode -> newNode) + for (let p = head; p !== null; p = p.next) { + const node = new Node(p.val, null, null); + map.set(p, node); + } + + // 第二轮遍历 + for (let p = head; p !== null; p = p.next) { + const node = map.get(p); + p.next && (node.next = map.get(p.next)); + p.random && (node.random = map.get(p.random)); + } + return map.get(head); +}; diff --git a/hot100/tree/108sortedArrayToBST.js b/hot100/tree/108sortedArrayToBST.js new file mode 100644 index 00000000..ee6146bc --- /dev/null +++ b/hot100/tree/108sortedArrayToBST.js @@ -0,0 +1,16 @@ +/** + * https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree + * + * 思路:分而治之,建立根,左右为子问题。) + */ + +// 递归版 +var sortedArrayToBST = function(nums) { + const helper = (l, r) => { + if (l > r) return null; + let mid = l + ((r - l) >> 1); + return new TreeNode(nums[mid], helper(l, mid - 1), helper(mid + 1, r)); + } + + return helper(0, nums.length - 1); +}; From a1cad2facf8943a7238849835648595618894b51 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 10 Dec 2023 21:24:37 +0800 Subject: [PATCH 183/210] feat: tree --- Week_02/094inorderTraversal.js | 4 +-- Week_02/144preorderTraversal.js | 48 ++++++++++++++++----------------- Week_02/429levelOrder.js | 29 ++++++++++---------- Week_02/590postorder.js | 27 +++++++++---------- 4 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Week_02/094inorderTraversal.js b/Week_02/094inorderTraversal.js index dd4d87ff..a5f217b8 100644 --- a/Week_02/094inorderTraversal.js +++ b/Week_02/094inorderTraversal.js @@ -4,7 +4,7 @@ // 1. 递归DFS var inorderTraversal = function(root) { - if (root == null) return [] + if (!root) return []; const res = []; const dfs = (p) => { if (p.left) dfs(p.left); @@ -15,7 +15,7 @@ var inorderTraversal = function(root) { return res; }; -// 2. 非递归,手动维护stack +// 2. 非递归,手动维护 stack var inorderTraversal = function(root) { if (root == null) return []; const res = [], stack = []; diff --git a/Week_02/144preorderTraversal.js b/Week_02/144preorderTraversal.js index 069f1f11..1104ec94 100644 --- a/Week_02/144preorderTraversal.js +++ b/Week_02/144preorderTraversal.js @@ -3,28 +3,28 @@ * 【dfs】 */ -// 1. 递归解法 -const preorderTraversal1 = function(root) { - if (root == null) return [] - const res = [] - const dfs = (root) => { - res.push(root.val) - if (root.left) dfs(root.left) - if (root.right) dfs(root.right) - } - dfs(root) - return res -} +// 1. 递归解法 dfs +var preorderTraversal = function(root) { + if (!root) return []; + const res = []; + const dfs = (root) => { + res.push(root.val); + if (root.left) dfs(root.left); + if (root.right) dfs(root.right); + } + dfs(root); + return res; +}; -// 2. 非递归解法 -const preorderTraversal = function(root) { - if (root == null) return [] - const res = [], stack = [root] - while(stack.length) { - const p = stack.pop() - if(p.right) stack.push(p.right) - if(p.left) stack.push(p.left) - res.push(p.val) - } - return res -} +// 2. 非递归解法 stack dfs +var preorderTraversal = function(root) { + if (!root) return []; + const res = [], stack = [root]; + while (stack.length) { + const p = stack.pop(); + res.push(p.val) + if (p.right) stack.push(p.right); + if (p.left) stack.push(p.left); + } + return res; +}; diff --git a/Week_02/429levelOrder.js b/Week_02/429levelOrder.js index 9f116d8f..aa6193a6 100644 --- a/Week_02/429levelOrder.js +++ b/Week_02/429levelOrder.js @@ -4,18 +4,19 @@ * BFS */ -function levelOrder(root) { - if (root == null) return [] - const res = [], queue = [root] - while(queue.length) { - const line = [], n = queue.length - for(let i = 0; i < n; ++i) { - const root = queue.pop() - if (root.children.length) - root.children.forEach(child => queue.unshift(child)) - line.push(root.val) +var levelOrder = function(root) { + if (!root) return []; + const res = [], queue = [root]; + while (queue.length) { + const line = [], n = queue.length; + for (let i = 0; i < n; ++i) { + const node = queue.pop() + if (node.children.length) { + node.children.forEach(child => queue.unshift(child)) + } + line.push(node.val) + } + res.push(line); } - res.push(line) - } - return res -} + return res; +}; diff --git a/Week_02/590postorder.js b/Week_02/590postorder.js index 553320e5..2b01ff6b 100644 --- a/Week_02/590postorder.js +++ b/Week_02/590postorder.js @@ -1,25 +1,24 @@ /** * https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/ - * + * */ // 1. 递归版 dfs -const postorder = function(root) { - if (root == null) return [] - const res = [] - const dfs = (p) => { - p.children && p.children.forEach(child => { - if (child) dfs(child) - }) - res.push(p.val) - } - dfs(root) - return res -} +var preorderTraversal = function(root) { + if (!root) return []; + const res = [], stack = [root]; + while (stack.length) { + const p = stack.pop(); + res.push(p.val) + if (p.right) stack.push(p.right); + if (p.left) stack.push(p.left); + } + return res; +}; // !! 2. 非递归版 【反转】 // trick 孩子从左往右压栈,出来则是从右往左遍历。最后再翻转 -const postorder = function(root) { +var postorder = function(root) { if (root == null) return [] const res = [], stack = [root] while (stack.length) { From 523587fb46e4739e6ebcea1be1a302eec0a4dd24 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 10 Dec 2023 22:55:21 +0800 Subject: [PATCH 184/210] feat: tree --- Week_02/1201nthUglyNumber.js | 48 +++++++++++++++++------------------ Week_02/264nthUglyNumber.js | 28 ++++++++++---------- Week_02/429levelOrder.js | 6 ++--- hot100/tree/230kthSmallest.js | 26 +++++++++++++++++++ 4 files changed, 68 insertions(+), 40 deletions(-) create mode 100644 hot100/tree/230kthSmallest.js diff --git a/Week_02/1201nthUglyNumber.js b/Week_02/1201nthUglyNumber.js index d75f259c..7edbda07 100644 --- a/Week_02/1201nthUglyNumber.js +++ b/Week_02/1201nthUglyNumber.js @@ -1,7 +1,7 @@ /** * https://leetcode-cn.com/problems/ugly-number-iii/ - * - * 解法: + * + * 解法: * 1. 二分 * 2. 容斥原理,计算个数 */ @@ -12,29 +12,29 @@ const gcd = (x, y) => x % y ? gcd(y, x % y) : y const lcm = (x, y) => x * y / gcd(x, y) // 解法一 -const nthUglyNumber1 = function(n, a, b, c) { - const ab = lcm(a, b), - ac = lcm(a, c), - bc = lcm(b, c), - abc = lcm(ab, c) - let left = 0, right = n * Math.min(a, b, c) - while(left <= right) { - const mid = Math.floor((left + right) / 2) - const num = Math.floor(mid / a) - + Math.floor(mid / b) - + Math.floor(mid / c) - - Math.floor(mid / ab) - - Math.floor(mid / ac) - - Math.floor(mid / bc) - + Math.floor(mid / abc) - if (num >= n) { - right = mid - 1 - } else { - left = mid + 1 +var nthUglyNumber = function(n, a, b, c) { + const ab = lcm(a, b), + ac = lcm(a, c), + bc = lcm(b, c), + abc = lcm(ab, c); + let left = 0, right = n * Math.min(a, b, c); + while (left <= right) { + const mid = left + ((right - left) >> 1); + const num = Math.floor(mid / a) + + Math.floor(mid / b) + + Math.floor(mid / c) + - Math.floor(mid / ab) + - Math.floor(mid / ac) + - Math.floor(mid / bc) + + Math.floor(mid / abc); + if (num >= n) { + right = mid - 1; + } else { + left = mid + 1; + } } - } - return left -} + return left; +}; // 解法二:【优化】位运算提速(但需要用bigInt类型,防止越界) const nthUglyNumber = function(n, a, b, c) { diff --git a/Week_02/264nthUglyNumber.js b/Week_02/264nthUglyNumber.js index 3c828232..13f31f01 100644 --- a/Week_02/264nthUglyNumber.js +++ b/Week_02/264nthUglyNumber.js @@ -1,24 +1,26 @@ /** * https://leetcode-cn.com/problems/ugly-number-ii/ - * + * * 相同题目: * 【剑指 Offer 49. 丑数】 https://leetcode-cn.com/problems/chou-shu-lcof/ * 【面试题 17.09. 第 k 个数】 https://leetcode-cn.com/problems/get-kth-magic-number-lcci/ */ // 解法: 三指针法递推 -const nthUglyNumber = function(n) { - if (n < 7) return n - let p2 = p3 = p5 = 0, nums = [1] - for (let i = 1; i < n; ++i) { - const x = 2 * nums[p2], y = 3 * nums[p3], z = 5 * nums[p5] - nums[i] = Math.min(x, y, z) - if (nums[i] === x) ++p2 - if (nums[i] === y) ++p3 - if (nums[i] === z) ++p5 - } - return nums[n - 1] -} +var nthUglyNumber = function(n) { + if (n < 7) return n; + let p2 = p3 = p5 = 0, nums = [1]; + for (let i = 1; i < n; ++i) { + const x = 2 * nums[p2]; + const y = 3 * nums[p3]; + const z = 5 * nums[p5]; + nums[i] = Math.min(x, y, z); + if (nums[i] === x) ++p2; + if (nums[i] === y) ++p3; + if (nums[i] === z) ++p5; + } + return nums[n - 1]; +}; // ---- test case ---- for(let i = 1; i <= 100; ++i) { diff --git a/Week_02/429levelOrder.js b/Week_02/429levelOrder.js index aa6193a6..363b020d 100644 --- a/Week_02/429levelOrder.js +++ b/Week_02/429levelOrder.js @@ -10,11 +10,11 @@ var levelOrder = function(root) { while (queue.length) { const line = [], n = queue.length; for (let i = 0; i < n; ++i) { - const node = queue.pop() + const node = queue.pop(); if (node.children.length) { - node.children.forEach(child => queue.unshift(child)) + node.children.forEach(child => queue.unshift(child)); } - line.push(node.val) + line.push(node.val); } res.push(line); } diff --git a/hot100/tree/230kthSmallest.js b/hot100/tree/230kthSmallest.js new file mode 100644 index 00000000..8aa27fe3 --- /dev/null +++ b/hot100/tree/230kthSmallest.js @@ -0,0 +1,26 @@ +/** + * https://leetcode.cn/problems/kth-smallest-element-in-a-bst + * BST中第 k 小的元素 + * @param {*} root + * @param {*} k + * + * + * 思路: dfs 中序遍历,结果为数组第 k 个元素 + * O(n) O(n) + */ +var kthSmallest = function (root, k) { + const nums = []; + + const dfs = (p) => { + if (!p) return; + dfs(p.left); + nums.push(p.val); + // if (nums.length === k) { + // return + // } + dfs(p.right); + } + + dfs(root); + return nums[k - 1]; +} From fc865b2c0ba1812f0812a0baffae510cc24585b2 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 12 Dec 2023 23:38:21 +0800 Subject: [PATCH 185/210] =?UTF-8?q?feat:=20=E5=8D=95=E8=B0=83=E6=A0=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_01/array/hard/084largestRectangleArea.js | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Week_01/array/hard/084largestRectangleArea.js b/Week_01/array/hard/084largestRectangleArea.js index ebb35e60..f954fd85 100644 --- a/Week_01/array/hard/084largestRectangleArea.js +++ b/Week_01/array/hard/084largestRectangleArea.js @@ -1,22 +1,28 @@ /** * https://leetcode-cn.com/problems/largest-rectangle-in-histogram/ * 84. 柱状图中最大的矩形 | hard + * + * 思路:单调栈存idx,直到遇到右边界才出栈 */ // stack O(n) -function largestRectangleArea(A) { - let maxArea = 0 - const stack = [] - A = [0, ...A, 0] - for (let i = 0; i < A.length; ++i) { - while (stack.length > 1 && A[stack[stack.length - 1]] > A[i]) { - const j = stack.pop() - maxArea = Math.max((i - stack[stack.length - 1] - 1) * A[j], maxArea) +var largestRectangleArea = function(heights) { + let max = 0; + const stack = [-1]; + const A = [...heights, 0]; + for (let i = 0; i < A.length; ++i) { + while (stack.length > 1 && A[stack[stack.length - 1]] > A[i]) { + const curIdx = stack.pop(); + const left = stack[stack.length - 1] + 1; + const right = i - 1; + const curArea = A[curIdx] * (right - left + 1); + max = Math.max(max, curArea); + } + stack.push(i); } - stack.push(i) - } - return maxArea -} + return max; +}; // ---- test case ---- console.log(largestRectangleArea([2,1,5,6,2,3])) +console.log(largestRectangleArea([2,4])) From b66256818b8bb32f562e4da59c1decaa60b15f2e Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 13 Dec 2023 00:30:03 +0800 Subject: [PATCH 186/210] =?UTF-8?q?feat:=20=E6=BB=91=E5=8A=A8=E7=AA=97?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_02/239maxSlidingWindow.js | 58 ++++++++++++---------------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/Week_02/239maxSlidingWindow.js b/Week_02/239maxSlidingWindow.js index fab4780b..4f686ec3 100644 --- a/Week_02/239maxSlidingWindow.js +++ b/Week_02/239maxSlidingWindow.js @@ -2,51 +2,33 @@ * https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/ * https://leetcode-cn.com/problems/sliding-window-maximum/ * 239. 滑动窗口最大值 - * + * * 用 window 记录窗口下标值 - * + * */ -const maxSlidingWindow = function (nums, k) { - if (!Array.isArray(nums) || nums.length < 1 || k < 1) return [] - const res = [], win = [] - for (let i = 0; i < nums.length; ++i) { - if (i >= k && i >= k + win[0]) { // window size - win.shift() +// 思路,win 必须存下标,每次遍历,从右往左清理掉又老又小的数 +var maxSlidingWindow = function(nums, k) { + const res = [], win = []; + for (let i = 0; i < nums.length; ++i) { + if (i > 0 && i - win[0] >= k) { + win.shift(); + } + while (win.length > 0 && nums[win[win.length - 1]] <= nums[i]) { + win.pop(); + } + win.push(i); + if (i >= k - 1) { + res.push(nums[win[0]]); + } } - while (nums[i] >= nums[win[win.length - 1]]) { // override left elements - win.pop() - } - win.push(i) - if (i >= k - 1) { - res.push(nums[win[0]]) - } - } - return res -} - -const maxSlidingWindow = function (nums, k) { - if (!Array.isArray(nums) || nums.length < 1 || k < 1) return [] - const res = [], win = [] - for (let i = 0; i < nums.length; ++i) { - if (i >= k && i >= k + win[0]) { // window size - win.shift() - } - while (nums[i] >= nums[win[win.length - 1]]) { // override left elements - win.pop() - } - win.push(i) - if (i >= k - 1) { - res.push(nums[win[0]]) - } - } - return res -} + return res; +}; // ---- test case ---- -console.log(maxSlidingWindow([1,3,-1,-3,5,3,6,7], 3)) +// console.log(maxSlidingWindow([1,3,-1,-3,5,3,6,7], 3)) // console.log(maxSlidingWindow([1], 1)) // console.log(maxSlidingWindow([1,-1], 1)) // console.log(maxSlidingWindow([9,11], 2)) // console.log(maxSlidingWindow([4,-2], 2)) -// console.log(maxSlidingWindow([1,3,1,2,0,5], 3)) +console.log(maxSlidingWindow([1,3,1,2,0,5], 3)) From d18321d18c4224372128d23f2fdfafd365162ca8 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 13 Dec 2023 23:25:05 +0800 Subject: [PATCH 187/210] =?UTF-8?q?feat:=20=E6=BB=91=E5=8A=A8=E7=AA=97?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Week_02/239maxSlidingWindow.js | 9 ++-- Week_06/076minWindow.js | 53 +++++++++++++++++++ .../438findAnagrams.js" | 44 ++++++++++++++- codetop/003lengthOfLongestSubstring.js | 28 +++++----- 4 files changed, 115 insertions(+), 19 deletions(-) diff --git a/Week_02/239maxSlidingWindow.js b/Week_02/239maxSlidingWindow.js index 4f686ec3..5465be72 100644 --- a/Week_02/239maxSlidingWindow.js +++ b/Week_02/239maxSlidingWindow.js @@ -11,15 +11,16 @@ var maxSlidingWindow = function(nums, k) { const res = [], win = []; for (let i = 0; i < nums.length; ++i) { - if (i > 0 && i - win[0] >= k) { + if (win.length > 0 && i - win[0] >= k) { // 删除队首过期元素 win.shift(); } - while (win.length > 0 && nums[win[win.length - 1]] <= nums[i]) { + while (win.length > 0 && nums[i] >= nums[win[win.length - 1]]) { // 删除队尾所有又旧又小的元素 win.pop(); } - win.push(i); + + win.push(i); // 入队 if (i >= k - 1) { - res.push(nums[win[0]]); + res.push(nums[win[0]]); // 队首元素 } } return res; diff --git a/Week_06/076minWindow.js b/Week_06/076minWindow.js index afc8ce60..f82789db 100644 --- a/Week_06/076minWindow.js +++ b/Week_06/076minWindow.js @@ -2,3 +2,56 @@ * https://leetcode-cn.com/problems/minimum-window-substring/ * 76. 最小覆盖子串 */ + +var minWindow = function(s, t) { + if (!s || !t) return ''; + + // 用 need 统计字符串 t + const need = new Map(); + for (const ch of t) { + const cnt = (need.get(ch) || 0) + 1; + need.set(ch, cnt); + } + + let start = 0, minSize = Infinity, needCnt = t.length; + for (let i = j = 0; j < s.length; ++j) { + // Step1: 右边界右移,窗口增加元素 + const jChar = s[j]; + if (need.has(jChar)) { + if (need.get(jChar) > 0) { // !! 这个 if 很关键,减到零之后,就不管了 + --needCnt; + } + need.set(jChar, need.get(jChar) - 1); // 需求被满足了,减少1 + } + + // Step2: 如果需求全部满足了,左边界右移,窗口减少元素,尝试寻找最短 str + if (needCnt === 0) { + let iChar = s[i]; + while (!need.has(iChar) || need.get(iChar) < 0) { // 有富余,尽管移 + if (need.has(iChar)) { + need.set(iChar, need.get(iChar) + 1); + // ++needCnt; + } + ++i; + iChar = s[i]; + } + // console.log(i, j, start, minSize, s.slice(start, start + minSize), need, needCnt) + if (j - i + 1 < minSize) { // 找到了满足条件的 + minSize = j - i + 1; + start = i; + } + // Step3: 左边界再多右移 1 位,让窗口不满足条件 + need.set(iChar, need.get(iChar) + 1); + ++needCnt; + ++i; + } + } + return minSize === Infinity ? '' : s.slice(start, start + minSize); +}; + +// ----- test ----- +// console.log(minWindow('ADOBECODEBANC', 'ABC')); // BANC +// console.log(minWindow('DOABECODEBANC', 'ABC')); // BANC +// console.log(minWindow('a', 'a')); // a +// console.log(minWindow('a', 'aa')); // '' +console.log(minWindow('bba', 'ab')); // 'ba' diff --git "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" index c1b9e829..55bc9c43 100644 --- "a/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" +++ "b/Week_10 \346\257\225\344\270\232\346\200\273\347\273\223/438findAnagrams.js" @@ -4,7 +4,7 @@ */ // 滑动窗口 + 数组统计 O(n) -function findAnagrams (s, p) { +function findAnagrams1 (s, p) { const m = s.length, n = p.length if (m < n || n < 1) return [] const startIdx = 'a'.codePointAt(0) @@ -36,7 +36,47 @@ function findAnagrams (s, p) { return res } +// 滑动窗口套路 +var findAnagrams = function(s, t) { + const need = new Map(), wind = new Map(); + for (const ch of t) { + need.set(ch, (need.get(ch) || 0) + 1); + } + + const res = [], size = t.length; + let count = 0; + for (let i = 0, j = 0; j < s.length; ++j) { + // Step1: 扩 1 + const jChar = s[j]; + if (need.has(jChar)) { + wind.set(jChar, (wind.get(jChar) || 0) + 1); + if (wind.get(jChar) === need.get(jChar)) { // !! + ++count; + } + } else { // 遇到不符合的元素,可以直接挪左指针到 j+1 + wind.clear(); + count = 0; + i = j + 1; + continue; + } + // Step2: 看看结果ok不 + if (j - i + 1 === size) { + if (count === need.size) { + res.push(i); + } + // Step3: 缩 1 + const iChar = s[i]; + ++i; + if (wind.get(iChar) === need.get(iChar)) { // !! + --count; + } + wind.set(iChar, wind.get(iChar) - 1); + } + } + return res; +}; + // ---- test case ---- console.log(findAnagrams('cbaebabacd', 'abc')) // [0, 6] console.log(findAnagrams('abab', 'ab')) // [0, 1, 2] -console.log(findAnagrams('baa', 'aa')) +// console.log(findAnagrams('baa', 'aa')) diff --git a/codetop/003lengthOfLongestSubstring.js b/codetop/003lengthOfLongestSubstring.js index 99a29331..2658745a 100644 --- a/codetop/003lengthOfLongestSubstring.js +++ b/codetop/003lengthOfLongestSubstring.js @@ -2,23 +2,25 @@ * https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/ * https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/ * 3. 无重复字符的最长子串 | medium - * + * * hashmap + 双指针 */ -const lengthOfLongestSubstring = function(s) { - const m = new Map() // 记录字母上一次出现的位置 - let left = 0, max = 0 // left 记录左边界 - for (let i = 0; i < s.length; ++i) { - const ch = s[i] - if (m.has(ch) && m.get(ch) >= left) { // 出现重复,更新 left - left = m.get(ch) + 1 +var lengthOfLongestSubstring = function(s) { + const map = new Map(); // 记录字母上一次出现的位置 + let maxSize = 0; + for (let i = j = 0; j < s.length; ++j) { + const jChar = s[j]; + if (map.has(jChar) && map.get(jChar) >= i) { // 出现重复,更新 left + i = map.get(jChar) + 1; + } + map.set(jChar, j); + if (maxSize < j - i + 1) { + maxSize = j - i + 1; + } } - m.set(ch, i) - max = Math.max(max, i - left + 1) - } - return max -} + return maxSize; +}; // ---- test case ---- console.log(lengthOfLongestSubstring('abcabcbb')) // 3 From ca8a5771f87316b3a6055624b0c28253fd519ea2 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 14 Dec 2023 11:46:20 +0800 Subject: [PATCH 188/210] feat: leet --- Week_03/105buildTree.js | 2 +- hot100/linklist/023mergeKLists.js | 37 ++++++++++++++++++++++++++ hot100/linklist/148sortList.js | 24 +++++++++++++++++ hot100/tree/114flatten.js | 26 ++++++++++++++++++ hot100/tree/199rightSideView.js | 28 +++++++++++++++++++ hot100/tree/543diameterOfBinaryTree.js | 12 +++++++++ 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 hot100/linklist/023mergeKLists.js create mode 100644 hot100/linklist/148sortList.js create mode 100644 hot100/tree/114flatten.js create mode 100644 hot100/tree/199rightSideView.js diff --git a/Week_03/105buildTree.js b/Week_03/105buildTree.js index b6aaa0d1..367c115d 100644 --- a/Week_03/105buildTree.js +++ b/Week_03/105buildTree.js @@ -3,7 +3,7 @@ * 思路: * 1. 建立辅助函数,扩充4个下标。pStart,pEnd,iStart,iEnd * 2. 递归调用辅助函数 - * + * * Definition for a binary tree node. * function TreeNode(val, left, right) { * this.val = (val===undefined ? 0 : val) diff --git a/hot100/linklist/023mergeKLists.js b/hot100/linklist/023mergeKLists.js new file mode 100644 index 00000000..ebc8938b --- /dev/null +++ b/hot100/linklist/023mergeKLists.js @@ -0,0 +1,37 @@ +/** + * https://leetcode.cn/problems/merge-k-sorted-lists + * + * 合并 k 个升序链表 + */ + +// 思路1. 两两合并 -> 归并 +var merge2List = function (l1, l2) { + if (!l1) return l2; + if (!l2) return l1; + if (l1.val <= l2.val) { + l1.next = merge2List(l1.next, l2); + return l1; + } else { + l2.next = merge2List(l1, l2.next); + return l2; + } +}; + +var merge = function (lists, lo, hi) { + if (lo === hi) { + return lists[lo]; + } + let mid = lo + ((hi - lo) >> 1); + let l1 = merge(lists, lo, mid); + let l2 = merge(lists, mid + 1, hi); + return merge2List(l1, l2); +}; + +var mergeKLists = function (lists) { + if (lists.length === 0) { + return null; + } + return merge(lists, 0, lists.length - 1); +}; + +// 思路2. diff --git a/hot100/linklist/148sortList.js b/hot100/linklist/148sortList.js new file mode 100644 index 00000000..40737f90 --- /dev/null +++ b/hot100/linklist/148sortList.js @@ -0,0 +1,24 @@ +/** + * https://leetcode.cn/problems/sort-list + * + * 排序链表 + */ + +// 解法一:数组排序 +var sortList1 = function (head) { + const arr = []; + for (let p = head; p !== null; p = p.next) { + arr.push(p.val); + } + + arr.sort((x, y) => x - y); + const dummy = new ListNode(-1); + let p = dummy; + for (const val of arr) { + p.next = new ListNode(val); + p = p.next; + } + return dummy.next; +} + +// 解法二:归并~ diff --git a/hot100/tree/114flatten.js b/hot100/tree/114flatten.js new file mode 100644 index 00000000..9be8d2e0 --- /dev/null +++ b/hot100/tree/114flatten.js @@ -0,0 +1,26 @@ +/** + * https://leetcode.cn/problems/flatten-binary-tree-to-linked-list + * + * 二叉树展开为链表 + */ + +// 思路:dfs,先推入数组。再遍历数组,构造链表 +var flatten = function (root) { + + const arr = []; + const dfs = (node) => { + if (!node) return; + arr.push(node); + dfs(node.left); + dfs(node.right); + } + dfs(root); + + let p = root; + for (let i = 1; i < arr.length; ++i) { + p.left = null + p.right = arr[i]; + p = p.right; + } + return root; +} diff --git a/hot100/tree/199rightSideView.js b/hot100/tree/199rightSideView.js new file mode 100644 index 00000000..04185600 --- /dev/null +++ b/hot100/tree/199rightSideView.js @@ -0,0 +1,28 @@ +/** + * https://leetcode.cn/problems/binary-tree-right-side-view + * + * 二叉树的右视图 + */ + +// 思路1: bfs层序遍历 +var rightSideView = function (root) { + if (!root) return []; + const res = [], queue = [root]; + while (queue.length) { + const size = queue.length; + + for (let i = 0; i < size; ++i) { + const node = queue.pop(); + if (node.left) { + queue.unshift(node.left); + } + if (node.right) { + queue.unshift(node.right); + } + if (i === size - 1) { + res.add(node.val); + } + } + } + return res; +} diff --git a/hot100/tree/543diameterOfBinaryTree.js b/hot100/tree/543diameterOfBinaryTree.js index 0fdfd5f5..16dd8274 100644 --- a/hot100/tree/543diameterOfBinaryTree.js +++ b/hot100/tree/543diameterOfBinaryTree.js @@ -8,4 +8,16 @@ var diameterOfBinaryTree = function(root) { + let count = 1; // 最长路径的节点个数 + + const depth = (node) => { + if (!node) return 0; + let l = depth(node.left); + let r = depth(node.right); + count = Math.max(count, l + r + 1); // 更新最长路径节点数 + return Math.max(l, r) + 1 // 返回根到叶子的最长路径的节点数 + } + + depth(root); + return count - 1 }; From 540229e26a8c2bfb4f384e0e07a65f3c0b3f9d98 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 15 Dec 2023 15:13:17 +0800 Subject: [PATCH 189/210] feat: leet * interview --- Week_03/017letterCombinations.js | 53 +++++++++++++++++--------------- Week_04/045jump.js | 10 +++--- hot100/039combinationSum.js | 11 +++++++ interview/myFlat.js | 36 ++++++++++++++++++++++ interview/unique.js | 21 +++++++++++++ 5 files changed, 101 insertions(+), 30 deletions(-) create mode 100644 hot100/039combinationSum.js create mode 100644 interview/myFlat.js create mode 100644 interview/unique.js diff --git a/Week_03/017letterCombinations.js b/Week_03/017letterCombinations.js index 613aead7..2ad47fd5 100644 --- a/Week_03/017letterCombinations.js +++ b/Week_03/017letterCombinations.js @@ -2,36 +2,39 @@ * https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ * 思路:分治 * 1. 画递归树,构造辅助函数 - * + * * @param {string} digits * @return {string[]} */ -const letterCombinations = function(digits) { - if (typeof digits !== 'string' || digits.length < 1) return [] +var letterCombinations = function(digits) { + if (!digits.length) return []; + const map = new Map([ + ['2', 'abc'], ['3', 'def'], ['4', 'ghi'], + ['5', 'jkl'], ['6', 'mno'], ['7', 'pqrs'], + ['8', 'tuv'], ['9', 'wxyz'] + ]); - const m = new Map([ - ['2', 'abc'], ['3', 'def'], - ['4', 'ghi'], ['5', 'jkl'], - ['6', 'mno'], ['7', 'pqrs'], - ['8', 'tuv'], ['9', 'wxyz']]), - res = [] - - const helper = (level, path) => { - if (level === digits.length) { - res.push(path.join('')) - return - } - const selectors = m.get(digits[level]) - for(let i = 0; i < selectors.length; ++i) { - path.push(selectors[i]) - helper(level + 1, path) - path.pop() + const res = []; + const helper = (level, path) => { + // terminator + if (level === digits.length) { + res.push(path.join('')); + return; + } + // process + const selectors = map.get(digits[level]); + for (let i = 0; i < selectors.length; ++i) { + path.push(selectors[i]); + // drill down + helper(level + 1, path); + // revert status + path.pop(); + } } - } - - helper(0, []) - return res -} + + helper(0, []); + return res; +}; console.log(letterCombinations('23')) // console.log(letterCombinations('995')) diff --git a/Week_04/045jump.js b/Week_04/045jump.js index 24d0cd15..3775616a 100644 --- a/Week_04/045jump.js +++ b/Week_04/045jump.js @@ -1,6 +1,6 @@ /** * https://leetcode-cn.com/problems/jump-game-ii/ - * + * * 45. 跳跃游戏 II * hard */ @@ -28,7 +28,7 @@ const jump = function(nums) { } // ---- test case ---- -console.log(jump([])) -console.log(jump([2,3,1,1,4])) -console.log(jump([2,1,1,1,1,4])) -console.log(jump([2,1,1,0,1,4])) +// console.log(jump([])) +console.log(jump([2,3,1,1,4])) // 2 +// console.log(jump([2,1,1,1,1,4])) +// console.log(jump([2,1,1,0,1,4])) diff --git a/hot100/039combinationSum.js b/hot100/039combinationSum.js new file mode 100644 index 00000000..b769d616 --- /dev/null +++ b/hot100/039combinationSum.js @@ -0,0 +1,11 @@ +/** + * https://leetcode.cn/problems/combination-sum + * + * 组合总和 + */ + +var combinationSum = function (candidates, target) { + if (!candidates || !candidates.length) return []; +// todo + +}; diff --git a/interview/myFlat.js b/interview/myFlat.js new file mode 100644 index 00000000..3ebc0f16 --- /dev/null +++ b/interview/myFlat.js @@ -0,0 +1,36 @@ +// ---- test ----- +const arr = [ + 1, 2, 3, 4, + [ + 1, 2, 3, + [ + 1, 2, 3, 4, + [ + 1, 2, 3 + ] + ] + ], + 5, + 'string', + { + name: '前端收割机' + } +]; + +console.log(myFlat(arr, 3)); + + +function myFlat(arr,depath){ + let target =[] + + arr.forEach(el => { + if (Array.isArray(el) && depath >= 0){ + target = target.concat(arguments.callee(el, depath - 1)) + } else { + target.push(el) + } + }) + + return target +} + diff --git a/interview/unique.js b/interview/unique.js new file mode 100644 index 00000000..88ea733d --- /dev/null +++ b/interview/unique.js @@ -0,0 +1,21 @@ +function unique(arr) { + const target = [] + const res = {} + arr.forEach(el => { + if (typeof el == 'object') { + const str = JSON.stringify(el) + if (!res[str]) { + target.push(el) + res[str] = el + } + } else if (!target.includes(el)) { + target.push(el) + } + }); + return target +} +const obj1 = { age: 12 } +const arr = [123, '123', {}, {}, null, undefined, void 0, "abc", "abc", obj1, obj1, { age: 12 }, { age: 12, name: 'lyn' }] +console.log(unique(arr)) + + From 4ee7bcdb8200193a5a8e8b5c1aa7f1fa5f099c66 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 18 Dec 2023 15:35:59 +0800 Subject: [PATCH 190/210] feat: handwrite --- .../handwrite/javascript/eventEmitter.js | 77 +++++++++++++++++++ interview/handwrite/utils/getAge.js | 25 ++++++ interview/handwrite/utils/getFrequentTag.js | 11 +++ interview/handwrite/utils/myDeepClone.js | 47 +++++++++++ 4 files changed, 160 insertions(+) create mode 100644 interview/handwrite/javascript/eventEmitter.js create mode 100644 interview/handwrite/utils/getAge.js create mode 100644 interview/handwrite/utils/getFrequentTag.js create mode 100644 interview/handwrite/utils/myDeepClone.js diff --git a/interview/handwrite/javascript/eventEmitter.js b/interview/handwrite/javascript/eventEmitter.js new file mode 100644 index 00000000..12ba7e20 --- /dev/null +++ b/interview/handwrite/javascript/eventEmitter.js @@ -0,0 +1,77 @@ +/** + * emitter.on(name,fn) // 订阅name事件,监听函数为fn,可多次订阅 + * emitter.once(name,fn) // 功能与on类似,但监听函数为一次性的,触发后自动移除 + * emitter.emit(name,data1,data2,...,datan) // 发布name事件,所有订阅该事件的监听函数被触发,data1,…,datan作为参数传给监听函数,若有多个函数,按照顺序执行 + * emitter.remove(name,fn) // 移除name事件的监听函数fn + */ + +class EventEmitter { + constructor() { + this.cache = Object.create(null); + } + /** 订阅事件 */ + on(type, fn) { + const fns = this.cache[type] || []; + if (fns.indexOf(fn) < 0) { + fns.push(fn); + } + this.cache[type] = fns; + return this; + } + /** 触发一次就销毁的事件 */ + once(type, fn) { + const wrapFn = (...args) => { + fn.apply(this, args); + this.remove(type, fn); + } + this.on(type, wrapFn); + return this; + } + emit(type, ...args) { + const fns = this.cache[type]; + if (Array.isArray(fns)) { + fns.forEach(fn => { + fn(...args); + }) + } + return this; + } + remove(type, fn) { + const fns = this.cache[type]; + if (Array.isArray(fns)) { + if (fn) { + const index = fns.indexOf(fn); + if (index > -1) { + fns.splice(index, 1); + } + } else { + fns.length = 0; // clear + } + } + return this; + } +} + +// ---- test case ---- +function fn1(a, b, c) { + console.log(a, b, c); +} +function fn2(a, b) { + console.log(a * 2, b * 3); +} +var em = new EventEmitter(); + +// 测试 on 和 emit +em.on("e1", fn1) + .on("e1", fn2) + .emit("e1", 1, 2, 3) // 1, 2, 3 2, 6 + .emit("e1", 1, 2, 3); // 1, 2, 3 2, 6 +console.log(em.cache); // [fn1, fn2] + +// 测试 once 和 emit +em.once("e2", fn1) + .once("e2", fn2) + .emit("e2", 3, 4, 5) // 3, 4, 5 6, 12 + .emit("e2", 3, 4, 5) // 3, 4, 5 + .emit("e2", 3, 4, 5); // 3, 4, 5 +console.log(em.cache); // [] diff --git a/interview/handwrite/utils/getAge.js b/interview/handwrite/utils/getAge.js new file mode 100644 index 00000000..5831d68f --- /dev/null +++ b/interview/handwrite/utils/getAge.js @@ -0,0 +1,25 @@ +function getAge(birthday) { + const validator = new RegExp(/^\d{4}-\d{2}-\d{2}$/); + if (!validator.test(birthday)) { + throw new Error(`invalidator birthday: ${birthday}`); + } + + const [birthYear, birthMonth, birthDate] = birthday.split('-').map(str => Number(str)); + const now = new Date(); + const nowYear = now.getFullYear(); + const nowMonth = now.getMonth() + 1; + const nowDate = now.getDate(); + + const age = nowYear - birthYear - 1; + if (nowMonth > birthMonth || (nowMonth === birthMonth && nowDate > birthDate)) { + return age + 1; + } + return age; +} + +// ---- test case ---- +var log = console.log +log(getAge('1995-09-12')) +log(getAge('1995-12-26')) +log(getAge('1997-12-02')) +log(getAge('1997-12-28')) diff --git a/interview/handwrite/utils/getFrequentTag.js b/interview/handwrite/utils/getFrequentTag.js new file mode 100644 index 00000000..b8d4e842 --- /dev/null +++ b/interview/handwrite/utils/getFrequentTag.js @@ -0,0 +1,11 @@ +function getFrequentTag() { + const o = $$('*') // = document.querySelectorAll('*') + .map(it => it.tagName.toLowerCase()) + .reduce((o, tagName) => { + o[tagName] = o[tagName] ? o[tagName] + 1 : 1; + return o; + }, {}); + + return Object.entries(o) + .reduce((x, y) => x[1] > y[1] ? x : y); +} diff --git a/interview/handwrite/utils/myDeepClone.js b/interview/handwrite/utils/myDeepClone.js new file mode 100644 index 00000000..20fa36d2 --- /dev/null +++ b/interview/handwrite/utils/myDeepClone.js @@ -0,0 +1,47 @@ +const myDeepClone = function (origin, vm = new WeakMap) { + if (typeof origin !== 'object' || origin == null) return origin; + if (origin instanceof Date) return new Date(origin); + if (origin instanceof RegExp) return new RegExp(origin); + // weakMap dispose circular deps + const stashed = vm.get(origin); + if (stashed) return stashed; + let target = Array.isArray(origin) ? [] : {}; + vm.set(origin, target); + for (const key in origin) { + if (origin.hasOwnProperty(key)) { + target[key] = myDeepClone(origin[key], vm); + } + } + return target; +} + +// ---- test case 1 ---- +var p1 = { + name: 'william', + age: 12, + birthday: new Date('1995-09-12'), + hobby: ['eat', 'sleep', 'code'], + address: { + city: 'shenzhen' + }, +} + +var p2 = myDeepClone(p1) +p1.address.city = 'beijing' +p2.hobby.push('music') +console.log(p1, p2) // p1、p2 相互独立 + +// ---- test case 2 ---- +var o1 = {x: 1}, o2 = {y: 2} +o1.a = o2 +o2.b = o1 +var o3 = myDeepClone(o1) +o1.z = 100 +console.log(o1, o3) + +// ---- test case 3 ---- +var arr1 = [1, 2, 3] +arr1.push(arr1) +var arr2 = myDeepClone(arr1) +arr2.push(1) +console.log(arr1, arr2) From a4049f2bfc7176c14e27d634a73d8c952b41636d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 20 Dec 2023 11:54:59 +0800 Subject: [PATCH 191/210] feat: handwrite --- interview/handwrite/esapi/01_bind.js | 14 +++ interview/handwrite/esapi/02_sleep_delay.js | 33 +++++ interview/handwrite/esapi/03_promiseAll.js | 21 ++++ interview/handwrite/esapi/04_isArray.js | 11 ++ interview/handwrite/esapi/05_flat.js | 14 +++ interview/handwrite/esapi/06_promise.js | 128 ++++++++++++++++++++ interview/handwrite/esapi/07_arrayReduce.js | 13 ++ interview/handwrite/esapi/08_trim.js | 4 + 8 files changed, 238 insertions(+) create mode 100644 interview/handwrite/esapi/01_bind.js create mode 100644 interview/handwrite/esapi/02_sleep_delay.js create mode 100644 interview/handwrite/esapi/03_promiseAll.js create mode 100644 interview/handwrite/esapi/04_isArray.js create mode 100644 interview/handwrite/esapi/05_flat.js create mode 100644 interview/handwrite/esapi/06_promise.js create mode 100644 interview/handwrite/esapi/07_arrayReduce.js create mode 100644 interview/handwrite/esapi/08_trim.js diff --git a/interview/handwrite/esapi/01_bind.js b/interview/handwrite/esapi/01_bind.js new file mode 100644 index 00000000..98fc9806 --- /dev/null +++ b/interview/handwrite/esapi/01_bind.js @@ -0,0 +1,14 @@ +// 手动绑定 this +Function.prototype.fakeBind = function (obj, ...args) { + return (...rest) => { + this.call(obj, ...args, ...rest); + } +} + +// ---- test case ---- +function f(b) { + console.log(this.a, b); +} + +f.fakeBind({a: 3})(4); +f.fakeBind({a: 3}, 10)(11); diff --git a/interview/handwrite/esapi/02_sleep_delay.js b/interview/handwrite/esapi/02_sleep_delay.js new file mode 100644 index 00000000..62e7d8a8 --- /dev/null +++ b/interview/handwrite/esapi/02_sleep_delay.js @@ -0,0 +1,33 @@ +const sleep = (time) => new Promise(resolve => setTimeout(resolve, time)); + +function delay(func, time, ...args) { + return new Promise((resolve) => { + setTimeout(() => { + Promise.resolve(func(...args)).then(resolve); + }, time); + }) +} + +// ---- test case ---- +// ;(async () => { +// console.log(1); +// await sleep(1000); +// console.log(2); +// })(); + + +console.log(new Date()) +delay( + (str) => { + return new Error(str) + }, + 3000, + 'wlwlwl' + ) + .then( + o => console.log('then:', o) + ).catch( + e => { + console.log('error:', e) + } + ) diff --git a/interview/handwrite/esapi/03_promiseAll.js b/interview/handwrite/esapi/03_promiseAll.js new file mode 100644 index 00000000..b5941812 --- /dev/null +++ b/interview/handwrite/esapi/03_promiseAll.js @@ -0,0 +1,21 @@ +// Promise.all + +function pAll(_promises) { + return new Promise((resolve, reject) => { + // Iterable => Array + const promises = Array.from(_promises); + // 结果用一个数组维护 + const r = []; + const len = promises.length; + let count = 0; + for (let i = 0; i < len; ++i) { + // Promise.resolve 把所有数据都转化为 Promise + Promise.resolve(promises[i]).then(o => { + r[i] = o; + if (++count === len) { + resolve(r); + } + }).catch(e => reject(e)); + } + }) +} diff --git a/interview/handwrite/esapi/04_isArray.js b/interview/handwrite/esapi/04_isArray.js new file mode 100644 index 00000000..64fd7f3f --- /dev/null +++ b/interview/handwrite/esapi/04_isArray.js @@ -0,0 +1,11 @@ +const isArray = (ele) => { + // return ele instanceof Array + return Object.prototype.toString.call(ele) === '[object Array]'; +} + +const log = console.log; +log(isArray(null)); +log(isArray(123)); +log(isArray('123')); +log(isArray([])); +log(isArray(new Array())); diff --git a/interview/handwrite/esapi/05_flat.js b/interview/handwrite/esapi/05_flat.js new file mode 100644 index 00000000..aee3b361 --- /dev/null +++ b/interview/handwrite/esapi/05_flat.js @@ -0,0 +1,14 @@ +// 思路:reduce + concat +function flatten(list, depth = 1) { + if (depth === 0) return list; + return list.reduce((a, b) => { + const target = Array.isArray(b) ? flatten(b, depth - 1) : b; + return a.concat(target); + }, []) +} + + +// ---- test case ---- +const a = flatten([1, 2, 3, [4, [5, 6]]]); +const b = flatten([1, 2, 3, [4, [5, 6]]], 2); +console.log(a, b); diff --git a/interview/handwrite/esapi/06_promise.js b/interview/handwrite/esapi/06_promise.js new file mode 100644 index 00000000..a2666e0c --- /dev/null +++ b/interview/handwrite/esapi/06_promise.js @@ -0,0 +1,128 @@ +// 异步链式有点难 + +const STATUS = { + PENDING: "PENDING", + FULFILLED: "FULFILLED", + REJECTED: "REJECTED", +}; + +class MyPromise { + + static resolve(value) { + if (value && value.then) { + return value; + } + return new MyPromise(resolve => resolve(value)); + } + + constructor(executer) { + this.status = STATUS.PENDING; + this.value = void 0; // return value when succ + this.reason = void 0; // return value when fail + this.resolveQueue = []; // callbacks of succ + this.rejectQueue = []; // callbacks of fail + + // revert status & execute resolveQueue + const resolve = (value) => { + setTimeout(() => { + if (this.status === STATUS.PENDING) { + this.status = STATUS.FULFILLED; + this.value = value; + // console.log(this.resolveQueue) + this.resolveQueue.forEach(({ fn, resolve: res}) => { + return res(fn(value)); + }); + } + }) + }; + + // revert status & execute rejectQueue + const reject = (reason) => { + setTimeout(() => { + if (this.status === STATUS.PENDING) { + this.status = STATUS.REJECTED; + this.reason = reason; + // console.log(this.rejectQueue) + this.rejectQueue.forEach(({ fn, reject: rej }) => { + return rej(fn(reason)); + }); + } + }) + }; + + try { + executer(resolve, reject); + } catch (error) { + reject(error); + } + } + + then(onFullfilled, onRejected) { + if (this.status === STATUS.FULFILLED) { + const result = fn(this.value); + return MyPromise.resolve(result); + } + if (this.status === STATUS.PENDING) { + return new MyPromise((resolve, reject) => { + this.resolveQueue.push({ fn: onFullfilled, resolve, reject }); + this.rejectQueue.push({ fn: onRejected, resolve, reject }); + }) + } + } +} + +// ---- test case ---- +// 同步调用 +// new MyPromise((resolve, reject) => { +// console.log("[sync promise]"); +// resolve("🙆‍♂️"); +// reject("🙅‍♂️"); +// }).then( +// (value) => { +// console.log("[sync fulfilled]", value); +// }, +// (reason) => { +// console.log("[sync rejected]", reason); +// } +// ); + +// 异步调用 +// new MyPromise((resolve, reject) => { +// console.log("[async promise]"); +// setTimeout(() => { +// resolve("🙆‍♂️"); +// }, 500); +// setTimeout(() => { +// reject("🙅‍♂️"); +// }, 100); +// }).then( +// (value) => { +// console.log("[async fulfilled]", value); +// }, +// (reason) => { +// console.log("[async rejected]", reason); +// } +// ); + +// 异步链式调用 +const startTime = new Date(); +var p2 = new MyPromise((resolve, reject) => { + console.log("promise start:", new Date() - startTime); + setTimeout(() => { + console.log("promise resolve:", new Date() - startTime); + resolve("value1"); + }, 2000); +}) + .then((value) => { + return new MyPromise((resolve) => { + console.log("then1", value, new Date() - startTime); + setTimeout(() => { + console.log("then resolve", new Date() - startTime); + resolve("value2"); + }, 3000); + }); + }) + .then((value) => { + console.log("then2", value, new Date() - startTime); + }, (err) => {console.log(err)}); +// console.log(p2); diff --git a/interview/handwrite/esapi/07_arrayReduce.js b/interview/handwrite/esapi/07_arrayReduce.js new file mode 100644 index 00000000..31c23a32 --- /dev/null +++ b/interview/handwrite/esapi/07_arrayReduce.js @@ -0,0 +1,13 @@ +const reduce = (list, fn, ...init) => { + let next = init.length ? init[0] : list[0]; + for (let i = init.length ? 0 : 1; i < list.length; ++i) { + next = fn(next, list[i], i); + } + return next; +} + +// ---- test case ---- +const res = reduce([1,2,3,4,5], (sum, num) => { + return sum + num; +}, 100); +console.log(res); // 115 diff --git a/interview/handwrite/esapi/08_trim.js b/interview/handwrite/esapi/08_trim.js new file mode 100644 index 00000000..8cb95bc9 --- /dev/null +++ b/interview/handwrite/esapi/08_trim.js @@ -0,0 +1,4 @@ +const trim = str => str.replace(/^\s+|\s+$/g, ''); + +// ---- test case ---- +console.log(trim(' abcd ')); From dba1024785ee802d926c2f938cb6119083863ddc Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 20 Dec 2023 18:01:47 +0800 Subject: [PATCH 192/210] feat: lodashapi --- .../lodashapi/01_throttle_debounce.js | 33 +++++++++++++++++++ .../02_cloneDeep.js} | 0 interview/handwrite/lodashapi/03_isEqual.js | 20 +++++++++++ 3 files changed, 53 insertions(+) create mode 100644 interview/handwrite/lodashapi/01_throttle_debounce.js rename interview/handwrite/{utils/myDeepClone.js => lodashapi/02_cloneDeep.js} (100%) create mode 100644 interview/handwrite/lodashapi/03_isEqual.js diff --git a/interview/handwrite/lodashapi/01_throttle_debounce.js b/interview/handwrite/lodashapi/01_throttle_debounce.js new file mode 100644 index 00000000..c953b5e9 --- /dev/null +++ b/interview/handwrite/lodashapi/01_throttle_debounce.js @@ -0,0 +1,33 @@ + +function debounce(f, wait) { + let timer; + return function(...args) { + clearTimeout(timer); + timer = setTimeout(() => { + f.apply(this, args); + }, wait); + } +} + +function throttle(f, wait) { + let timer; + return function (...args) { + if (timer) return; + timer = setTimeout(() => { + f.apply(this, args); + timer = null; + }, wait); + } +} + +// 时间戳版 throttle +function throttleByTime(f, wait) { + let lastTime = 0; + return function(...args) { + const now = Date.now(); + if (now - lastTime >= wait) { + f.apply(this, args); + lastTime = now; + } + } +} diff --git a/interview/handwrite/utils/myDeepClone.js b/interview/handwrite/lodashapi/02_cloneDeep.js similarity index 100% rename from interview/handwrite/utils/myDeepClone.js rename to interview/handwrite/lodashapi/02_cloneDeep.js diff --git a/interview/handwrite/lodashapi/03_isEqual.js b/interview/handwrite/lodashapi/03_isEqual.js new file mode 100644 index 00000000..f3a66019 --- /dev/null +++ b/interview/handwrite/lodashapi/03_isEqual.js @@ -0,0 +1,20 @@ +function isEqual(x, y) { + if (x === y) return true; + if (typeof x === 'object' && !!x && typeof y === 'object' && !!y) { + const keysX = Object.keys(x); + const keysY = Object.keys(y); + if (keysX.length !== keysY.length) return false; + for (const key of keysX) { + if (!isEqual(x[key], y[key])) return false; // recursive + } + return true; + } + return false; +} + +// ---- test case ---- +const o1 = { a: [1,2,3], b:'222', c: { d: { e: [34] }, e: 1 } } +const o2 = { a: [1,2,3], b:'222', c: { d: { e: [34] }, e: 1 } } +const o3 = { a: [1,2,3], b:'222', c: { d: { e: [35] }, e: 1 } } +console.log(isEqual(o1, o2)); +console.log(isEqual(o3, o2)); From c8d7a36b90f7b221a35be6d5d8ac27412dcd800e Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 22 Dec 2023 08:07:58 +0800 Subject: [PATCH 193/210] feat: this --- interview/handwrite/lodashapi/04_get.js | 7 +++++ js_basic/this.html | 40 +++++++++++++++++++++++++ js_basic/this0.html | 13 ++++++++ js_basic/this1.html | 17 +++++++++++ js_basic/this2.html | 15 ++++++++++ 5 files changed, 92 insertions(+) create mode 100644 interview/handwrite/lodashapi/04_get.js create mode 100644 js_basic/this.html create mode 100644 js_basic/this0.html create mode 100644 js_basic/this1.html create mode 100644 js_basic/this2.html diff --git a/interview/handwrite/lodashapi/04_get.js b/interview/handwrite/lodashapi/04_get.js new file mode 100644 index 00000000..4c799d18 --- /dev/null +++ b/interview/handwrite/lodashapi/04_get.js @@ -0,0 +1,7 @@ +function get(source, path, defaultValue) { + // a[3].b -> a.3.b -> [a, 3, b] + const paths = path.replace() +} + +// ---- test case ---- + diff --git a/js_basic/this.html b/js_basic/this.html new file mode 100644 index 00000000..60361176 --- /dev/null +++ b/js_basic/this.html @@ -0,0 +1,40 @@ + diff --git a/js_basic/this0.html b/js_basic/this0.html new file mode 100644 index 00000000..06097261 --- /dev/null +++ b/js_basic/this0.html @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/js_basic/this1.html b/js_basic/this1.html new file mode 100644 index 00000000..efee65d7 --- /dev/null +++ b/js_basic/this1.html @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/js_basic/this2.html b/js_basic/this2.html new file mode 100644 index 00000000..f818b39b --- /dev/null +++ b/js_basic/this2.html @@ -0,0 +1,15 @@ + \ No newline at end of file From 07cd830b610d452006795b981e340dd9b02729b5 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 25 Dec 2023 21:33:54 +0800 Subject: [PATCH 194/210] feat: red book interview 1 --- interview/redbook/arrayToTree.js | 59 ++++++++++++++++++++++++++++++++ interview/redbook/eventQueue.js | 12 +++++++ interview/redbook/reactEvent.jsx | 19 ++++++++++ 3 files changed, 90 insertions(+) create mode 100644 interview/redbook/arrayToTree.js create mode 100644 interview/redbook/eventQueue.js create mode 100644 interview/redbook/reactEvent.jsx diff --git a/interview/redbook/arrayToTree.js b/interview/redbook/arrayToTree.js new file mode 100644 index 00000000..ade05f58 --- /dev/null +++ b/interview/redbook/arrayToTree.js @@ -0,0 +1,59 @@ +const arr = [ + {id: 2, title: '部门2', pid: 1}, + {id: 3, title: '部门3', pid: 1}, + {id: 1, title: '部门1', pid: 0}, + {id: 4, title: '部门4', pid: 3}, + {id: 5, title: '部门5', pid: 4}, +] + +/** + * 1 + * / \ + * 2 3 + * | + * 4 + * | + * 5 + */ + +// 解法一:递归 +const arrayToTree1 = (source, rootId) => { + if (!Array.isArray(source)) return []; + + const res = []; + for (const item of source) { + if (item.pid === rootId) { + item.children = arrayToTree1(source, item.id) || []; + res.push(item); + } + } + return res; +} + +// 解法二:构建缓存 +const arrayToTree2 = (source, rootId) => { + if (!Array.isArray(source)) return []; + + const map = new Map(); + for (const item of source) { + map.set(item.id, item); + } + + // console.log(JSON.stringify(Object.fromEntries(map.entries()), null, 2)); + const res = []; + for (const item of source) { + const { pid }= item; + if (pid === rootId) { + res.push(item); + } else { + const parentItem = map.get(pid); + const origChildren = parentItem.children || []; + console.log(parentItem) + parentItem.children = [origChildren, item]; + } + } + return res; +} + +const res = arrayToTree2(arr, 0); +console.log(JSON.stringify(res, null, 2)); diff --git a/interview/redbook/eventQueue.js b/interview/redbook/eventQueue.js new file mode 100644 index 00000000..ba279e49 --- /dev/null +++ b/interview/redbook/eventQueue.js @@ -0,0 +1,12 @@ + +setTimeout(() => { + Promise.resolve(1).then(console.log); + console.log(2); +}, 0); + +setTimeout(() => { + console.log(3); +}, 0); +console.log(4); + +// 4 2 1 3 diff --git a/interview/redbook/reactEvent.jsx b/interview/redbook/reactEvent.jsx new file mode 100644 index 00000000..9c0a74d1 --- /dev/null +++ b/interview/redbook/reactEvent.jsx @@ -0,0 +1,19 @@ +import { useRef } from "react" + +export function App() { + const ref = useRef(null); + + document.addEventListener('click', (e) => { + console.log('document click', e); + }); + + ref.addEventListener('click', (e) => { + console.log('ref dom click', e); + }); + + return

+
{console.log('react event click', e)}} ref={ref} /> +
+} + +// react 合成事件有什么好处 From 6851b9b232090105c214b16b40bc2b2bc1974cff Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 25 Dec 2023 21:41:36 +0800 Subject: [PATCH 195/210] feat: add interview ques react render --- interview/bytedance/react03.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 interview/bytedance/react03.js diff --git a/interview/bytedance/react03.js b/interview/bytedance/react03.js new file mode 100644 index 00000000..46839abf --- /dev/null +++ b/interview/bytedance/react03.js @@ -0,0 +1,30 @@ +/** + * 构建一个 render 函数,将 data 对象渲染为以下 dom + +
    +
  • douyin
  • +
  • toutiao
  • +
+ + */ + +function Element({ tagName, props, children }) { + // your code +} + +Element.prototype.render = function () { + // your code +}; + + +// ---- test case ---- +const data = { + tagName: 'url', + props: { 'class': 'list' }, + children: [ + { tagName: 'li', children: ['douyin'] }, + { tagName: 'li', children: ['toutiao'] }, + ] +} + +console.log(Element(data)); From cd053e0ce49b7122340be95a216aa36373b6f836 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 25 Dec 2023 21:55:49 +0800 Subject: [PATCH 196/210] feat: solve react render --- interview/bytedance/react03.html | 62 ++++++++++++++++++++++++++++++++ interview/bytedance/react03.js | 30 ---------------- 2 files changed, 62 insertions(+), 30 deletions(-) create mode 100644 interview/bytedance/react03.html delete mode 100644 interview/bytedance/react03.js diff --git a/interview/bytedance/react03.html b/interview/bytedance/react03.html new file mode 100644 index 00000000..ebc6087d --- /dev/null +++ b/interview/bytedance/react03.html @@ -0,0 +1,62 @@ + diff --git a/interview/bytedance/react03.js b/interview/bytedance/react03.js deleted file mode 100644 index 46839abf..00000000 --- a/interview/bytedance/react03.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * 构建一个 render 函数,将 data 对象渲染为以下 dom - -
    -
  • douyin
  • -
  • toutiao
  • -
- - */ - -function Element({ tagName, props, children }) { - // your code -} - -Element.prototype.render = function () { - // your code -}; - - -// ---- test case ---- -const data = { - tagName: 'url', - props: { 'class': 'list' }, - children: [ - { tagName: 'li', children: ['douyin'] }, - { tagName: 'li', children: ['toutiao'] }, - ] -} - -console.log(Element(data)); From 65477c0d1e94013a483465ffbcf0295b80d5af44 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 26 Dec 2023 01:00:13 +0800 Subject: [PATCH 197/210] feat: solve this --- interview/this/01_1.html | 14 ++++++++++++++ interview/this/01_2.html | 16 ++++++++++++++++ interview/this/01_3.html | 18 ++++++++++++++++++ interview/this/02.html | 11 +++++++++++ interview/this/03.html | 21 ++++++++++++++++++++ interview/this/04.html | 41 ++++++++++++++++++++++++++++++++++++++++ interview/this/05.html | 18 ++++++++++++++++++ interview/this/06.html | 37 ++++++++++++++++++++++++++++++++++++ 8 files changed, 176 insertions(+) create mode 100644 interview/this/01_1.html create mode 100644 interview/this/01_2.html create mode 100644 interview/this/01_3.html create mode 100644 interview/this/02.html create mode 100644 interview/this/03.html create mode 100644 interview/this/04.html create mode 100644 interview/this/05.html create mode 100644 interview/this/06.html diff --git a/interview/this/01_1.html b/interview/this/01_1.html new file mode 100644 index 00000000..aa3ea4da --- /dev/null +++ b/interview/this/01_1.html @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/interview/this/01_2.html b/interview/this/01_2.html new file mode 100644 index 00000000..d3585146 --- /dev/null +++ b/interview/this/01_2.html @@ -0,0 +1,16 @@ + diff --git a/interview/this/01_3.html b/interview/this/01_3.html new file mode 100644 index 00000000..ade5d62e --- /dev/null +++ b/interview/this/01_3.html @@ -0,0 +1,18 @@ + diff --git a/interview/this/02.html b/interview/this/02.html new file mode 100644 index 00000000..7a7b4eaf --- /dev/null +++ b/interview/this/02.html @@ -0,0 +1,11 @@ + diff --git a/interview/this/03.html b/interview/this/03.html new file mode 100644 index 00000000..a1c40471 --- /dev/null +++ b/interview/this/03.html @@ -0,0 +1,21 @@ + diff --git a/interview/this/04.html b/interview/this/04.html new file mode 100644 index 00000000..9c8f875e --- /dev/null +++ b/interview/this/04.html @@ -0,0 +1,41 @@ + \ No newline at end of file diff --git a/interview/this/05.html b/interview/this/05.html new file mode 100644 index 00000000..e50c4957 --- /dev/null +++ b/interview/this/05.html @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/interview/this/06.html b/interview/this/06.html new file mode 100644 index 00000000..0d1433f9 --- /dev/null +++ b/interview/this/06.html @@ -0,0 +1,37 @@ + \ No newline at end of file From 49c022c11ce71cb078387ed6d61cc1dc04ad6474 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 28 Dec 2023 15:17:12 +0800 Subject: [PATCH 198/210] feat: solve placeholder --- interview/moe/1_placeholder.js | 71 ++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 interview/moe/1_placeholder.js diff --git a/interview/moe/1_placeholder.js b/interview/moe/1_placeholder.js new file mode 100644 index 00000000..c05d9734 --- /dev/null +++ b/interview/moe/1_placeholder.js @@ -0,0 +1,71 @@ +const __ = Symbol('PLACEHOLDER'); + +function hasSymbol(arr) { + // console.log('h:', arr); + for (const item of arr) { + if (typeof item === 'symbol') return true; + } + return false; +} + +function placeholder(fn, ...bound) { + while (bound.length < fn.length) { + bound.push(__); + } + return (...args) => { + const newArgs = bound.slice(); + for (let i = 0, j = 0; i < newArgs.length && j < args.length; ++i) { + if (newArgs[i] === __) { + newArgs[i] = args[j++]; + } + } + if (hasSymbol(newArgs)) { + return placeholder(fn, ...newArgs); + } else { + return fn(...newArgs); + } + } +} + +// ---- test case ---- + +function main() { + function dot(x1, y1, x2, y2) { + console.log('dot', x1, y1, x2, y2) + return x1 * x2 + y1 * y2; + } + + const p1 = placeholder(dot, 3, 4); + + // assert.deepStrictEqual(typeof placeholder(dot, 2, __, __, 4), 'function'); + console.log(typeof placeholder(dot, 2, __, __, 4), typeof p1); // 👉 function + // assert.deepStrictEqual(placeholder(dot, 10, __, 10, __)(2, 3), dot(10, 2, 10, 3)); + placeholder(dot, 10, __, 10, __)(2, 3); // 👉 10 2 10 3 + // assert.deepStrictEqual(placeholder(dot, __, __, __, 5)(4, __, 2)(__)(3), dot(4, 3, 2, 5)); + placeholder(dot, __, __, __, 5)(4, __, 2)(__)(3) // 👉 4 3 2 5 + // assert.deepStrictEqual(placeholder(dot, 3)(__, __)(4, __, 2)(3), dot(3, 4, 3, 2)); + placeholder(dot, 3)(__, __)(4, __, 2)(3) // 👉 3 4 3 2 + // assert.deepStrictEqual(placeholder(dot)(3, __, __, 4)(5, 6), dot(3, 5, 6, 4)); + placeholder(dot)(3, __, __, 4)(5, 6) // 👉 3 5 6 4 + // assert.deepStrictEqual(placeholder(dot, 3, 4, 5, 3)(), dot(3, 4, 5, 3)); + placeholder(dot, 3, 4, 5, 3)() // 👉 3 4 5 3 + + // assert.deepStrictEqual(p1(5, 6), dot(3, 4, 5, 6)); + p1(5, 6); // 👉 3 4 5 6 + // assert.deepStrictEqual(p1(7, 8), dot(3, 4, 7, 8)); + p1(7, 8); // 👉 3 4 7 8 + // assert.deepStrictEqual(p1(5)(6), dot(3, 4, 5, 6)); + p1(5)(6); // 👉 3 4 5 6 + // assert.deepStrictEqual(p1(7)(8), dot(3, 4, 7, 8)); + p1(7)(8); // 👉 3 4 7 8 + + const p2 = p1(__, 6); + console.log(typeof p2); // 👉 function + p2(5); // 👉 3 4 5 6 + p2(6); // 👉 3 4 6 6 + + console.log('PASSED!'); + } + + main() + From d7edbcec6f421f7dcdb531878cbc67a760f3b847 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 28 Dec 2023 15:29:14 +0800 Subject: [PATCH 199/210] feat: not solve number to chinese --- interview/moe/2_numberToChinese.js | 80 ++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 interview/moe/2_numberToChinese.js diff --git a/interview/moe/2_numberToChinese.js b/interview/moe/2_numberToChinese.js new file mode 100644 index 00000000..7a9ed32a --- /dev/null +++ b/interview/moe/2_numberToChinese.js @@ -0,0 +1,80 @@ +/** + * TODO + * 数字转化为中文描述 + */ +function chineseNumber(num) { + const chineseMap = new Map([ + [0, "零"], + [1, "一"], + [2, "二"], + [3, "三"], + [4, "四"], + [5, "五"], + [6, "六"], + [7, "七"], + [8, "八"], + [9, "九"], + ]); + const unitMap = new Map([ + [1, ""], + [10, "十"], + [100, "百"], + [1000, "千"], + [10000, "万"], + [100000, "十万"], + [1000000, "百万"], + [10000000, "千万"], + [100000000, "亿"], + [1000000000, "十亿"], + [10000000000, "百亿"], + [100000000000, "千亿"], + [1000000000000, "万亿"], + [10000000000000, "十万亿"], + [100000000000000, "百万亿"], + [1000000000000000, "千万亿"], + ]); + + if (num < 10) { + return chineseMap.get(num); + } + + if (num < 100) { + const tenDigit = Math.floor(num / 10); + const remainder = num % 10; + let res = chineseMap.get(tenDigit) + unitMap.get(10); + if (remainder === 0) { + return res; + } else { + return res + chineseMap.get(remainder); + } + } + + // if (num > 10000) { + // const unitDigit = Math.floor(num / 10000); + // const remainder = num % 10000; + // return + // } + + for (const unit of unitMap.keys()) { + if (unit <= num && num < unit * 10) { + const unitDigit = Math.floor(num / unit); + const remainder = num % unit; + if (remainder === 0) { + return chineseNumber(unitDigit) + unitMap.get(unit); + } else { + return ( + chineseNumber(unitDigit) + + unitMap.get(unit) + + chineseNumber(remainder) + ); + } + } + } +} + +// 示例用法 +console.log(chineseNumber(1234)); +console.log(chineseNumber(5678)); +console.log(chineseNumber(1234_5678)); // 一千二百三十四万五千六百七十八 +console.log(chineseNumber(1234_5678_9098_7654)); // 一千二百三十四万五千六百七十八亿九千零九十八万七千六百五十四 +console.log(chineseNumber(1200_0000_0000_0200)); // 一千二百 万 亿 零 二百 From a47522bfe43749a29234e11f833eae6574bd93ff Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 28 Dec 2023 15:33:19 +0800 Subject: [PATCH 200/210] feat: not solve number to chinese2 --- interview/moe/2_numberToChinese.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/interview/moe/2_numberToChinese.js b/interview/moe/2_numberToChinese.js index 7a9ed32a..883c049d 100644 --- a/interview/moe/2_numberToChinese.js +++ b/interview/moe/2_numberToChinese.js @@ -20,18 +20,8 @@ function chineseNumber(num) { [10, "十"], [100, "百"], [1000, "千"], - [10000, "万"], - [100000, "十万"], - [1000000, "百万"], - [10000000, "千万"], - [100000000, "亿"], - [1000000000, "十亿"], - [10000000000, "百亿"], - [100000000000, "千亿"], - [1000000000000, "万亿"], - [10000000000000, "十万亿"], - [100000000000000, "百万亿"], - [1000000000000000, "千万亿"], + [1_0000, "万"], + [1_0000_0000, "亿"], ]); if (num < 10) { @@ -70,6 +60,7 @@ function chineseNumber(num) { } } } + return '' } // 示例用法 From 741d9fed46a50fd065b6a641dd6197eee08a7467 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Fri, 29 Dec 2023 01:06:18 +0800 Subject: [PATCH 201/210] feat: scheduler --- interview/bytedance/scheduler.js | 54 ++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 interview/bytedance/scheduler.js diff --git a/interview/bytedance/scheduler.js b/interview/bytedance/scheduler.js new file mode 100644 index 00000000..04bd9d0e --- /dev/null +++ b/interview/bytedance/scheduler.js @@ -0,0 +1,54 @@ +/** + * 带并发限制的异步调度器 + */ + +class Scheduler { + concurrency = 2; + running = 0; + queue = []; + + add(task) { + return new Promise(resolve => { + this.queue.push({ + taskGenerator: task, + resolve, + }); + this.schedule(); + }) + } + + schedule() { + while (this.queue.length > 0 && this.running < this.concurrency) { + const curTask = this.queue.shift(); + this.running += 1; + curTask.taskGenerator().then(result => { + this.running -= 1; + curTask.resolve(result); + this.schedule(); + }) + } + } +} + +// ---- test case ---- +const timeout = (time) => + new Promise((resolve) => { + setTimeout(resolve, time); + }); + +const scheduler = new Scheduler(); +const addTask = (time, order) => { + scheduler.add(() => timeout(time)).then(() => console.log(`[${new Date().toLocaleString()}] `, order)); +}; + +console.log(`[${new Date().toLocaleString()}] start...`); +addTask(10000, "1"); +addTask(5000, "2"); +addTask(3000, "3"); +addTask(4000, "4"); +// output: 2 3 1 4 +// 一开始,1、2两个任务进入队列 +// 500ms时,2完成,输出2,任务3进队 +// 800ms时,3完成,输出3,任务4进队 +// 1000ms时,1完成,输出1 +// 1200ms时,4完成,输出4 From e6a1822aff8e04c8f251a70f277d1edcb443e841 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 31 Dec 2023 16:04:58 +0800 Subject: [PATCH 202/210] feat: graph --- Week_04/200numIslands.js | 46 ++++++++++++++---------------- hot100/graph/994_orangesRotting.js | 45 +++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 hot100/graph/994_orangesRotting.js diff --git a/Week_04/200numIslands.js b/Week_04/200numIslands.js index 472fb908..4caa1106 100644 --- a/Week_04/200numIslands.js +++ b/Week_04/200numIslands.js @@ -5,34 +5,32 @@ */ // dfs -const numIslands = function(A) { - if (!Array.isArray(A) || A.length < 1 || - !Array.isArray(A[0] || A[0].length < 1)) return 0 +var numIslands = function(A) { + if (!Array.isArray(A) || A.length < 1 || !Array.isArray(A[0]) || A[0].length < 1) return 0; - const dfsMarking = (i, j) => { - if (i >= 0 && i < m && - j >= 0 && j < n && - A[i][j] === '1') { - A[i][j] = '0' - dfsMarking(i + 1, j) - dfsMarking(i - 1, j) - dfsMarking(i, j + 1) - dfsMarking(i, j - 1) + const m = A.length, n = A[0].length; + let cnt = 0; + + const dfsMarking = (i, j) => { + if (i >= 0 && i < m && j >= 0 && j < n && A[i][j] === '1') { + A[i][j] = '0'; + dfsMarking(i + 1, j); + dfsMarking(i - 1, j); + dfsMarking(i, j + 1); + dfsMarking(i, j - 1); + } } - } - const m = A.length, n = A[0].length - let cnt = 0 - for (let i = 0; i < m; ++i) { - for (let j = 0; j < n; ++j) { - if (A[i][j] === '1') { - ++cnt - dfsMarking(i, j) - } + for (let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + if (A[i][j] === '1') { + ++cnt; + dfsMarking(i, j); + } + } } - } - return cnt -} + return cnt; +}; // ---- test case ---- diff --git a/hot100/graph/994_orangesRotting.js b/hot100/graph/994_orangesRotting.js new file mode 100644 index 00000000..33171744 --- /dev/null +++ b/hot100/graph/994_orangesRotting.js @@ -0,0 +1,45 @@ +/** + * https://leetcode.cn/problems/rotting-oranges + * + */ + +// BFS +var orangesRotting = function(A) { + const m = A.length, n = A[0].length; + const queue = []; + let freshCnt = 0; + // Step1: 统计新鲜橘子的数量 freshCnt,并且把烂橘子坐标放入队列 + for (let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + if (A[i][j] === 1) { + ++freshCnt; + } else if (A[i][j] === 2) { + queue.push([i, j]); + } + } + } + + // 尝试感染位置 r,c + const mark = (r, c) => { + if (r >= 0 && r < m && c >= 0 && c < n && A[r][c] === 1) { + A[r][c] = 2; + --freshCnt; + queue.push([r, c]); + } + } + + // Step2: BFS 传染 + let round = 0; + while (freshCnt && queue.length) { + ++round; + const size = queue.length; + for (let i = 0; i < size; ++i) { + const [r, c] = queue.shift(); + mark(r - 1, c); + mark(r + 1, c); + mark(r, c + 1); + mark(r, c - 1); + } + } + return freshCnt > 0 ? -1 : round; +}; From fac5dacf05e0e092c2d1d22b37ed02a6eb9f1b90 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 2 Jan 2024 00:10:08 +0800 Subject: [PATCH 203/210] feat: solve 763 with greedy --- hot100/greedy/763partitionLabels.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 hot100/greedy/763partitionLabels.js diff --git a/hot100/greedy/763partitionLabels.js b/hot100/greedy/763partitionLabels.js new file mode 100644 index 00000000..70459e85 --- /dev/null +++ b/hot100/greedy/763partitionLabels.js @@ -0,0 +1,29 @@ +/** + * https://leetcode.cn/problems/partition-labels + * 划分字母区间 + * + */ + +var partitionLabels = (S) => { + const lastPosMap = new Map(); // 字母的最远位置 + for (let i = 0; i < S.length; ++i) { + lastPosMap.set(S[i], i); + } + + const res = []; + let start = 0; // 切割点 + let maxPos = 0; // 已扫描的字符中,最远的位置 + for (let i = 0; i < S.length; ++i) { + const curLastPos = lastPosMap.get(S[i]); + maxPos = Math.max(maxPos, curLastPos); + if (i === maxPos) { + res.push(i - start + 1); + start = i + 1; + } + } + return res; +} + +// ---- test case ---- +console.log(partitionLabels('ababcbacadefegdehijhklij')); // [9, 7, 8] +console.log(partitionLabels('eccbbbbdec')); // [10] From 7d92589a6819a1466f3e13f39e1de8a7d727e124 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Tue, 2 Jan 2024 00:39:35 +0800 Subject: [PATCH 204/210] feat: solve 207 with adjTable --- hot100/graph/207canFinish.js | 44 +++++++++++++++++++ ...orangesRotting.js => 994orangesRotting.js} | 0 2 files changed, 44 insertions(+) create mode 100644 hot100/graph/207canFinish.js rename hot100/graph/{994_orangesRotting.js => 994orangesRotting.js} (100%) diff --git a/hot100/graph/207canFinish.js b/hot100/graph/207canFinish.js new file mode 100644 index 00000000..8b3a0759 --- /dev/null +++ b/hot100/graph/207canFinish.js @@ -0,0 +1,44 @@ +/** + * https://leetcode.cn/problems/course-schedule + * 课程安排 + */ + +var canFinish = function (numCourses, prerequisites) { + const inDegree = Array(numCourses).fill(0); // 统计节点的入度 + const adjTable = new Map(); // 邻接表 + for (let i = 0; i < prerequisites.length; ++i) { + const [to, from] = prerequisites[i]; + inDegree[to]++; + if (adjTable.has(from)) { + const arr = adjTable.get(from); + arr.push(to); + } else { + adjTable.set(from, [to]); + } + } + + const queue = []; + for (let i = 0; i < inDegree.length; ++i) { + if (inDegree[i] === 0) queue.push(i); // 入度为零的课入队 + } + + let count = 0; + while (queue.length) { + const selected = queue.shift(); // 当前选中的课 + ++count; + const toList = adjTable.get(selected); // 这门课的后续课程 + if (toList && toList.length) { + for (const toItem of toList) { + --inDegree[toItem]; + if (inDegree[toItem] === 0) { + queue.push(toItem); + } + } + } + } + return count === numCourses; +}; + +// ---- test cases ---- +console.log(canFinish(2, [[1,0]])); // true +console.log(canFinish(2, [[1,0],[0,1]])); // false diff --git a/hot100/graph/994_orangesRotting.js b/hot100/graph/994orangesRotting.js similarity index 100% rename from hot100/graph/994_orangesRotting.js rename to hot100/graph/994orangesRotting.js From 203e0027119f6eacedf2a1b93e720b674ada287d Mon Sep 17 00:00:00 2001 From: Si3ver Date: Wed, 3 Jan 2024 22:57:23 +0800 Subject: [PATCH 205/210] feat: solve 279 numSquares --- hot100/dp/279numSquares.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 hot100/dp/279numSquares.js diff --git a/hot100/dp/279numSquares.js b/hot100/dp/279numSquares.js new file mode 100644 index 00000000..966ae5b5 --- /dev/null +++ b/hot100/dp/279numSquares.js @@ -0,0 +1,23 @@ +/** + * https://leetcode.cn/problems/perfect-squares + * 完全平方数 + * + * dp[i] = min( i, f(i-j*j)+1 ) + * O(n ^ 3/2) + */ + +var numSquares = function(n) { + const dp = Array(n + 1).fill(0); + for (let i = 1; i <= n; ++i) { + dp[i] = i; + for (let j = 1; i - j * j >= 0; ++j) { + dp[i] = Math.min(dp[i], dp[i - j * j] + 1); + } + } + // console.log(n, dp); + return dp[n]; +} + +// ---- test case ---- +console.log(numSquares(12)); +console.log(numSquares(13)); From 8281cd583852b1a9f6346c20aaf8efbaea365461 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 4 Jan 2024 00:03:46 +0800 Subject: [PATCH 206/210] feat: quick sort --- codetop/912sortArray.js | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/codetop/912sortArray.js b/codetop/912sortArray.js index e435b783..294b414e 100644 --- a/codetop/912sortArray.js +++ b/codetop/912sortArray.js @@ -3,29 +3,28 @@ * 912. 排序数组 | medium */ -function quickSort(arr, left = 0, right = arr.length - 1) { - if (left >= right) return - const pivotIdx = partition(arr, left, right) - quickSort(arr, left, pivotIdx - 1) - quickSort(arr, pivotIdx + 1, right) -} - -function partition(arr, left, right) { - const pivot = arr[left] - while (left < right) { - while (left < right && arr[right] >= pivot) --right - if (left < right) arr[left] = arr[right] - while (left < right && arr[left] <= pivot) ++left - if (left < right) arr[right] = arr[left] - } - arr[left] = pivot - return left -} +var sortArray = function(nums, left = 0, right = nums.length - 1) { + if (left >= right) return nums; + const pivotIndex = partition(nums, left, right); + sortArray(nums, left, pivotIndex - 1); + sortArray(nums, pivotIndex + 1, right); + return nums; +}; -function sortArray(arr) { - quickSort(arr, 0, arr.length - 1) - return arr +function partition(nums, left, right) { + const pivot = nums[left]; + while (left < right) { + // console.log(left, right, nums) + while (left < right && nums[right] >= pivot) --right; + if (left < right) nums[left] = nums[right]; + while (left < right && nums[left] <= pivot) ++left; + if (left < right) nums[right] = nums[left]; + } + nums[left] = pivot; + // console.log(nums, left, right) + return left; } // ---- test case ---- console.log(sortArray([5,2,3,1])) +console.log(sortArray([0])) From 42c286eeda30deeddfa55bcf5dcd6565bd8abc85 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Thu, 4 Jan 2024 00:29:11 +0800 Subject: [PATCH 207/210] =?UTF-8?q?feat(opt):=20=E8=B7=B3=E8=BF=87=20pivot?= =?UTF-8?q?=E5=B7=A6=E5=8F=B3=E7=9B=B8=E7=AD=89=E7=9A=84=E5=85=83=E7=B4=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- codetop/912sortArray.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/codetop/912sortArray.js b/codetop/912sortArray.js index 294b414e..581cd736 100644 --- a/codetop/912sortArray.js +++ b/codetop/912sortArray.js @@ -3,11 +3,22 @@ * 912. 排序数组 | medium */ -var sortArray = function(nums, left = 0, right = nums.length - 1) { - if (left >= right) return nums; - const pivotIndex = partition(nums, left, right); - sortArray(nums, left, pivotIndex - 1); - sortArray(nums, pivotIndex + 1, right); +function sortArray(nums) { + quickSort(nums, 0, nums.length - 1); + return nums; +} + +function quickSort(nums, lo, hi) { + if (lo >= hi) return; + + const pivotIndex = partition(nums, lo, hi); + // 优化:跳过与 pivot 相等的元素 + let nextHi = pivotIndex - 1, nextLo = pivotIndex + 1; + while (nextHi > lo && nums[nextHi] === nums[pivotIndex]) --nextHi; + while (nextLo < hi && nums[nextLo] === nums[pivotIndex]) ++nextLo; + + quickSort(nums, lo, nextHi); + quickSort(nums, nextLo, hi); return nums; }; From db3f4d2b34f750bee6e736d7d91f83a318458d97 Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 15 Jun 2025 21:50:19 +0800 Subject: [PATCH 208/210] =?UTF-8?q?style:=20=E7=BB=9F=E4=B8=80=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=A0=BC=E5=BC=8F=E5=B9=B6=E4=BF=AE=E5=A4=8D=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复多个文件中的注释格式和代码格式问题 优化快速排序算法中选择枢轴的逻辑 添加数字转中文的功能实现 --- Week_04/122maxProfitII.js | 4 +-- Week_06/322coinChange.js | 4 +-- Week_08/051solveNQueens.js | 3 +- Week_09/072minDistance.js | 2 +- Week_09/sort-quick.js | 19 +++++++---- interview/moe/3_gpt4.js | 65 ++++++++++++++++++++++++++++++++++++++ interview/moe/4_gtp4.js | 42 ++++++++++++++++++++++++ 7 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 interview/moe/3_gpt4.js create mode 100644 interview/moe/4_gtp4.js diff --git a/Week_04/122maxProfitII.js b/Week_04/122maxProfitII.js index 31190881..37549852 100644 --- a/Week_04/122maxProfitII.js +++ b/Week_04/122maxProfitII.js @@ -1,8 +1,8 @@ /** * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ - * + * * 122. 买卖股票的最佳时机 II - * + * * 买入卖出无限制,可以用贪心法 */ diff --git a/Week_06/322coinChange.js b/Week_06/322coinChange.js index ab4ffc5e..9dd500bf 100644 --- a/Week_06/322coinChange.js +++ b/Week_06/322coinChange.js @@ -1,10 +1,10 @@ /** * https://leetcode-cn.com/problems/coin-change/ * 322. 零钱兑换 | medium - * + * * f(amount) = min((f(amount - coin) + 1) for coin in coins) * O(mn) O(n) - * + * * 11 -> [1, 2, 5] * amount 0 1 2 3 4 5 6 7 8 9 10 11 * 0 1 1 2 2 1 2 2 3 3 2 2 diff --git a/Week_08/051solveNQueens.js b/Week_08/051solveNQueens.js index e2374bf7..96999bb2 100644 --- a/Week_08/051solveNQueens.js +++ b/Week_08/051solveNQueens.js @@ -1,11 +1,10 @@ /** * https://leetcode-cn.com/problems/n-queens/ * 51. N 皇后 | hard - * + * */ function buildResult (res, n) { - const m = new Map() const graphes = [] res.forEach(state => { const graph = [] diff --git a/Week_09/072minDistance.js b/Week_09/072minDistance.js index 35d1daf2..eabba773 100644 --- a/Week_09/072minDistance.js +++ b/Week_09/072minDistance.js @@ -8,7 +8,7 @@ if (w1,w2末尾字符相同) ---> f(i, j) = f(i-1, j-1) -else (w1,w2末尾字符相同) +else ---> f(i, j) = min( f(i-1, j-1) + 1, // 修改w1,把最后一个x修改为y,然后相同末尾可以去掉 f(i-1, j) + 1, // 删除w1末尾字符 diff --git a/Week_09/sort-quick.js b/Week_09/sort-quick.js index fef04d87..b327da24 100644 --- a/Week_09/sort-quick.js +++ b/Week_09/sort-quick.js @@ -7,7 +7,12 @@ function quickSort(arr, left = 0, right = arr.length - 1) { } function partition(arr, left, right) { - const pivot = arr[left] +// const pivot = arr[left] + +const mid = left + ((right - left) >> 1); +const pivot = arr[mid]; +arr[mid] = arr[left]; +// arr[left] = pivot; while (left < right) { while (left < right && arr[right] >= pivot) --right if (left < right) arr[left] = arr[right] @@ -23,16 +28,16 @@ const arr1 = [5,2,3,1] quickSort(arr1) console.log(arr1) -// const arr2 = [5,1,1,2,0,0] -// quickSort(arr2) -// console.log(arr2) +const arr2 = [5,1,1,2,0,0] +quickSort(arr2) +console.log(arr2) // var quickSort = function(nums) { // function quickSortHelper(nums, start, end) { // if (start >= end) return nums - + // var pivotValue = nums[start] // var smaller = start // for (var i = start + 1; i <= end; i++) { @@ -47,11 +52,11 @@ console.log(arr1) // var smallerCache = nums[smaller] // nums[smaller] = nums[start] // nums[start] = smallerCache - + // quickSortHelper(nums, start, smaller - 1) // quickSortHelper(nums, smaller + 1, end) // return nums // } - + // return quickSortHelper(nums, 0, nums.length - 1) // }; diff --git a/interview/moe/3_gpt4.js b/interview/moe/3_gpt4.js new file mode 100644 index 00000000..02a68768 --- /dev/null +++ b/interview/moe/3_gpt4.js @@ -0,0 +1,65 @@ +function convertToChineseNumeral(num) { + const numStr = num.toString(); + const chineseNumerals = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']; + const units = ['', '十', '百', '千']; + const bigUnits = ['', '万', '亿']; + const extraBigUnit = '万亿'; + + let result = ''; + let zeroFlag = false; // 标记连续的零 + let part = ''; // 每四位的读法 + let sectionCount = Math.ceil(numStr.length / 4); // 计算总共需要多少组(每组四位) + + // 处理每四位数为一组,从高位到低位 + for (let i = 0, start = 0; i < sectionCount; i++) { + let end = numStr.length - i * 4; + start = Math.max(end - 4, 0); + let currentSection = numStr.substring(start, end); + part = ''; + + for (let j = 0; j < currentSection.length; j++) { + const digit = currentSection[j]; + const numeral = chineseNumerals[parseInt(digit)]; + if (digit !== '0') { + if (zeroFlag) { + part += '零'; + zeroFlag = false; + } + part += numeral + units[currentSection.length - 1 - j]; + } else if (part.length !== 0) { + zeroFlag = true; + } + } + + if (part) { + // 添加大单位 + if (sectionCount > 2 && i === sectionCount - 2) { + // 对于万亿级别的数字,第一次使用“万亿”,之后使用“万” + part += (sectionCount === 3 && i === 0) ? extraBigUnit : bigUnits[1]; + } else if (i === sectionCount - 3) { + part += bigUnits[2]; + } + } else if (zeroFlag && result.length !== 0) { + part = '零'; + } + + result = part + result; + } + + // 处理一十开头的情况 + if (result.startsWith('一十')) { + result = result.substring(1); + } + + return result; +} + + +// 使用例子 +console.log(convertToChineseNumeral(10_0000_0000_0000)); // 十万亿 +console.log(convertToChineseNumeral(1234)); // 一千二百三十四 +console.log(convertToChineseNumeral(5678)); // 五千六百七十八 +console.log(convertToChineseNumeral(1234_5678)); // 一千二百三十四万五千六百七十八 +console.log(convertToChineseNumeral(1234_5678_9098_7654)); // 一千二百三十四万五千六百七十八亿九千零九十八万七千六百五十四 +console.log(convertToChineseNumeral(1200_0000_0000_0200)); // 一千二百万亿零二百 +// console.log(convertToChineseNumeral(1200_0000_0000_0200)); // 一千二百 万 亿 零 二百 diff --git a/interview/moe/4_gtp4.js b/interview/moe/4_gtp4.js new file mode 100644 index 00000000..11891ca0 --- /dev/null +++ b/interview/moe/4_gtp4.js @@ -0,0 +1,42 @@ +function numToChinese(num) { + if (num === 0) return '零'; + + const strNum = String(num); + const len = strNum.length; + + if (len > 16) return '数字太大'; + + const cnNums = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']; + const cnUnits = ['', '十', '百', '千']; + const cnBigUnits = ['', '万', '亿', '万亿']; + const result = []; + + let zeroCount = 0; + + for (let i = 0; i < len; i++) { + const digit = strNum[len - 1 - i]; + const cnNum = cnNums[parseInt(digit)]; + const unitPos = i % 4; + const bigUnitPos = Math.floor(i / 4); + + if (digit === '0') { + zeroCount++; + if (unitPos === 0 && zeroCount < 4) { + result.unshift(cnBigUnits[bigUnitPos]); + } + } else { + zeroCount = 0; + result.unshift(cnNum + cnUnits[unitPos] + (unitPos === 0 ? cnBigUnits[bigUnitPos] : '')); + } + } + + return result.join('').replace(/零+/g, '零').replace(/零万/g, '万').replace(/零亿/g, '亿').replace(/亿万/g, '亿'); +} + +// 测试您提供的例子 +console.log(numToChinese(10000000000000)); // 十万亿 +console.log(numToChinese(1234)); // 一千二百三十四 +console.log(numToChinese(5678)); // 五千六百七十八 +console.log(numToChinese(12345678)); // 一千二百三十四万五千六百七十八 +console.log(numToChinese(1234567890987654)); // 一千二百三十四万五千六百七十八亿九千零九十八万七千六百五十四 +console.log(numToChinese(1200000000000200)); // 一千二百万亿零二百 From 2ee40e591a18c1bcd3abb7788af4975d98645a7b Mon Sep 17 00:00:00 2001 From: Si3ver Date: Sun, 15 Jun 2025 21:52:37 +0800 Subject: [PATCH 209/210] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=A4=9A?= =?UTF-8?q?=E4=B8=AA=E7=AE=97=E6=B3=95=E7=BB=83=E4=B9=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=8F=8A=E8=A7=A3=E7=AD=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加DFS、贪心、递归、二分查找、位运算等算法练习文件 包含数字权值、字符串处理、树操作、动态规划等题目解答 更新README记录已完成和未完成的题目状态 --- ...350\267\263\345\217\260\351\230\266_dp.js" | 14 +++++ ...17\347\272\242\346\213\274\345\233\276.js" | 1 + ...60\344\275\215\346\223\215\344\275\234.js" | 1 + .../1_dfs/_19_\347\233\270\351\201\207.js" | 3 + ...47\220\203\346\212\225\347\233\222_set.js" | 30 ++++++++++ ...211\233\347\211\233\347\232\204Ackmann.js" | 22 ++++++++ ...27\351\200\206\345\272\217\345\257\271.js" | 0 ...16\347\232\204\345\275\251\345\270\246.js" | 0 ...14\345\210\206\346\237\245\346\211\276.js" | 56 +++++++++++++++++++ ...71\347\247\260\344\271\213\347\276\216.js" | 32 +++++++++++ ...11\346\225\260\344\271\230\347\247\257.js" | 2 + ...47\345\234\243\350\257\236\346\240\221.js" | 0 ...73\346\225\260\345\215\232\345\274\210.js" | 0 ...07\345\201\266\346\212\275\345\217\226.js" | 16 ++++++ ...64\346\225\260\345\210\207\345\211\262.js" | 14 +++++ ...16\350\265\260\345\205\254\350\267\257.js" | 22 ++++++++ ...22\345\210\227\350\257\242\351\227\256.js" | 7 +++ ...30\346\230\257\351\232\276\350\277\207.js" | 12 ++++ ...61\347\210\266\350\212\202\347\202\271.js" | 15 +++++ ...4\346\240\221_\351\201\215\345\216\206.js" | 3 + ...20\346\240\221\346\223\215\344\275\234.js" | 1 + ...1_\344\272\214\345\217\211\346\240\221.js" | 5 ++ ...1_\350\277\236\351\200\232\345\233\276.js" | 1 + ...37\350\256\241\344\275\231\346\225\260.js" | 54 ++++++++++++++++++ ...347\272\242\347\232\20401\344\270\262_.js" | 15 +++++ ...\344\275\215\345\207\217\346\263\225_0.js" | 38 +++++++++++++ .../*32_\351\255\224\345\241\224.js" | 2 + ...40\346\225\260\345\210\206\350\247\243.js" | 44 +++++++++++++++ ...6\346\236\234_\350\264\252\345\277\203.js" | 15 +++++ ...60\347\273\204\345\210\240\351\231\244.js" | 7 +++ ...\217\267\346\223\215\344\275\234_stack.js" | 2 + ...60\345\255\227\345\217\230\346\215\242.js" | 0 ...73\345\212\250\345\256\211\346\216\222.js" | 1 + ...04\344\270\216\350\277\220\347\256\227.js" | 1 + ...33\345\210\266\350\275\254\346\215\242.js" | 1 + ...60\345\255\227\346\270\270\346\210\217.js" | 1 + ...26\345\222\214\344\271\213\345\222\214.js" | 1 + ...347\210\261\347\247\221\345\255\2461.0.js" | 1 + ...14\345\244\247\345\257\214\347\277\201.js" | 1 + ...75\347\232\204\351\207\221\345\270\201.js" | 1 + ...4v\344\270\211\345\205\203\347\273\204.js" | 1 + ...33\344\270\252\351\200\211\351\241\271.js" | 1 + ...60\345\255\227\350\256\241\346\225\260.js" | 1 + ...66\345\234\250\344\270\200\350\265\267.js" | 1 + ...04\345\255\227\347\254\246\344\270\262.js" | 22 ++++++++ ...21\345\212\250\347\252\227\345\217\243.js" | 2 + ...7_\345\255\220\345\272\217\345\210\227.js" | 0 ...347\272\242\347\232\204red\344\270\262.js" | 1 + ...345\245\275red\344\270\262\344\270\200.js" | 1 + ...04\345\255\227\346\257\215\344\270\262.js" | 1 + nc_practice/README.md | 13 +++++ 51 files changed, 486 insertions(+) create mode 100644 "nc_practice/1_dfs/38_\350\267\263\345\217\260\351\230\266_dp.js" create mode 100644 "nc_practice/1_dfs/_10_\345\260\217\347\272\242\346\213\274\345\233\276.js" create mode 100644 "nc_practice/1_dfs/_13_\345\260\217\347\272\242\347\232\204\346\225\260\344\275\215\346\223\215\344\275\234.js" create mode 100644 "nc_practice/1_dfs/_19_\347\233\270\351\201\207.js" create mode 100644 "nc_practice/2_\351\200\222\345\275\222/29_\345\260\217\347\220\203\346\212\225\347\233\222_set.js" create mode 100644 "nc_practice/2_\351\200\222\345\275\222/37_\347\211\233\347\211\233\347\232\204Ackmann.js" create mode 100644 "nc_practice/2_\351\200\222\345\275\222/_02_\345\260\217\347\272\242\347\232\204\345\255\220\345\272\217\345\210\227\351\200\206\345\272\217\345\257\271.js" create mode 100644 "nc_practice/2_\351\200\222\345\275\222/_03_\345\260\217\347\276\216\347\232\204\345\275\251\345\270\246.js" create mode 100644 "nc_practice/2_\351\200\222\345\275\222/_40_\345\260\217\347\272\242\347\232\204\346\225\260\347\273\204_\344\272\214\345\210\206\346\237\245\346\211\276.js" create mode 100644 "nc_practice/3_\345\244\215\346\235\202\345\272\246/45_\345\257\271\347\247\260\344\271\213\347\276\216.js" create mode 100644 "nc_practice/3_\345\244\215\346\235\202\345\272\246/_25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257.js" create mode 100644 "nc_practice/3_\345\244\215\346\235\202\345\272\246/_39_\350\266\205\347\272\247\345\234\243\350\257\236\346\240\221.js" create mode 100644 "nc_practice/3_\345\244\215\346\235\202\345\272\246/_41_\346\267\273\346\225\260\345\215\232\345\274\210.js" create mode 100644 "nc_practice/4_\346\236\232\344\270\276/11_\345\260\217\347\272\242\347\232\204\345\245\207\345\201\266\346\212\275\345\217\226.js" create mode 100644 "nc_practice/4_\346\236\232\344\270\276/12_\346\270\270\346\270\270\347\232\204\346\225\264\346\225\260\345\210\207\345\211\262.js" create mode 100644 "nc_practice/4_\346\236\232\344\270\276/14_\345\260\217\347\276\216\350\265\260\345\205\254\350\267\257.js" create mode 100644 "nc_practice/4_\346\236\232\344\270\276/15_\345\260\217\347\276\216\347\232\204\346\216\222\345\210\227\350\257\242\351\227\256.js" create mode 100644 "nc_practice/4_\346\236\232\344\270\276/43_\345\274\200\345\277\203\350\277\230\346\230\257\351\232\276\350\277\207.js" create mode 100644 "nc_practice/5_\346\240\221/33_\346\240\221\344\270\212\346\234\200\347\237\255\350\267\257_\345\205\254\345\205\261\347\210\266\350\212\202\347\202\271.js" create mode 100644 "nc_practice/5_\346\240\221/_23_Monica\347\232\204\346\240\221_\351\201\215\345\216\206.js" create mode 100644 "nc_practice/5_\346\240\221/_26_\345\260\217\347\272\242\347\232\204\345\255\220\346\240\221\346\223\215\344\275\234.js" create mode 100644 "nc_practice/5_\346\240\221/_31_\344\272\214\345\217\211\346\240\221.js" create mode 100644 "nc_practice/5_\346\240\221/_35_\346\270\270\346\270\270\347\232\204\344\270\211\350\211\262\346\240\221_\350\277\236\351\200\232\345\233\276.js" create mode 100644 "nc_practice/6_\350\264\252\345\277\203/*06_\345\260\217\347\272\242\347\232\204\346\225\260\345\255\227\345\210\240\351\231\244_\347\273\237\350\256\241\344\275\231\346\225\260.js" create mode 100644 "nc_practice/6_\350\264\252\345\277\203/*08_\345\260\217\347\272\242\347\232\20401\344\270\262_.js" create mode 100644 "nc_practice/6_\350\264\252\345\277\203/*16_\345\207\275\346\225\260_\345\200\237\344\275\215\345\207\217\346\263\225_0.js" create mode 100644 "nc_practice/6_\350\264\252\345\277\203/*32_\351\255\224\345\241\224.js" create mode 100644 "nc_practice/6_\350\264\252\345\277\203/01_\345\260\217\350\213\257\347\232\204\346\225\260\345\255\227\346\235\203\345\200\274_\350\264\250\345\233\240\346\225\260\345\210\206\350\247\243.js" create mode 100644 "nc_practice/6_\350\264\252\345\277\203/42_\345\220\203\347\263\226\346\236\234_\350\264\252\345\277\203.js" create mode 100644 "nc_practice/6_\350\264\252\345\277\203/_05_\345\260\217\347\276\216\347\232\204\346\225\260\347\273\204\345\210\240\351\231\244.js" create mode 100644 "nc_practice/6_\350\264\252\345\277\203/_24_\345\260\217\346\254\247\347\232\204\346\213\254\345\217\267\346\223\215\344\275\234_stack.js" create mode 100644 "nc_practice/6_\350\264\252\345\277\203/_30_\346\225\260\345\255\227\345\217\230\346\215\242.js" create mode 100644 "nc_practice/6_\350\264\252\345\277\203/_36_\346\264\273\345\212\250\345\256\211\346\216\222.js" create mode 100644 "nc_practice/7_\344\275\215\350\277\220\347\256\227/_21_\345\260\217\347\272\242\347\232\204\344\270\216\350\277\220\347\256\227.js" create mode 100644 "nc_practice/7_\344\275\215\350\277\220\347\256\227/_28_\350\277\233\345\210\266\350\275\254\346\215\242.js" create mode 100644 "nc_practice/7_\344\275\215\350\277\220\347\256\227/_44_\346\225\260\345\255\227\346\270\270\346\210\217.js" create mode 100644 "nc_practice/7_\344\275\215\350\277\220\347\256\227/_46_\345\274\202\346\210\226\345\222\214\344\271\213\345\222\214.js" create mode 100644 "nc_practice/7_\344\275\215\350\277\220\347\256\227/_50_dd\347\210\261\347\247\221\345\255\2461.0.js" create mode 100644 "nc_practice/8_\347\272\277\346\200\247 dp/_04_\345\260\217\347\276\216\345\222\214\345\244\247\345\257\214\347\277\201.js" create mode 100644 "nc_practice/8_\347\272\277\346\200\247 dp/_18_\346\225\243\350\220\275\347\232\204\351\207\221\345\270\201.js" create mode 100644 "nc_practice/8_\347\272\277\346\200\247 dp/_22_\345\260\217\347\272\242\347\232\204v\344\270\211\345\205\203\347\273\204.js" create mode 100644 "nc_practice/8_\347\272\277\346\200\247 dp/_47_\345\233\233\344\270\252\351\200\211\351\241\271.js" create mode 100644 "nc_practice/8_\347\272\277\346\200\247 dp/_48_COUNT\346\225\260\345\255\227\350\256\241\346\225\260.js" create mode 100644 "nc_practice/8_\347\272\277\346\200\247 dp/_49_\345\222\214\351\233\266\345\234\250\344\270\200\350\265\267.js" create mode 100644 "nc_practice/9_\345\255\227\347\254\246\344\270\262/07_\345\260\217\347\272\242\347\232\204\345\255\227\347\254\246\344\270\262.js" create mode 100644 "nc_practice/9_\345\255\227\347\254\246\344\270\262/_09_\345\260\217\347\272\242\347\232\204\347\210\206\347\202\270\344\270\262\344\272\214_\346\273\221\345\212\250\347\252\227\345\217\243.js" create mode 100644 "nc_practice/9_\345\255\227\347\254\246\344\270\262/_17_\345\255\220\345\272\217\345\210\227.js" create mode 100644 "nc_practice/9_\345\255\227\347\254\246\344\270\262/_20_\345\260\217\347\272\242\347\232\204red\344\270\262.js" create mode 100644 "nc_practice/9_\345\255\227\347\254\246\344\270\262/_27_\345\260\217\347\272\242\347\232\204\345\245\275red\344\270\262\344\270\200.js" create mode 100644 "nc_practice/9_\345\255\227\347\254\246\344\270\262/_34_\346\270\270\346\270\270\347\232\204\345\255\227\346\257\215\344\270\262.js" create mode 100644 nc_practice/README.md diff --git "a/nc_practice/1_dfs/38_\350\267\263\345\217\260\351\230\266_dp.js" "b/nc_practice/1_dfs/38_\350\267\263\345\217\260\351\230\266_dp.js" new file mode 100644 index 00000000..deb63e4c --- /dev/null +++ "b/nc_practice/1_dfs/38_\350\267\263\345\217\260\351\230\266_dp.js" @@ -0,0 +1,14 @@ +/** + * @param {number} n 台阶数量 + * @return {number} 跳法数量 + */ +function jumpFloor(n) { + if (n <= 3) return n + let pre = 2, cur = 3 + for (let i = 4; i <= n; i++) { + let temp = cur + cur = pre + cur + pre = temp + } + return cur +} diff --git "a/nc_practice/1_dfs/_10_\345\260\217\347\272\242\346\213\274\345\233\276.js" "b/nc_practice/1_dfs/_10_\345\260\217\347\272\242\346\213\274\345\233\276.js" new file mode 100644 index 00000000..99b6d230 --- /dev/null +++ "b/nc_practice/1_dfs/_10_\345\260\217\347\272\242\346\213\274\345\233\276.js" @@ -0,0 +1 @@ +// 小红拼图 diff --git "a/nc_practice/1_dfs/_13_\345\260\217\347\272\242\347\232\204\346\225\260\344\275\215\346\223\215\344\275\234.js" "b/nc_practice/1_dfs/_13_\345\260\217\347\272\242\347\232\204\346\225\260\344\275\215\346\223\215\344\275\234.js" new file mode 100644 index 00000000..fc4136ca --- /dev/null +++ "b/nc_practice/1_dfs/_13_\345\260\217\347\272\242\347\232\204\346\225\260\344\275\215\346\223\215\344\275\234.js" @@ -0,0 +1 @@ +// 小红的数位操作 \ No newline at end of file diff --git "a/nc_practice/1_dfs/_19_\347\233\270\351\201\207.js" "b/nc_practice/1_dfs/_19_\347\233\270\351\201\207.js" new file mode 100644 index 00000000..d3bdd730 --- /dev/null +++ "b/nc_practice/1_dfs/_19_\347\233\270\351\201\207.js" @@ -0,0 +1,3 @@ +// 相遇问题 +// + diff --git "a/nc_practice/2_\351\200\222\345\275\222/29_\345\260\217\347\220\203\346\212\225\347\233\222_set.js" "b/nc_practice/2_\351\200\222\345\275\222/29_\345\260\217\347\220\203\346\212\225\347\233\222_set.js" new file mode 100644 index 00000000..833b3196 --- /dev/null +++ "b/nc_practice/2_\351\200\222\345\275\222/29_\345\260\217\347\220\203\346\212\225\347\233\222_set.js" @@ -0,0 +1,30 @@ +// 小球投盒 +// 思路:集合删除法,记录空盒序号,每次操作,删除非空盒子。 +// 备注:集合遍历可以用 forEach +// 时间复杂度:O(n) + +// 使用集合 set 存储空盒序号。 +// 1. 如果操作类型为 1,从 set 中删除当前盒子序号; +// 2. 如果操作类型为 2,从 set 中删除其他序号; +function solve(n, lines) { + const emptyBox = new Set(new Array(n).fill(0).map((_, idx) => String(idx + 1))); + for (let i = 1; i < lines.length; ++i) { // 从 1 开始为每一步操作 + const [opType, boxId] = lines[i].split(" "); + if (opType === "1") { + emptyBox.delete(boxId); + } else { + emptyBox.forEach(id => { + if (id !== boxId) { + emptyBox.delete(id); + } + }) + } + if (emptyBox.size === 0) { + return i; + } + } + return -1; +} + +console.log(solve(3, ['', "1 1", "1 2", "1 3"])) +console.log(solve(3, ['', "1 1", "2 2", "1 3", "1 2"])) diff --git "a/nc_practice/2_\351\200\222\345\275\222/37_\347\211\233\347\211\233\347\232\204Ackmann.js" "b/nc_practice/2_\351\200\222\345\275\222/37_\347\211\233\347\211\233\347\232\204Ackmann.js" new file mode 100644 index 00000000..2562d925 --- /dev/null +++ "b/nc_practice/2_\351\200\222\345\275\222/37_\347\211\233\347\211\233\347\232\204Ackmann.js" @@ -0,0 +1,22 @@ +// https://www.nowcoder.com/practice/3a7a4c26420c4358a1a5cda3da2fa1c8 + +// 递归 +// 解法一:直接按公式递归(自顶向下) +function ack(m, n) { + if (m === 0) { + return n + 1; + } + if (m > 0 && n === 0) { + return ack(m - 1, 1); + } + if (m > 0 && n > 0) { + return ack(m - 1, ack(m, n - 1)); + } + return -1; +} + +// 解法二:动态规划递推(自底向上) +// todo + +console.log(ack(3, 4)); +console.log(ack(0, 10)); diff --git "a/nc_practice/2_\351\200\222\345\275\222/_02_\345\260\217\347\272\242\347\232\204\345\255\220\345\272\217\345\210\227\351\200\206\345\272\217\345\257\271.js" "b/nc_practice/2_\351\200\222\345\275\222/_02_\345\260\217\347\272\242\347\232\204\345\255\220\345\272\217\345\210\227\351\200\206\345\272\217\345\257\271.js" new file mode 100644 index 00000000..e69de29b diff --git "a/nc_practice/2_\351\200\222\345\275\222/_03_\345\260\217\347\276\216\347\232\204\345\275\251\345\270\246.js" "b/nc_practice/2_\351\200\222\345\275\222/_03_\345\260\217\347\276\216\347\232\204\345\275\251\345\270\246.js" new file mode 100644 index 00000000..e69de29b diff --git "a/nc_practice/2_\351\200\222\345\275\222/_40_\345\260\217\347\272\242\347\232\204\346\225\260\347\273\204_\344\272\214\345\210\206\346\237\245\346\211\276.js" "b/nc_practice/2_\351\200\222\345\275\222/_40_\345\260\217\347\272\242\347\232\204\346\225\260\347\273\204_\344\272\214\345\210\206\346\237\245\346\211\276.js" new file mode 100644 index 00000000..aa78611d --- /dev/null +++ "b/nc_practice/2_\351\200\222\345\275\222/_40_\345\260\217\347\272\242\347\232\204\346\225\260\347\273\204_\344\272\214\345\210\206\346\237\245\346\211\276.js" @@ -0,0 +1,56 @@ +// 小红的数组 +// https://ac.nowcoder.com/acm/contest/11218/D + +/** + * 思路:(二分查找) + * 1. 先对数组进行排序 + * 2. + */ +function lowerBound(arr, target, left, right) { + while (left < right) { + const mid = (left + right) >> 1; + if (arr[mid] >= target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; +} + +function upperBound(arr, target, left, right) { + while (left < right) { + const mid = (left + right) >> 1; + if (arr[mid] > target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; +} + +function solve(arr, k) { + arr.sort((a, b) => a - b); // O(nlogn) + let s1 = 0, s2 = 0, s3 = 0; + for (let i = 0; i < arr.length; i++) { + const target = k / arr[i]; + const left = i + 1; + const right = arr.length; + + const l = lowerBound(arr, target, left, right); + const r = upperBound(arr, target, left, right); + + if (l === right) { + s3 += right - i - 1 + } else { + s1 += right - r; + s2 += r - l; + s3 += l - left; + } + } + return [s1, s2, s3] +} + +console.log(solve([1, 2, 3, 4], 7)) +console.log(solve([3, 3, 3, 3, 3], 9)) diff --git "a/nc_practice/3_\345\244\215\346\235\202\345\272\246/45_\345\257\271\347\247\260\344\271\213\347\276\216.js" "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/45_\345\257\271\347\247\260\344\271\213\347\276\216.js" new file mode 100644 index 00000000..2375a163 --- /dev/null +++ "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/45_\345\257\271\347\247\260\344\271\213\347\276\216.js" @@ -0,0 +1,32 @@ +// 对称之美 +// 思路:双指针 + hash +// https://ac.nowcoder.com/acm/contest/10746/H +// 类似题,非对称之美(最长回文子串):https://ac.nowcoder.com/acm/problem/214851 + +// 思路:核心在于判断两个字符串是否有同一个 char。找相同 char 可以用 set 降低复杂度 +function hasSameChar(str1, str2) { + const set = new Set(str1.split('')) + for (const ch of str2) { + if (set.has(ch)) { + return true; + } + } + return false; +} + +function solve(strArr) { + const n = strArr.length; + const times = n >> 1; + let ans = true; + for (let i = 0; i < times; ++i) { + if (!hasSameChar(strArr[i], strArr[n - i - 1])) { + ans = false; + break; + } + } + return ans; +} + +console.log(solve(['a'])) // true +console.log(solve(['a', 'b', 'c'])) // false +console.log(solve(['a', 'b', 'ac'])) // true diff --git "a/nc_practice/3_\345\244\215\346\235\202\345\272\246/_25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257.js" "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/_25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257.js" new file mode 100644 index 00000000..0c7ba91d --- /dev/null +++ "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/_25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257.js" @@ -0,0 +1,2 @@ +// 小欧的选数乘积 + diff --git "a/nc_practice/3_\345\244\215\346\235\202\345\272\246/_39_\350\266\205\347\272\247\345\234\243\350\257\236\346\240\221.js" "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/_39_\350\266\205\347\272\247\345\234\243\350\257\236\346\240\221.js" new file mode 100644 index 00000000..e69de29b diff --git "a/nc_practice/3_\345\244\215\346\235\202\345\272\246/_41_\346\267\273\346\225\260\345\215\232\345\274\210.js" "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/_41_\346\267\273\346\225\260\345\215\232\345\274\210.js" new file mode 100644 index 00000000..e69de29b diff --git "a/nc_practice/4_\346\236\232\344\270\276/11_\345\260\217\347\272\242\347\232\204\345\245\207\345\201\266\346\212\275\345\217\226.js" "b/nc_practice/4_\346\236\232\344\270\276/11_\345\260\217\347\272\242\347\232\204\345\245\207\345\201\266\346\212\275\345\217\226.js" new file mode 100644 index 00000000..9fd99257 --- /dev/null +++ "b/nc_practice/4_\346\236\232\344\270\276/11_\345\260\217\347\272\242\347\232\204\345\245\207\345\201\266\346\212\275\345\217\226.js" @@ -0,0 +1,16 @@ + +// 小红的奇偶抽取 +function solve(numStr) { + let oddNum = 0, + evenNum = 0; + + for (let i = 0; i < numStr.length; ++i) { + const digit = numStr[i] - '0' + if (digit & 1) { + oddNum = oddNum * 10 + digit; + } else { + evenNum = evenNum * 10 + digit; + } + } + return Math.abs(oddNum - evenNum) +} diff --git "a/nc_practice/4_\346\236\232\344\270\276/12_\346\270\270\346\270\270\347\232\204\346\225\264\346\225\260\345\210\207\345\211\262.js" "b/nc_practice/4_\346\236\232\344\270\276/12_\346\270\270\346\270\270\347\232\204\346\225\264\346\225\260\345\210\207\345\211\262.js" new file mode 100644 index 00000000..7e310dcd --- /dev/null +++ "b/nc_practice/4_\346\236\232\344\270\276/12_\346\270\270\346\270\270\347\232\204\346\225\264\346\225\260\345\210\207\345\211\262.js" @@ -0,0 +1,14 @@ +// 游游的整数切割 +function solve(numStr) { + const n = numStr.length + const lastDigit = numStr[n - 1] - '0' + const isLastOdd = lastDigit & 1 + let ans = 0 + for (let i = 0; i < n - 1; ++i) { + const digit = numStr[i] - '0' + const isCurOdd = digit & 1 + if (isCurOdd && isLastOdd) ++ans + if (!isCurOdd && !isLastOdd) ++ans + } + return ans +} diff --git "a/nc_practice/4_\346\236\232\344\270\276/14_\345\260\217\347\276\216\350\265\260\345\205\254\350\267\257.js" "b/nc_practice/4_\346\236\232\344\270\276/14_\345\260\217\347\276\216\350\265\260\345\205\254\350\267\257.js" new file mode 100644 index 00000000..1b7c043a --- /dev/null +++ "b/nc_practice/4_\346\236\232\344\270\276/14_\345\260\217\347\276\216\350\265\260\345\205\254\350\267\257.js" @@ -0,0 +1,22 @@ +function solve(arr, start, end) { + let sum1 = 0, sum2 = 0 + for (let i = 0; i < arr.length; ++i) { + if (start <= i && i < end) { + sum1 += arr[i] + } else { + sum2 += arr[i] + } + } + return Math.min(sum1, sum2) +} + +void async function () { + // Write your code here + const lines = [] + while(line = await readline()){ + lines.push(line) + } + const arr = lines[1].split(' ').map(Number) + const [start, end] = lines[2].split(' ').map(str => parseInt(str) - 1).sort((x, y) => x - y) // 排序一下 + console.log(solve(arr, start, end)) +}() diff --git "a/nc_practice/4_\346\236\232\344\270\276/15_\345\260\217\347\276\216\347\232\204\346\216\222\345\210\227\350\257\242\351\227\256.js" "b/nc_practice/4_\346\236\232\344\270\276/15_\345\260\217\347\276\216\347\232\204\346\216\222\345\210\227\350\257\242\351\227\256.js" new file mode 100644 index 00000000..b0db3723 --- /dev/null +++ "b/nc_practice/4_\346\236\232\344\270\276/15_\345\260\217\347\276\216\347\232\204\346\216\222\345\210\227\350\257\242\351\227\256.js" @@ -0,0 +1,7 @@ +function isNeighbor(arr, x, y) { + for (let i = 0; i < arr.length - 1; ++i) { + if (arr[i] === x && arr[i + 1] === y) return true + if (arr[i] === y && arr[i + 1] === x) return true + } + return false; +} diff --git "a/nc_practice/4_\346\236\232\344\270\276/43_\345\274\200\345\277\203\350\277\230\346\230\257\351\232\276\350\277\207.js" "b/nc_practice/4_\346\236\232\344\270\276/43_\345\274\200\345\277\203\350\277\230\346\230\257\351\232\276\350\277\207.js" new file mode 100644 index 00000000..c2d6045a --- /dev/null +++ "b/nc_practice/4_\346\236\232\344\270\276/43_\345\274\200\345\277\203\350\277\230\346\230\257\351\232\276\350\277\207.js" @@ -0,0 +1,12 @@ +function solve(str) { + const happyCnt = str.split(':-)').length - 1 + const sadCnt = str.split(':-(').length - 1 + if (happyCnt > sadCnt) { + return 'Happy' + } else if (happyCnt < sadCnt) { + return 'Sad' + } else if (happyCnt === 0) { + return 'None' + } + return 'Just so so' +} diff --git "a/nc_practice/5_\346\240\221/33_\346\240\221\344\270\212\346\234\200\347\237\255\350\267\257_\345\205\254\345\205\261\347\210\266\350\212\202\347\202\271.js" "b/nc_practice/5_\346\240\221/33_\346\240\221\344\270\212\346\234\200\347\237\255\350\267\257_\345\205\254\345\205\261\347\210\266\350\212\202\347\202\271.js" new file mode 100644 index 00000000..829bebf8 --- /dev/null +++ "b/nc_practice/5_\346\240\221/33_\346\240\221\344\270\212\346\234\200\347\237\255\350\267\257_\345\205\254\345\205\261\347\210\266\350\212\202\347\202\271.js" @@ -0,0 +1,15 @@ +// 33. 树上最短路 + +function solve(x, y) { + let ans = 0; + while (x !== y) { + y = y >> 1 + ++ans + if (x > y) { // 交换 + const tmp = x + x = y + y = tmp + } + } + return ans; +} diff --git "a/nc_practice/5_\346\240\221/_23_Monica\347\232\204\346\240\221_\351\201\215\345\216\206.js" "b/nc_practice/5_\346\240\221/_23_Monica\347\232\204\346\240\221_\351\201\215\345\216\206.js" new file mode 100644 index 00000000..44c029f5 --- /dev/null +++ "b/nc_practice/5_\346\240\221/_23_Monica\347\232\204\346\240\221_\351\201\215\345\216\206.js" @@ -0,0 +1,3 @@ +// +// 邻接表? + diff --git "a/nc_practice/5_\346\240\221/_26_\345\260\217\347\272\242\347\232\204\345\255\220\346\240\221\346\223\215\344\275\234.js" "b/nc_practice/5_\346\240\221/_26_\345\260\217\347\272\242\347\232\204\345\255\220\346\240\221\346\223\215\344\275\234.js" new file mode 100644 index 00000000..7b23a241 --- /dev/null +++ "b/nc_practice/5_\346\240\221/_26_\345\260\217\347\272\242\347\232\204\345\255\220\346\240\221\346\223\215\344\275\234.js" @@ -0,0 +1 @@ +// 小红的子树操作 diff --git "a/nc_practice/5_\346\240\221/_31_\344\272\214\345\217\211\346\240\221.js" "b/nc_practice/5_\346\240\221/_31_\344\272\214\345\217\211\346\240\221.js" new file mode 100644 index 00000000..8e1efbb1 --- /dev/null +++ "b/nc_practice/5_\346\240\221/_31_\344\272\214\345\217\211\346\240\221.js" @@ -0,0 +1,5 @@ +// 31. 二叉树 + +function solve(m, n) { + +} diff --git "a/nc_practice/5_\346\240\221/_35_\346\270\270\346\270\270\347\232\204\344\270\211\350\211\262\346\240\221_\350\277\236\351\200\232\345\233\276.js" "b/nc_practice/5_\346\240\221/_35_\346\270\270\346\270\270\347\232\204\344\270\211\350\211\262\346\240\221_\350\277\236\351\200\232\345\233\276.js" new file mode 100644 index 00000000..7c50a2d5 --- /dev/null +++ "b/nc_practice/5_\346\240\221/_35_\346\270\270\346\270\270\347\232\204\344\270\211\350\211\262\346\240\221_\350\277\236\351\200\232\345\233\276.js" @@ -0,0 +1 @@ +// 游游的三色树 diff --git "a/nc_practice/6_\350\264\252\345\277\203/*06_\345\260\217\347\272\242\347\232\204\346\225\260\345\255\227\345\210\240\351\231\244_\347\273\237\350\256\241\344\275\231\346\225\260.js" "b/nc_practice/6_\350\264\252\345\277\203/*06_\345\260\217\347\272\242\347\232\204\346\225\260\345\255\227\345\210\240\351\231\244_\347\273\237\350\256\241\344\275\231\346\225\260.js" new file mode 100644 index 00000000..eee99795 --- /dev/null +++ "b/nc_practice/6_\350\264\252\345\277\203/*06_\345\260\217\347\272\242\347\232\204\346\225\260\345\255\227\345\210\240\351\231\244_\347\273\237\350\256\241\344\275\231\346\225\260.js" @@ -0,0 +1,54 @@ +// 小红的数字删除 + +// 思路: +// 1. 统计余数 0、1、2 的个数 cntArr 和总余数 totalRemain +// 2. 如果总余数为 0,说明随便删。但要注意前导零 +// 3. 如果总余数为 1,说明需要先删除一个余数为 1 的数字,再回到第二步 +// 4. 如果总余数为 2,说明需要先删除一个余数为 2 的数字,再回到第二步 + +function solve(numStr) { + const cntArr = [0, 0, 0] + for (let i = 0; i < numStr.length; ++i) { + const digit = numStr[i] - '0' + const remain = digit % 3 + ++cntArr[remain] + } + const totalRemain = (cntArr[1] + 2 * cntArr[2]) % 3 + let ans = 0; + if (totalRemain) { + if (cntArr[totalRemain] === 0) { // 没得删 + return 0; + } else { + ans = 1 + --cntArr[totalRemain] + // console.log(cntArr, totalRemain) + if (cntArr[totalRemain] === 0 && !['3', '6', '9'].includes(numStr[0])) { // '10000003' + for (let i = 1; i < numStr.length; ++i) { + if (numStr[i] === '0') { + --cntArr[0] + } else { + break; + } + } + } + } + } + ans += cntArr[0] + if (cntArr[1] || cntArr[2]) { + return ans + } + return ans - 1 +} + +console.log(solve('0')) // 0 +// console.log(solve('2251')) +// console.log(solve('30021')) +console.log(solve('3000000')) // 6 +console.log(solve('30000001')) // 7 +console.log(solve('10000003')) // 1 +console.log(solve('3000000103')) // 9 +console.log(solve('1000000303')) // 3 +console.log(solve('1000000')) // 0 +// console.log(solve('333')) +// console.log(solve('123')) +// console.log(solve('300')) diff --git "a/nc_practice/6_\350\264\252\345\277\203/*08_\345\260\217\347\272\242\347\232\20401\344\270\262_.js" "b/nc_practice/6_\350\264\252\345\277\203/*08_\345\260\217\347\272\242\347\232\20401\344\270\262_.js" new file mode 100644 index 00000000..cb931a0b --- /dev/null +++ "b/nc_practice/6_\350\264\252\345\277\203/*08_\345\260\217\347\272\242\347\232\20401\344\270\262_.js" @@ -0,0 +1,15 @@ +// 小红的 01 串 +// https://www.nowcoder.com/practice/09ca882b363a480aa33ab15e8cd2b039 +// https://www.nowcoder.com/practice/9b072237ebdd4dd99562f01cbf594fac + +// 不是上面这题,例题里是好串(坏串变好串) +// https://www.nowcoder.com/feed/main/detail/6aea3ae1ac0c40b483c04b14ff60bc0f?sourceSSR=search +// https://www.nowcoder.com/discuss/731944613962866688 +// 游酷盛世 3.27 笔试题 1 + +// 思路:? +function solve(str) { + let ans = 0 + + return ans +} diff --git "a/nc_practice/6_\350\264\252\345\277\203/*16_\345\207\275\346\225\260_\345\200\237\344\275\215\345\207\217\346\263\225_0.js" "b/nc_practice/6_\350\264\252\345\277\203/*16_\345\207\275\346\225\260_\345\200\237\344\275\215\345\207\217\346\263\225_0.js" new file mode 100644 index 00000000..9ec9d9ba --- /dev/null +++ "b/nc_practice/6_\350\264\252\345\277\203/*16_\345\207\275\346\225\260_\345\200\237\344\275\215\345\207\217\346\263\225_0.js" @@ -0,0 +1,38 @@ +// 函数 + +// 思路:借位减法 +function fn(numStr) { + const len = numStr.length + let ans = '', flag = 0 // 向前借位 + for (let i = len - 1; i >= 0; --i) { + const digit = numStr[i] - '0' - flag + if (digit > 3) { + flag = 0 + ans = '3'.repeat(ans.length + 1) // 遇到大哥了,需要把后面刷成 3 + } else if (digit < 1) { + flag = 1 + ans = '3' + ans // 借位后,当前位变 3 + } else { + flag = 0 + ans = `${digit}${ans}` + } + } + // console.log(flag, ans, 'x') + return flag && ans[0] === '3' ? ans.slice(1) : ans +} + +console.log(fn('')) // '' +console.log(fn('0')) // '' +console.log(fn('1')) // 1 +console.log(fn('10')) // 3 +console.log(fn('1010')) // 333 +console.log(fn('2010')) // 1333 +console.log(fn('100')) // 33 +console.log(fn('400')) // 333 +console.log(fn('125')) // 123 +console.log(fn('12517')) // 12333 +console.log(fn('100517')) // 33333 +console.log(fn('200517')) // 133333 +console.log(fn('300517')) // 133333 +console.log(fn('400517')) // 133333 +console.log(fn('999999999999999999')) // diff --git "a/nc_practice/6_\350\264\252\345\277\203/*32_\351\255\224\345\241\224.js" "b/nc_practice/6_\350\264\252\345\277\203/*32_\351\255\224\345\241\224.js" new file mode 100644 index 00000000..cb034d2a --- /dev/null +++ "b/nc_practice/6_\350\264\252\345\277\203/*32_\351\255\224\345\241\224.js" @@ -0,0 +1,2 @@ +// 魔塔 +// H A D diff --git "a/nc_practice/6_\350\264\252\345\277\203/01_\345\260\217\350\213\257\347\232\204\346\225\260\345\255\227\346\235\203\345\200\274_\350\264\250\345\233\240\346\225\260\345\210\206\350\247\243.js" "b/nc_practice/6_\350\264\252\345\277\203/01_\345\260\217\350\213\257\347\232\204\346\225\260\345\255\227\346\235\203\345\200\274_\350\264\250\345\233\240\346\225\260\345\210\206\350\247\243.js" new file mode 100644 index 00000000..2ebd905a --- /dev/null +++ "b/nc_practice/6_\350\264\252\345\277\203/01_\345\260\217\350\213\257\347\232\204\346\225\260\345\255\227\346\235\203\345\200\274_\350\264\250\345\233\240\346\225\260\345\210\206\350\247\243.js" @@ -0,0 +1,44 @@ +// 小红的数字权值 +// https://www.nowcoder.com/questionTerminal/aeacca655eec45999a6dc4d998dfd4a5?answerType=1&f=discussion + +// 思路: +// 分为不拆(pi + 1)乘积和拆(pi 求和翻倍)和两种策略。 +// 先算出所有质因数,再根据质因数的个数和指数和,判断哪种策略更优。 + +function solve(x) { + if (x === 2) return 2; + let sum = 0, // 拆 (p1+p2+p3+...)*2 + mmm = 1; // 不拆 (p1+1)*(p2+1)*... + for (let i = 2; i * i <= x; ++i) { + if (x % i === 0) { + let cnt = 0; + while (x % i === 0) { + ++cnt; + x /= i; + } + mmm *= cnt + 1; + sum += cnt; + } + } + if (x > 1) { // x 是剩余的最后质因子,可能是 1、2、3、5、7、11、13、17、19 等等 + mmm *= 2; + sum += 1; + } + // console.log(x, ':', mmm, 2 * sum); + return Math.max(mmm, 2 * sum); +} + +// 当只有 1 个质因子时,设指数为 p,不拆(1+p) <= 拆开(2p),拆开更优 +console.log(solve(2)); // = 2^1 | 不拆=1+1 = 拆=2*1 2 +console.log(solve(4)); // = 2^2 | 不拆=1+2 < 拆=2*2 4 +console.log(solve(8)); // = 2^3 | 不拆=1+3 < 拆=2*3 6 +console.log(solve(9)); // = 3^2 | 不拆=1+2 < 拆=2*2 4 +console.log(solve(16)); // = 2^4 | 不拆=1+4 < 拆=2*4 8 + +// 当有2个质因子时,设指数为 p1, p2。不拆(p1+1)*(p2+1) >= 拆2*(p1+p2),不拆更优 +console.log(solve(6)); // = 2^1 * 3^1 | 不拆=2*2 = 拆=2*2 4 +console.log(solve(10)); // = 2^1 * 5^1 | 不拆=2*2 = 拆=2*2 4 +console.log(solve(123)); // = 3^1 * 41^1 | 不拆=2*2 = 拆=2*2 4 +console.log(solve(12)); // = 2^2 * 3^1 | 不拆=3*2 > 拆=2*3 6 +console.log(solve(24)); // = 3^1 * 2^3 | 不拆=2*4 = 拆=2*4 8 +console.log(solve(36)); // = 2^2 * 3^2 | 不拆=3*3 > 拆=2*4 9 diff --git "a/nc_practice/6_\350\264\252\345\277\203/42_\345\220\203\347\263\226\346\236\234_\350\264\252\345\277\203.js" "b/nc_practice/6_\350\264\252\345\277\203/42_\345\220\203\347\263\226\346\236\234_\350\264\252\345\277\203.js" new file mode 100644 index 00000000..bb731824 --- /dev/null +++ "b/nc_practice/6_\350\264\252\345\277\203/42_\345\220\203\347\263\226\346\236\234_\350\264\252\345\277\203.js" @@ -0,0 +1,15 @@ +// 吃糖果 + +// 思路:贪心法,从最不甜的开始吃 O(nlogn) +function solve(arr, k) { + arr.sort((x, y) => x - y) + let ans = 0 + for (let i = 0; i < arr.length; ++i) { + k -= arr[i] + if (k < 0) { + break + } + ++ans + } + return ans; +} diff --git "a/nc_practice/6_\350\264\252\345\277\203/_05_\345\260\217\347\276\216\347\232\204\346\225\260\347\273\204\345\210\240\351\231\244.js" "b/nc_practice/6_\350\264\252\345\277\203/_05_\345\260\217\347\276\216\347\232\204\346\225\260\347\273\204\345\210\240\351\231\244.js" new file mode 100644 index 00000000..59bd8c4f --- /dev/null +++ "b/nc_practice/6_\350\264\252\345\277\203/_05_\345\260\217\347\276\216\347\232\204\346\225\260\347\273\204\345\210\240\351\231\244.js" @@ -0,0 +1,7 @@ +// + +function solve(arr, k, x) { + let ans; + + return ans; +} diff --git "a/nc_practice/6_\350\264\252\345\277\203/_24_\345\260\217\346\254\247\347\232\204\346\213\254\345\217\267\346\223\215\344\275\234_stack.js" "b/nc_practice/6_\350\264\252\345\277\203/_24_\345\260\217\346\254\247\347\232\204\346\213\254\345\217\267\346\223\215\344\275\234_stack.js" new file mode 100644 index 00000000..25734add --- /dev/null +++ "b/nc_practice/6_\350\264\252\345\277\203/_24_\345\260\217\346\254\247\347\232\204\346\213\254\345\217\267\346\223\215\344\275\234_stack.js" @@ -0,0 +1,2 @@ +// 小欧的括号操作 + diff --git "a/nc_practice/6_\350\264\252\345\277\203/_30_\346\225\260\345\255\227\345\217\230\346\215\242.js" "b/nc_practice/6_\350\264\252\345\277\203/_30_\346\225\260\345\255\227\345\217\230\346\215\242.js" new file mode 100644 index 00000000..e69de29b diff --git "a/nc_practice/6_\350\264\252\345\277\203/_36_\346\264\273\345\212\250\345\256\211\346\216\222.js" "b/nc_practice/6_\350\264\252\345\277\203/_36_\346\264\273\345\212\250\345\256\211\346\216\222.js" new file mode 100644 index 00000000..e7c2feab --- /dev/null +++ "b/nc_practice/6_\350\264\252\345\277\203/_36_\346\264\273\345\212\250\345\256\211\346\216\222.js" @@ -0,0 +1 @@ +// 活动安排 diff --git "a/nc_practice/7_\344\275\215\350\277\220\347\256\227/_21_\345\260\217\347\272\242\347\232\204\344\270\216\350\277\220\347\256\227.js" "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/_21_\345\260\217\347\272\242\347\232\204\344\270\216\350\277\220\347\256\227.js" new file mode 100644 index 00000000..acbe0e97 --- /dev/null +++ "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/_21_\345\260\217\347\272\242\347\232\204\344\270\216\350\277\220\347\256\227.js" @@ -0,0 +1 @@ +// 小红的与运算 \ No newline at end of file diff --git "a/nc_practice/7_\344\275\215\350\277\220\347\256\227/_28_\350\277\233\345\210\266\350\275\254\346\215\242.js" "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/_28_\350\277\233\345\210\266\350\275\254\346\215\242.js" new file mode 100644 index 00000000..25ccd0f6 --- /dev/null +++ "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/_28_\350\277\233\345\210\266\350\275\254\346\215\242.js" @@ -0,0 +1 @@ +// 进制转换 \ No newline at end of file diff --git "a/nc_practice/7_\344\275\215\350\277\220\347\256\227/_44_\346\225\260\345\255\227\346\270\270\346\210\217.js" "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/_44_\346\225\260\345\255\227\346\270\270\346\210\217.js" new file mode 100644 index 00000000..e359eacd --- /dev/null +++ "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/_44_\346\225\260\345\255\227\346\270\270\346\210\217.js" @@ -0,0 +1 @@ +// 数字游戏 \ No newline at end of file diff --git "a/nc_practice/7_\344\275\215\350\277\220\347\256\227/_46_\345\274\202\346\210\226\345\222\214\344\271\213\345\222\214.js" "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/_46_\345\274\202\346\210\226\345\222\214\344\271\213\345\222\214.js" new file mode 100644 index 00000000..a716ab19 --- /dev/null +++ "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/_46_\345\274\202\346\210\226\345\222\214\344\271\213\345\222\214.js" @@ -0,0 +1 @@ +// 异或和之和 \ No newline at end of file diff --git "a/nc_practice/7_\344\275\215\350\277\220\347\256\227/_50_dd\347\210\261\347\247\221\345\255\2461.0.js" "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/_50_dd\347\210\261\347\247\221\345\255\2461.0.js" new file mode 100644 index 00000000..068e2f3c --- /dev/null +++ "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/_50_dd\347\210\261\347\247\221\345\255\2461.0.js" @@ -0,0 +1 @@ +// dd爱科学1.0 \ No newline at end of file diff --git "a/nc_practice/8_\347\272\277\346\200\247 dp/_04_\345\260\217\347\276\216\345\222\214\345\244\247\345\257\214\347\277\201.js" "b/nc_practice/8_\347\272\277\346\200\247 dp/_04_\345\260\217\347\276\216\345\222\214\345\244\247\345\257\214\347\277\201.js" new file mode 100644 index 00000000..8777c542 --- /dev/null +++ "b/nc_practice/8_\347\272\277\346\200\247 dp/_04_\345\260\217\347\276\216\345\222\214\345\244\247\345\257\214\347\277\201.js" @@ -0,0 +1 @@ +// 小美的大富翁 \ No newline at end of file diff --git "a/nc_practice/8_\347\272\277\346\200\247 dp/_18_\346\225\243\350\220\275\347\232\204\351\207\221\345\270\201.js" "b/nc_practice/8_\347\272\277\346\200\247 dp/_18_\346\225\243\350\220\275\347\232\204\351\207\221\345\270\201.js" new file mode 100644 index 00000000..6662adf0 --- /dev/null +++ "b/nc_practice/8_\347\272\277\346\200\247 dp/_18_\346\225\243\350\220\275\347\232\204\351\207\221\345\270\201.js" @@ -0,0 +1 @@ +// 散落的金币 \ No newline at end of file diff --git "a/nc_practice/8_\347\272\277\346\200\247 dp/_22_\345\260\217\347\272\242\347\232\204v\344\270\211\345\205\203\347\273\204.js" "b/nc_practice/8_\347\272\277\346\200\247 dp/_22_\345\260\217\347\272\242\347\232\204v\344\270\211\345\205\203\347\273\204.js" new file mode 100644 index 00000000..c19526db --- /dev/null +++ "b/nc_practice/8_\347\272\277\346\200\247 dp/_22_\345\260\217\347\272\242\347\232\204v\344\270\211\345\205\203\347\273\204.js" @@ -0,0 +1 @@ +// 小红的v三元组 \ No newline at end of file diff --git "a/nc_practice/8_\347\272\277\346\200\247 dp/_47_\345\233\233\344\270\252\351\200\211\351\241\271.js" "b/nc_practice/8_\347\272\277\346\200\247 dp/_47_\345\233\233\344\270\252\351\200\211\351\241\271.js" new file mode 100644 index 00000000..b4192832 --- /dev/null +++ "b/nc_practice/8_\347\272\277\346\200\247 dp/_47_\345\233\233\344\270\252\351\200\211\351\241\271.js" @@ -0,0 +1 @@ +// 四个选项 \ No newline at end of file diff --git "a/nc_practice/8_\347\272\277\346\200\247 dp/_48_COUNT\346\225\260\345\255\227\350\256\241\346\225\260.js" "b/nc_practice/8_\347\272\277\346\200\247 dp/_48_COUNT\346\225\260\345\255\227\350\256\241\346\225\260.js" new file mode 100644 index 00000000..89e5ea93 --- /dev/null +++ "b/nc_practice/8_\347\272\277\346\200\247 dp/_48_COUNT\346\225\260\345\255\227\350\256\241\346\225\260.js" @@ -0,0 +1 @@ +// COUNT数字计数 \ No newline at end of file diff --git "a/nc_practice/8_\347\272\277\346\200\247 dp/_49_\345\222\214\351\233\266\345\234\250\344\270\200\350\265\267.js" "b/nc_practice/8_\347\272\277\346\200\247 dp/_49_\345\222\214\351\233\266\345\234\250\344\270\200\350\265\267.js" new file mode 100644 index 00000000..09959dcd --- /dev/null +++ "b/nc_practice/8_\347\272\277\346\200\247 dp/_49_\345\222\214\351\233\266\345\234\250\344\270\200\350\265\267.js" @@ -0,0 +1 @@ +// 和零在一起 \ No newline at end of file diff --git "a/nc_practice/9_\345\255\227\347\254\246\344\270\262/07_\345\260\217\347\272\242\347\232\204\345\255\227\347\254\246\344\270\262.js" "b/nc_practice/9_\345\255\227\347\254\246\344\270\262/07_\345\260\217\347\272\242\347\232\204\345\255\227\347\254\246\344\270\262.js" new file mode 100644 index 00000000..005e71b7 --- /dev/null +++ "b/nc_practice/9_\345\255\227\347\254\246\344\270\262/07_\345\260\217\347\272\242\347\232\204\345\255\227\347\254\246\344\270\262.js" @@ -0,0 +1,22 @@ +// 小红的字符串 + +// 一:暴力 O(n^2) +function solve(numStr, kStr) { + const nLen = numStr.length, + kLen = kStr.length; + if (nLen < kLen) return 0; + let ans = (2 * nLen - kLen + 2) * (kLen - 1) / 2; // 长度小于 kLen 的方案数 + for (let pos = 0; pos <= nLen - kLen; ++pos) { // 长度等于 kLen 的方案 + const curStr = numStr.slice(pos, pos + kLen); + const curNum = parseInt(curStr); + if (curNum < parseInt(kStr)) { + ++ans; + } + } + return ans; +} + +// 二:滑动窗口? + + +console.log(solve('1234', '23')) diff --git "a/nc_practice/9_\345\255\227\347\254\246\344\270\262/_09_\345\260\217\347\272\242\347\232\204\347\210\206\347\202\270\344\270\262\344\272\214_\346\273\221\345\212\250\347\252\227\345\217\243.js" "b/nc_practice/9_\345\255\227\347\254\246\344\270\262/_09_\345\260\217\347\272\242\347\232\204\347\210\206\347\202\270\344\270\262\344\272\214_\346\273\221\345\212\250\347\252\227\345\217\243.js" new file mode 100644 index 00000000..3bd08bdf --- /dev/null +++ "b/nc_practice/9_\345\255\227\347\254\246\344\270\262/_09_\345\260\217\347\272\242\347\232\204\347\210\206\347\202\270\344\270\262\344\272\214_\346\273\221\345\212\250\347\252\227\345\217\243.js" @@ -0,0 +1,2 @@ +// 小红的爆炸串二 + diff --git "a/nc_practice/9_\345\255\227\347\254\246\344\270\262/_17_\345\255\220\345\272\217\345\210\227.js" "b/nc_practice/9_\345\255\227\347\254\246\344\270\262/_17_\345\255\220\345\272\217\345\210\227.js" new file mode 100644 index 00000000..e69de29b diff --git "a/nc_practice/9_\345\255\227\347\254\246\344\270\262/_20_\345\260\217\347\272\242\347\232\204red\344\270\262.js" "b/nc_practice/9_\345\255\227\347\254\246\344\270\262/_20_\345\260\217\347\272\242\347\232\204red\344\270\262.js" new file mode 100644 index 00000000..6564ab17 --- /dev/null +++ "b/nc_practice/9_\345\255\227\347\254\246\344\270\262/_20_\345\260\217\347\272\242\347\232\204red\344\270\262.js" @@ -0,0 +1 @@ +// 小红的red串 \ No newline at end of file diff --git "a/nc_practice/9_\345\255\227\347\254\246\344\270\262/_27_\345\260\217\347\272\242\347\232\204\345\245\275red\344\270\262\344\270\200.js" "b/nc_practice/9_\345\255\227\347\254\246\344\270\262/_27_\345\260\217\347\272\242\347\232\204\345\245\275red\344\270\262\344\270\200.js" new file mode 100644 index 00000000..144c8b03 --- /dev/null +++ "b/nc_practice/9_\345\255\227\347\254\246\344\270\262/_27_\345\260\217\347\272\242\347\232\204\345\245\275red\344\270\262\344\270\200.js" @@ -0,0 +1 @@ +// 小红的好red串一 \ No newline at end of file diff --git "a/nc_practice/9_\345\255\227\347\254\246\344\270\262/_34_\346\270\270\346\270\270\347\232\204\345\255\227\346\257\215\344\270\262.js" "b/nc_practice/9_\345\255\227\347\254\246\344\270\262/_34_\346\270\270\346\270\270\347\232\204\345\255\227\346\257\215\344\270\262.js" new file mode 100644 index 00000000..b4d28155 --- /dev/null +++ "b/nc_practice/9_\345\255\227\347\254\246\344\270\262/_34_\346\270\270\346\270\270\347\232\204\345\255\227\346\257\215\344\270\262.js" @@ -0,0 +1 @@ +// 游游的字母串 \ No newline at end of file diff --git a/nc_practice/README.md b/nc_practice/README.md new file mode 100644 index 00000000..0ced706a --- /dev/null +++ b/nc_practice/README.md @@ -0,0 +1,13 @@ +# 例题 50 (4 + 5 + 4 + 5 + 5 + 10 + 5 + 6 + 6 = 50) + +## AC + +01_小苯的数字权值.js 贪心❎ 质因子分解✅ +07_小红的字符串.js 字符串❎ 暴力遍历✅ +11_小红的奇偶抽取.js 枚举✅ + +## 未 AC + +06_小红的数字删除.js 95.45% +08_小红的01串.js 27.27% 蒙的 +09_小红的爆炸串二.js 滑动窗口 有答案 From 52639a7c9687cc0e8e5afdaf89bc994809c7c19c Mon Sep 17 00:00:00 2001 From: Si3ver Date: Mon, 16 Jun 2025 00:04:27 +0800 Subject: [PATCH 210/210] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=A4=9A?= =?UTF-8?q?=E4=B8=AA=E7=AE=97=E6=B3=95=E9=A2=98=E7=9B=AE=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor: 调整二叉树函数参数顺序 fix: 删除重复文件并添加新实现 style: 格式化代码并添加注释 --- ...46\225\260\344\271\230\347\247\257_set.js" | 14 +++++ ...7\345\234\243\350\257\236\346\240\221*.js" | 58 +++++++++++++++++++ ...47\247\260\344\271\213\347\276\216_set.js" | 0 ...11\346\225\260\344\271\230\347\247\257.js" | 2 - ...47\345\234\243\350\257\236\346\240\221.js" | 0 ...1_\344\272\214\345\217\211\346\240\221.js" | 4 +- ...347\210\261\347\247\221\345\255\2461.0.js" | 33 +++++++++++ ...347\210\261\347\247\221\345\255\2461.0.js" | 1 - 8 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 "nc_practice/3_\345\244\215\346\235\202\345\272\246/25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257_set.js" create mode 100644 "nc_practice/3_\345\244\215\346\235\202\345\272\246/39_\350\266\205\347\272\247\345\234\243\350\257\236\346\240\221*.js" rename "nc_practice/3_\345\244\215\346\235\202\345\272\246/45_\345\257\271\347\247\260\344\271\213\347\276\216.js" => "nc_practice/3_\345\244\215\346\235\202\345\272\246/45_\345\257\271\347\247\260\344\271\213\347\276\216_set.js" (100%) delete mode 100644 "nc_practice/3_\345\244\215\346\235\202\345\272\246/_25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257.js" delete mode 100644 "nc_practice/3_\345\244\215\346\235\202\345\272\246/_39_\350\266\205\347\272\247\345\234\243\350\257\236\346\240\221.js" create mode 100644 "nc_practice/7_\344\275\215\350\277\220\347\256\227/50_dd\347\210\261\347\247\221\345\255\2461.0.js" delete mode 100644 "nc_practice/7_\344\275\215\350\277\220\347\256\227/_50_dd\347\210\261\347\247\221\345\255\2461.0.js" diff --git "a/nc_practice/3_\345\244\215\346\235\202\345\272\246/25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257_set.js" "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257_set.js" new file mode 100644 index 00000000..7e37e01e --- /dev/null +++ "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257_set.js" @@ -0,0 +1,14 @@ +// 小欧的选数乘积 + +function solve(x, y, arr) { + if (x >= y) return 0 + if (!arr.length) return -1 + const set = new Set(arr.map(Number).sort((x,y) => y - x)) + let ans = 0 + for (const times of set) { + x *= times + ++ans + if (x >= y) return ans + } + return -1 +} diff --git "a/nc_practice/3_\345\244\215\346\235\202\345\272\246/39_\350\266\205\347\272\247\345\234\243\350\257\236\346\240\221*.js" "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/39_\350\266\205\347\272\247\345\234\243\350\257\236\346\240\221*.js" new file mode 100644 index 00000000..ab58f1e1 --- /dev/null +++ "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/39_\350\266\205\347\272\247\345\234\243\350\257\236\346\240\221*.js" @@ -0,0 +1,58 @@ +// 超级圣诞树 +// https://www.nowcoder.com/practice/470d26c9a73e4e17be8cc45cac843423 + +function solve(n) { + let arr = Array.from({ length: 500 }, () => new Array(800).fill(0)); + // 初始化小三角形 + arr[0][2] = 1; + arr[1][1] = 1; arr[1][3] = 1; + arr[2][0] = 1; arr[2][2] = 1; arr[2][4] = 1; + + let length = 3, width = 5; + + for (let i = 2; i <= n; i++) { + // 加工左下和右下的小三角形 + for (let j = length; j < length * 2; j++) { + for (let k = 0; k < width; k++) { + arr[j][k] = arr[j - length][k]; + arr[j][k + width + 1] = arr[j - length][k]; + } + } + // 清空原三角形 + for (let j = 0; j < length; j++) { + for (let k = 0; k < width; k++) { + arr[j][k] = 0; + } + } + // 将原三角形挪到中间 + for (let j = 0; j < length; j++) { + for (let k = Math.floor((width + 1) / 2); k < width + Math.floor((width + 1) / 2); k++) { + arr[j][k] = arr[j + length][k - Math.floor((width + 1) / 2)]; + } + } + length *= 2; + width = 2 * width + 1; + } + + // 打印圣诞树 + for (let i = 0; i < length; i++) { + let line = ''; + for (let j = 0; j < width; j++) { + line += arr[i][j] === 0 ? ' ' : '*'; + } + console.log(line); + } + // 打印树干 + for (let i = 0; i < n; i++) { + let trunk = ''; + for (let j = 0; j < Math.floor(width / 2); j++) { + trunk += ' '; + } + trunk += '*'; + console.log(trunk); + } +} + +solve(1) +solve(2) +solve(3) diff --git "a/nc_practice/3_\345\244\215\346\235\202\345\272\246/45_\345\257\271\347\247\260\344\271\213\347\276\216.js" "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/45_\345\257\271\347\247\260\344\271\213\347\276\216_set.js" similarity index 100% rename from "nc_practice/3_\345\244\215\346\235\202\345\272\246/45_\345\257\271\347\247\260\344\271\213\347\276\216.js" rename to "nc_practice/3_\345\244\215\346\235\202\345\272\246/45_\345\257\271\347\247\260\344\271\213\347\276\216_set.js" diff --git "a/nc_practice/3_\345\244\215\346\235\202\345\272\246/_25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257.js" "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/_25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257.js" deleted file mode 100644 index 0c7ba91d..00000000 --- "a/nc_practice/3_\345\244\215\346\235\202\345\272\246/_25_\345\260\217\346\254\247\347\232\204\351\200\211\346\225\260\344\271\230\347\247\257.js" +++ /dev/null @@ -1,2 +0,0 @@ -// 小欧的选数乘积 - diff --git "a/nc_practice/3_\345\244\215\346\235\202\345\272\246/_39_\350\266\205\347\272\247\345\234\243\350\257\236\346\240\221.js" "b/nc_practice/3_\345\244\215\346\235\202\345\272\246/_39_\350\266\205\347\272\247\345\234\243\350\257\236\346\240\221.js" deleted file mode 100644 index e69de29b..00000000 diff --git "a/nc_practice/5_\346\240\221/_31_\344\272\214\345\217\211\346\240\221.js" "b/nc_practice/5_\346\240\221/_31_\344\272\214\345\217\211\346\240\221.js" index 8e1efbb1..20a86278 100644 --- "a/nc_practice/5_\346\240\221/_31_\344\272\214\345\217\211\346\240\221.js" +++ "b/nc_practice/5_\346\240\221/_31_\344\272\214\345\217\211\346\240\221.js" @@ -1,5 +1,7 @@ // 31. 二叉树 -function solve(m, n) { +// n: 节点个数 +// m: 最大高度 +function solve(n, m) { } diff --git "a/nc_practice/7_\344\275\215\350\277\220\347\256\227/50_dd\347\210\261\347\247\221\345\255\2461.0.js" "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/50_dd\347\210\261\347\247\221\345\255\2461.0.js" new file mode 100644 index 00000000..04dc46fe --- /dev/null +++ "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/50_dd\347\210\261\347\247\221\345\255\2461.0.js" @@ -0,0 +1,33 @@ +// dd爱科学1.0 + +function solve(s) { + // q 数组维护当前最优的非递减子序列 + const q = []; + + for (let c of s) { + // 二分查找第一个大于 c 的位置 + let left = 0, right = q.length; + while (left < right) { + const mid = Math.floor((left + right) / 2); + if (q[mid] > c) { + right = mid; + } else { + left = mid + 1; + } + } + + const idx = left; + if (idx === q.length) { + // 当前字符可以接在 q 末尾,扩展子序列 + q.push(c); + } else { + // 替换第一个大于 c 的元素,使 q 尽可能小 + q[idx] = c; + } + } + console.log(q) + // 最小修改次数 = 总长度 - 最长非递减子序列长度 + return s.length - q.length; +} + +console.log(solve('ACEBF')) diff --git "a/nc_practice/7_\344\275\215\350\277\220\347\256\227/_50_dd\347\210\261\347\247\221\345\255\2461.0.js" "b/nc_practice/7_\344\275\215\350\277\220\347\256\227/_50_dd\347\210\261\347\247\221\345\255\2461.0.js" deleted file mode 100644 index 068e2f3c..00000000 --- "a/nc_practice/7_\344\275\215\350\277\220\347\256\227/_50_dd\347\210\261\347\247\221\345\255\2461.0.js" +++ /dev/null @@ -1 +0,0 @@ -// dd爱科学1.0 \ No newline at end of file