Skip to content

Commit fe899df

Browse files
committed
update 手写
1 parent 6718bec commit fe899df

File tree

9 files changed

+505
-113
lines changed

9 files changed

+505
-113
lines changed

docs/_media/容器盛水.png

12.2 KB
Loading

docs/base/js.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ new干了什么?
1717

1818
原型链
1919

20-
原型链是主要的继承方式。
20+
原型链是主要的继承方式。原型链指的是实例在继承父类时, 实例的原型是父类的实例
21+
22+
`实例.__proto__= 原形.prototype`
2123

2224
主要思想就是原型是另一个类型的实例。也就是这个原型本身有一个内部指针(`__proto__`)指向另一个原型, 相应的另一个原型也有一个指针指向另一个构造函数。这样就在实例和原形之间构造了一条原型链
2325

docs/js/手写.md

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,9 @@ this 值
3232
谁调用的函数, this 指向就是谁
3333

3434
```javascript
35-
Function.prototype.call2 = function () {
36-
let [thisArg, ...args] = [...arguments];
37-
thisArg = Object(thisArg) || window;
38-
let fn = Symbol();
35+
Function.prototype.call2 = function (thisArg, ...args) {
3936
thisArg[fn] = this;
40-
let result = thisArg[fn](...args);
37+
const result = thisArg[fn](...args)
4138
delete thisArg[fn];
4239
return result;
4340
};
@@ -48,10 +45,7 @@ Function.prototype.call2 = function () {
4845
apply 传入的是一个数组
4946

5047
```javascript
51-
Function.prototype.apply2 = function (thisArg = window) {
52-
let [thisArg, args] = [...args];
53-
thisArg = Object(thisArg);
54-
let fn = Symbol();
48+
Function.prototype.apply2 = function (thisArg, args) {
5549
thisArg[fn] = this;
5650
let result = thisArg[fn](...args);
5751
delete thisArg.fn;
@@ -64,22 +58,6 @@ Function.prototype.apply2 = function (thisArg = window) {
6458
和 call 相比多了处理`prototype`的部分,返回的是一个函数
6559

6660
```javascript
67-
Function.prototype.bind2 = function (content) {
68-
if (typeof this !== "function") {
69-
throw Error("not a function");
70-
}
71-
let fn = this;
72-
let args = [...arguments].slice(1);
73-
74-
let resFn = function () {
75-
return fn.apply(this instanceof resFn ? this : content, args);
76-
};
77-
function tmp() {}
78-
tmp.prototype = this.prototype;
79-
resFn.prototype = new tmp();
80-
return resFn;
81-
};
82-
8361
Function.prototype.myBind = function (context, ...args) {
8462
return (...newArgs) => {
8563
return this.call(context, ...args, ...newArgs);

docs/算法/动态规划.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88

99
给定一个整数数组 `nums` ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
1010

11+
思路:
12+
13+
1. 如果累加值大于0, 则继续加
14+
2. 如果累加值小于0, 则重置值
15+
1116
```
1217
输入: [-2,1,-3,4,-1,2,1,-5,4]
1318
输出: 6
@@ -67,3 +72,37 @@ function climbStairs(n) {
6772
}
6873
```
6974

75+
4. #### [最长递增子序列](https://leetcode-cn.com/problems/longest-increasing-subsequence/)
76+
77+
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
78+
79+
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
80+
81+
```
82+
输入:nums = [10,9,2,5,3,7,101,18]
83+
输出:4
84+
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
85+
```
86+
87+
思路:
88+
89+
不会
90+
91+
```javascript
92+
function lengthOfLIS(nums) {
93+
let n = nums.length
94+
if(n == 0) return 0
95+
let dep = new Array(n).fill(1)
96+
let max = 0
97+
for(let i = 0; i < n; i++) {
98+
for(let j = 0; j < i; j++) {
99+
if(nums[j] < nums[i]) {
100+
dp[i] = Math.max(dp[i], dp[j]+1)
101+
}
102+
}
103+
max = Math.max(max. dp[i])
104+
}
105+
return max
106+
}
107+
```
108+

docs/算法/双指针.md

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,164 @@ function hasCycle(head) {
101101
}
102102
```
103103

104+
4. #### [盛最多水的容器](https://leetcode-cn.com/problems/container-with-most-water/)
105+
106+
思路:
107+
108+
乘最多的水, 也就是面积要最大, 那么就是要最长最高
109+
110+
为什么双指针的做法是正确的?
111+
112+
双指针代表了什么?
113+
114+
双指针代表的是 可以作为容器边界的所有位置的范围。在一开始,双指针指向数组的左右边界,表示 数组中所有的位置都可以作为容器的边界,因为我们还没有进行过任何尝试。在这之后,我们每次将 对应的数字较小的那个指针 往 另一个指针 的方向移动一个位置,就表示我们认为 这个指针不可能再作为容器的边界了。
115+
116+
```javascript
117+
function maxArea(height) {
118+
let left = 0
119+
let right = height - 1
120+
let ans = 0
121+
while(left < right) {
122+
let area = Math.min(height(left), height[right]) * (right - left)
123+
ans = Math.max(ans, area)
124+
125+
if(height[left] < height[right]) {
126+
left++
127+
} else {
128+
right--
129+
}
130+
}
131+
return ans
132+
}
133+
```
134+
135+
4. #### [最接近的三数之和](https://leetcode-cn.com/problems/3sum-closest/)
136+
137+
```javascript
138+
function threeSumClosest(nums, target) {
139+
nums.sort((a, b) => a - b);
140+
let res = nums[0] + nums[1] + nums[nums.length - 1];
141+
for (let i = 0; i < nums.length - 2; i++) {
142+
const n1 = nums[i];
143+
let l = i + 1;
144+
let r = nums.length - 1;
145+
while (l < r) {
146+
const n2 = nums[l];
147+
const n3 = nums[r];
148+
const sum = n1 + n2 + n3;
149+
if (sum > target) {
150+
r--;
151+
} else {
152+
l++;
153+
}
154+
if (Math.abs(sum - target) < Math.abs(res - target)) {
155+
res = sum;
156+
}
157+
}
158+
}
159+
return res;
160+
}
161+
```
162+
163+
5. #### [三数之和](https://leetcode-cn.com/problems/3sum/)
164+
165+
```javascript
166+
var threeSum = function(nums) {
167+
let ans = []
168+
let len = nums.length
169+
if(nums == null || len < 3) return ans
170+
nums.sort((a,b) => a-b)
171+
for(let i = 0; i < len; i++) {
172+
if(nums[i] > 0) break;
173+
if(i > 0 && nums[i] == nums[i-1]) continue
174+
let L = i + 1
175+
let R = len - 1
176+
while(L < R) {
177+
let sum = nums[i] + nums[L] +nums[R]
178+
if(sum == 0) {
179+
ans.push([nums[i], nums[L], nums[R]])
180+
while(L<R && nums[L] == nums[L+1]) L++
181+
while(L<R && nums[R] == nums[R-1]) R--
182+
L++
183+
R--
184+
} else if(sum > 0) {
185+
R--
186+
} else {
187+
L++
188+
}
189+
}
190+
}
191+
return ans
192+
};
193+
```
194+
195+
196+
197+
6. #### [旋转链表](https://leetcode-cn.com/problems/rotate-list/)
198+
199+
```javascript
200+
function rotateRight(head, k) {
201+
let fast = head, slow = head
202+
while(k--) {
203+
if(fast && fast.next) fast = fast.next
204+
else fast = head // 循环了一圈回来了
205+
}
206+
207+
if(slow == fast) return head
208+
while(fast.next) {
209+
slow = slow.next
210+
fast = fast.next
211+
}
212+
213+
fast.next = head
214+
head = slow.next
215+
slow.next = null
216+
return head
217+
}
218+
```
219+
220+
7. #### [最长不含重复字符的子字符串](https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/)
221+
222+
```javascript
223+
function lengthOfLongestSubstring(s) {
224+
let start = 0, end = 0
225+
let res = 0
226+
const map = new Map()
227+
while(end < s.length) {
228+
if(map.get(s[end]) >= start) {
229+
start = map.get(s[end]) + 1
230+
map.set(s[end], end)
231+
} else {
232+
map.set(s[end], end)
233+
res = Math.max(res, end - start + 1)
234+
}
235+
end++
236+
}
237+
return res
238+
}
239+
```
240+
241+
8. 容器盛水问题
242+
243+
给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个容器,请返回容器能装多少水。
244+
245+
![](../_media/容器盛水.png)
246+
247+
```javascript
248+
function maxWater(arr) {
249+
let left = 0, right = arr.length - 1
250+
let leftMax = 0, rightMax = 0
251+
let sum = 0
252+
while(left < right) {
253+
leftMax = Math.max(leftMax, arr[left])
254+
rightMax = Math.max(rightMax, arr[right])
255+
if(leftMax <= rightMax) {
256+
sum += leftMax - arr[left++]
257+
} else {
258+
sum += rightMax - arr[right--]
259+
}
260+
}
261+
return sum
262+
}
263+
```
264+

docs/算法/回朔.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
回朔法
2+
3+
采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况
4+
5+
- 找到一个可能存在的正确的答案;
6+
- 在尝试了所有可能的分步方法后宣告该问题没有答案
7+
8+
练习:
9+
110
1. #### [子集](https://leetcode-cn.com/problems/subsets/)
211

312
给你一个整数数组 `nums` ,返回该数组所有可能的子集(幂集)。解集不能包含重复的子集。
@@ -34,3 +43,102 @@ const subsets = (nums) => {
3443
};
3544
```
3645

46+
2. #### [全排列](https://leetcode-cn.com/problems/permutations/)
47+
48+
给定一个 **没有重复** 数字的序列,返回其所有可能的全排列。
49+
50+
```
51+
输入: [1,2,3]
52+
输出:
53+
[
54+
[1,2,3],
55+
[1,3,2],
56+
[2,1,3],
57+
[2,3,1],
58+
[3,1,2],
59+
[3,2,1]
60+
]
61+
```
62+
63+
思路:
64+
65+
怎么写递归函数
66+
67+
+ 我们要在这个包含解的空间树上,用 DFS(递归)的方式搜索出所有的解。
68+
69+
+ dfs 函数做的事:基于当前的 path,继续选数,直到构建出合法的path,加入解集。
70+
+ 递归的入口:dfs 执行传入空 path,什么都还没选。
71+
72+
+ 函数体内,用 for 循环,枚举出当前所有的选项,并通过 if 语句跳过剪枝项。
73+
74+
+ 每一轮迭代,作出一个选择,基于它,继续选(递归调用)。
75+
76+
递归的出口:当构建的 path 数组长度等于 nums 长度,就选够了,加入解集。
77+
78+
为什么要回溯
79+
80+
+ 我们不是找到一个排列就完事,要找出所有满足条件的排列。
81+
82+
+ 递归结束时,结束的是当前的递归分支,还要去别的分支继续搜。
83+
84+
+ 所以,要撤销当前的选择,回到选择前的状态,去选下一个选项,即切入下一个分支。
85+
86+
+ 退回来,把路走全,才能在一棵空间树中,回溯出所有的解。
87+
88+
```javascript
89+
function permute(nums) {
90+
let res = []
91+
let used = {}
92+
function deps(path) {
93+
if(path.length == nums.length) {
94+
res.push(path.slice())
95+
return
96+
}
97+
for(let num of nums) {
98+
if(used[num]) continue
99+
path.push(num)
100+
used[num] = true
101+
deps(path)
102+
path.pop()
103+
used[num] = false
104+
}
105+
}
106+
deps([])
107+
return res
108+
}
109+
```
110+
111+
3. 加起来和为目标值的组合
112+
113+
给出一组候选数和一个目标数, 找出候选数中 和为目标数的所有组合
114+
115+
```
116+
input: [100, 10, 20, 70, 60, 10, 50] 80
117+
output: [[10,10,60],[10,20,50],[10,70],[20,60]]
118+
```
119+
120+
121+
122+
```javascript
123+
function combinationSum2(nums, target) {
124+
let result = []
125+
nums.sort((a,b) => a-b)
126+
function combination(arr, start, val) {
127+
if(val == 0) {
128+
result.push([...arr])
129+
} else {
130+
for(let i = start; i < nums.length; i++) {
131+
if(nums[i] <= val && (i== start || nums[i] != nums[i - 1]) {
132+
val -= nums[i]
133+
arr.push(nums[i])
134+
combination(arr, i, val)
135+
arr.pop()
136+
val += nums[i]
137+
}
138+
}
139+
}
140+
}
141+
combination([], 0, target)
142+
}
143+
```
144+

0 commit comments

Comments
 (0)