Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
wushizhenking
CS-Notes
提交
7ca1fcc0
C
CS-Notes
项目概览
wushizhenking
/
CS-Notes
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
CS-Notes
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
7ca1fcc0
编写于
4月 03, 2018
作者:
C
CyC2018
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
auto commit
上级
3e35079c
变更
3
显示空白变更内容
内联
并排
Showing
3 changed file
with
151 addition
and
90 deletion
+151
-90
notes/Leetcode 题解.md
notes/Leetcode 题解.md
+146
-85
notes/分布式问题分析.md
notes/分布式问题分析.md
+5
-5
pics/2018040302.jpg
pics/2018040302.jpg
+0
-0
未找到文件。
notes/Leetcode 题解.md
浏览文件 @
7ca1fcc0
...
...
@@ -1841,9 +1841,9 @@ private int rob(int[] nums, int first, int last) {
定义一个数组 dp 存储错误方式数量,dp[i] 表示前 i 个信和信封的错误方式数量。假设第 i 个信装到第 j 个信封里面,而第 j 个信装到第 k 个信封里面。根据 i 和 k 是否相等,有两种情况:
①
i==k,交换 i 和 k 的信后,它们的信和信封在正确的位置,但是其余 i-2 封信有 dp[i-2] 种错误装信的方式。由于 j 有 i-1 种取值,因此共有 (i-1)
\*
dp[i-2] 种错误装信方式。
1.
i==k,交换 i 和 k 的信后,它们的信和信封在正确的位置,但是其余 i-2 封信有 dp[i-2] 种错误装信的方式。由于 j 有 i-1 种取值,因此共有 (i-1)
\*
dp[i-2] 种错误装信方式。
②
i != k,交换 i 和 j 的信后,第 i 个信和信封在正确的位置,其余 i-1 封信有 dp[i-1] 种错误装信方式。由于 j 有 i-1 种取值,因此共有 (n-1)
\*
dp[i-1] 种错误装信方式。
2.
i != k,交换 i 和 j 的信后,第 i 个信和信封在正确的位置,其余 i-1 封信有 dp[i-1] 种错误装信方式。由于 j 有 i-1 种取值,因此共有 (n-1)
\*
dp[i-1] 种错误装信方式。
综上所述,错误装信数量方式数量为:
...
...
@@ -1898,7 +1898,10 @@ len = 2 : [4, 5], [5, 6] => tails[1] = 5
len = 3 : [4, 5, 6] => tails[2] = 6
```
对于一个元素 x,如果它大于 tails 数组所有的值,那么把它添加到 tails 后面;如果 tails[i-1] < x <= tails[i],那么更新 tails[i] = x 。
对于一个元素 x,
-
如果它大于 tails 数组所有的值,那么把它添加到 tails 后面,表示最长递增子序列长度加 1;
-
如果 tails[i-1] < x <= tails[i],那么更新 tails[i] = x。
可以看出 tails 数组保持有序,因此在查找 S
<sub>
i
</sub>
位于 tails 数组的位置时就可以使用二分查找。
...
...
@@ -1926,6 +1929,43 @@ private int binarySearch(int[] nums, int first, int last, int key) {
}
```
**一组整数对能够构成的最长链**
[
Leetcode : 646. Maximum Length of Pair Chain (Medium)
](
https://leetcode.com/problems/maximum-length-of-pair-chain/description/
)
```
html
Input: [[1,2], [2,3], [3,4]]
Output: 2
Explanation: The longest chain is [1,2] -> [3,4]
```
对于 (a, b) 和 (c, d) ,如果 b < c,则它们可以构成一条链。
```
java
public
int
findLongestChain
(
int
[][]
pairs
)
{
if
(
pairs
==
null
||
pairs
.
length
==
0
)
{
return
0
;
}
Arrays
.
sort
(
pairs
,
(
a
,
b
)
->
(
a
[
0
]
-
b
[
0
]));
int
n
=
pairs
.
length
;
int
[]
dp
=
new
int
[
n
];
Arrays
.
fill
(
dp
,
1
);
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
for
(
int
j
=
0
;
j
<
i
;
j
++)
{
if
(
pairs
[
i
][
0
]
>
pairs
[
j
][
1
]){
dp
[
i
]
=
Math
.
max
(
dp
[
i
],
dp
[
j
]
+
1
);
}
}
}
int
ret
=
0
;
for
(
int
num
:
dp
)
{
ret
=
Math
.
max
(
ret
,
num
);
}
return
ret
;
}
```
**最长摆动子序列**
[
Leetcode : 376. Wiggle Subsequence (Medium)
](
https://leetcode.com/problems/wiggle-subsequence/description/
)
...
...
@@ -1966,9 +2006,8 @@ public int wiggleMaxLength(int[] nums) {
定义一个二维数组 dp 用来存储最长公共子序列的长度,其中 dp
[
i
][
j
]
表示 S1 的前 i 个字符与 S2 的前 j 个字符最长公共子序列的长度。考虑 S1
<sub>
i
</sub>
与 S2
<sub>
j
</sub>
值是否相等,分为两种情况:
① 当 S1
<sub>
i
</sub>
==S2
<sub>
j
</sub>
时,那么就能在 S1 的前 i-1 个字符与 S2 的前 j-1 个字符最长公共子序列的基础上再加上 S1
<sub>
i
</sub>
这个值,最长公共子序列长度加 1 ,即 dp
[
i
][
j
]
= dp
[
i-1
][
j-1
]
+ 1。
② 当 S1
<sub>
i
</sub>
!= S2
<sub>
j
</sub>
时,此时最长公共子序列为 S1 的前 i-1 个字符和 S2 的前 j 个字符最长公共子序列,与 S1 的前 i 个字符和 S2 的前 j-1 个字符最长公共子序列,它们的最大者,即 dp
[
i
][
j
]
= max{ dp
[
i-1
][
j
]
, dp
[
i
][
j-1
]
}。
1.
当 S1
<sub>
i
</sub>
==S2
<sub>
j
</sub>
时,那么就能在 S1 的前 i-1 个字符与 S2 的前 j-1 个字符最长公共子序列的基础上再加上 S1
<sub>
i
</sub>
这个值,最长公共子序列长度加 1 ,即 dp
[
i
][
j
]
= dp
[
i-1
][
j-1
]
+ 1。
2.
当 S1
<sub>
i
</sub>
!= S2
<sub>
j
</sub>
时,此时最长公共子序列为 S1 的前 i-1 个字符和 S2 的前 j 个字符最长公共子序列,与 S1 的前 i 个字符和 S2 的前 j-1 个字符最长公共子序列,它们的最大者,即 dp
[
i
][
j
]
= max{ dp
[
i-1
][
j
]
, dp
[
i
][
j-1
]
}。
综上,最长公共子序列的状态转移方程为:
...
...
@@ -1978,9 +2017,9 @@ public int wiggleMaxLength(int[] nums) {
与最长递增子序列相比,最长公共子序列有以下不同点:
①
针对的是两个序列,求它们的最长公共子序列。
②
在最长递增子序列中,dp
[
i] 表示以 S<sub>i</sub> 为结尾的最长递增子序列长度,子序列必须包含 S<sub>i</sub> ;在最长公共子序列中,dp[i
][
j
]
表示 S1 中前 i 个字符与 S2 中前 j 个字符的最长公共子序列长度,不一定包含 S1
<sub>
i
</sub>
和 S2
<sub>
j
</sub>
。
③
由于 2 ,在求最终解时,最长公共子序列中 dp
[
N
][
M
]
就是最终解,而最长递增子序列中 dp[N] 不是最终解,因为以 S
<sub>
N
</sub>
为结尾的最长递增子序列不一定是整个序列最长递增子序列,需要遍历一遍 dp 数组找到最大者。
-
针对的是两个序列,求它们的最长公共子序列。
-
在最长递增子序列中,dp
[
i] 表示以 S<sub>i</sub> 为结尾的最长递增子序列长度,子序列必须包含 S<sub>i</sub> ;在最长公共子序列中,dp[i
][
j
]
表示 S1 中前 i 个字符与 S2 中前 j 个字符的最长公共子序列长度,不一定包含 S1
<sub>
i
</sub>
和 S2
<sub>
j
</sub>
。
-
由于 2 ,在求最终解时,最长公共子序列中 dp
[
N
][
M
]
就是最终解,而最长递增子序列中 dp[N] 不是最终解,因为以 S
<sub>
N
</sub>
为结尾的最长递增子序列不一定是整个序列最长递增子序列,需要遍历一遍 dp 数组找到最大者。
```
java
public
int
lengthOfLCS
(
int
[]
nums1
,
int
[]
nums2
)
{
...
...
@@ -2002,8 +2041,8 @@ public int lengthOfLCS(int[] nums1, int[] nums2) {
定义一个二维数组 dp 存储最大价值,其中 dp
[
i
][
j
]
表示体积不超过 j 的情况下,前 i 件物品能达到的最大价值。设第 i 件物品体积为 w,价值为 v,根据第 i 件物品是否添加到背包中,可以分两种情况讨论:
①
第 i 件物品没添加到背包,总体积不超过 j 的前 i 件物品的最大价值就是总体积不超过 j 的前 i-1 件物品的最大价值,dp
[
i
][
j
]
= dp
[
i-1
][
j
]
。
②
第 i 件物品添加到背包中,dp
[
i
][
j
]
= dp
[
i-1
][
j-w
]
+ v。
1.
第 i 件物品没添加到背包,总体积不超过 j 的前 i 件物品的最大价值就是总体积不超过 j 的前 i-1 件物品的最大价值,dp
[
i
][
j
]
= dp
[
i-1
][
j
]
。
2.
第 i 件物品添加到背包中,dp
[
i
][
j
]
= dp
[
i-1
][
j-w
]
+ v。
第 i 件物品可添加也可以不添加,取决于哪种情况下最大价值更大。
...
...
@@ -2069,33 +2108,25 @@ Output: true
Explanation: The array can be partitioned as [1, 5, 5] and [11].
```
可以看成一个背包大小为 sum/2 的 0-1 背包问题,但是也有不同的地方,这里没有价值属性,并且背包必须被填满。
以下实现使用了空间优化。
可以看成一个背包大小为 sum/2 的 0-1 背包问题。
```
java
public
boolean
canPartition
(
int
[]
nums
)
{
public
boolean
canPartition
(
int
[]
nums
)
{
int
sum
=
0
;
for
(
int
num
:
nums
)
{
sum
+=
num
;
}
if
(
sum
%
2
!=
0
)
{
return
false
;
}
for
(
int
num
:
nums
)
sum
+=
num
;
if
(
sum
%
2
!=
0
)
return
false
;
int
W
=
sum
/
2
;
boolean
[]
dp
=
new
boolean
[
W
+
1
];
for
(
int
i
=
0
;
i
<=
W
;
i
++)
{
if
(
nums
[
0
]
==
i
)
{
dp
[
i
]
=
true
;
}
dp
[
0
]
=
true
;
for
(
int
num
:
nums
)
{
// 0-1 背包一个物品只能用一次
for
(
int
i
=
W
;
i
>=
0
;
i
--)
{
// 从后往前,先计算 dp[i] 再计算 dp[i-num]
if
(
num
<=
i
)
{
dp
[
i
]
=
dp
[
i
]
||
dp
[
i
-
num
];
}
for
(
int
i
=
1
;
i
<
nums
.
length
;
i
++)
{
for
(
int
j
=
W
;
j
>=
nums
[
i
];
j
--)
{
dp
[
j
]
=
dp
[
j
]
||
dp
[
j
-
nums
[
i
]];
}
}
return
dp
[
W
];
}
}
```
**字符串按单词列表分割**
...
...
@@ -2108,15 +2139,20 @@ dict = ["leet", "code"].
Return true because "leetcode" can be segmented as "leet code".
```
这是一个完全背包问题,和 0-1 背包不同的是,完全背包中物品可以使用多次。在这一题当中,词典中的单词可以被使用多次。
0-1 背包和完全背包在实现上的不同之处是,0-1 背包对物品的迭代是在最外层,而完全背包对物品的迭代是最最里层。
```
java
public
boolean
wordBreak
(
String
s
,
List
<
String
>
wordDict
)
{
int
n
=
s
.
length
();
boolean
[]
dp
=
new
boolean
[
n
+
1
];
dp
[
0
]
=
true
;
for
(
int
i
=
1
;
i
<=
n
;
i
++)
{
for
(
String
word
:
wordDict
)
{
if
(
word
.
length
()
<=
i
&&
word
.
equals
(
s
.
substring
(
i
-
word
.
length
(),
i
)))
{
dp
[
i
]
=
dp
[
i
]
||
dp
[
i
-
word
.
length
()];
for
(
String
word
:
wordDict
)
{
// 每个单词可以使用多次
int
len
=
word
.
length
();
if
(
len
<=
i
&&
word
.
equals
(
s
.
substring
(
i
-
len
,
i
)))
{
dp
[
i
]
=
dp
[
i
]
||
dp
[
i
-
len
];
}
}
}
...
...
@@ -2142,7 +2178,9 @@ Explanation:
There are 5 ways to assign symbols to make the sum of nums be target 3.
```
该问题可以转换为 subset sum 问题,从而使用 0-1 背包的方法来求解。可以将这组数看成两部分,P 和 N,其中 P 使用正号,N 使用负号,有以下推导:
该问题可以转换为 Subset Sum 问题,从而使用 0-1 背包的方法来求解。
可以将这组数看成两部分,P 和 N,其中 P 使用正号,N 使用负号,有以下推导:
```
html
sum(P) - sum(N) = target
...
...
@@ -2155,26 +2193,34 @@ sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N)
```
java
public
int
findTargetSumWays
(
int
[]
nums
,
int
S
)
{
int
sum
=
0
;
for
(
int
num
:
nums
)
sum
+=
num
;
if
(
sum
<
S
||
(
sum
+
S
)
%
2
==
1
)
return
0
;
int
W
=
(
sum
+
S
)
/
2
;
int
[]
dp
=
new
int
[
W
+
1
];
dp
[
0
]
=
1
;
for
(
int
num
:
nums
)
{
sum
+=
num
;
for
(
int
i
=
W
;
i
>=
0
;
i
--)
{
if
(
num
<=
i
)
{
dp
[
i
]
=
dp
[
i
]
+
dp
[
i
-
num
];
}
if
(
sum
<
S
||
(
sum
+
S
)
%
2
==
1
)
{
return
0
;
}
return
subsetSum
(
nums
,
(
sum
+
S
)
>>>
1
);
}
return
dp
[
W
];
}
```
private
int
subsetSum
(
int
[]
nums
,
int
targetSum
)
{
Arrays
.
sort
(
nums
);
int
[]
dp
=
new
int
[
targetSum
+
1
];
dp
[
0
]
=
1
;
for
(
int
i
=
0
;
i
<
nums
.
length
;
i
++)
{
int
num
=
nums
[
i
];
for
(
int
j
=
targetSum
;
j
>=
num
;
j
--)
{
dp
[
j
]
=
dp
[
j
]
+
dp
[
j
-
num
];
}
DFS 解法:
```
java
public
int
findTargetSumWays
(
int
[]
nums
,
int
S
)
{
return
findTargetSumWays
(
nums
,
0
,
S
);
}
private
int
findTargetSumWays
(
int
[]
nums
,
int
start
,
int
S
)
{
if
(
start
==
nums
.
length
)
{
return
S
==
0
?
1
:
0
;
}
return
dp
[
targetSum
]
;
return
findTargetSumWays
(
nums
,
start
+
1
,
S
+
nums
[
start
])
+
findTargetSumWays
(
nums
,
start
+
1
,
S
-
nums
[
start
])
;
}
```
...
...
@@ -2446,10 +2492,36 @@ public int minDistance(String word1, String word2) {
}
```
**修改一个字符串称为另一个字符串**
// TODO
**修改一个字符串称为另一个字符串**
[
Leetcode : 72. Edit Distance (Hard)
](
https://leetcode.com/problems/edit-distance/description/
)
```
java
public
int
minDistance
(
String
word1
,
String
word2
)
{
if
(
word1
==
null
||
word2
==
null
)
{
return
0
;
}
int
m
=
word1
.
length
(),
n
=
word2
.
length
();
int
[][]
dp
=
new
int
[
m
+
1
][
n
+
1
];
for
(
int
i
=
1
;
i
<=
m
;
i
++)
{
dp
[
i
][
0
]
=
i
;
}
for
(
int
i
=
1
;
i
<=
n
;
i
++)
{
dp
[
0
][
i
]
=
i
;
}
for
(
int
i
=
1
;
i
<=
m
;
i
++)
{
for
(
int
j
=
1
;
j
<=
n
;
j
++)
{
if
(
word1
.
charAt
(
i
-
1
)
==
word2
.
charAt
(
j
-
1
))
{
dp
[
i
][
j
]
=
dp
[
i
-
1
][
j
-
1
];
}
else
{
dp
[
i
][
j
]
=
Math
.
min
(
dp
[
i
-
1
][
j
-
1
],
Math
.
min
(
dp
[
i
][
j
-
1
],
dp
[
i
-
1
][
j
]))
+
1
;
}
}
}
return
dp
[
m
][
n
];
}
```
### 分割整数
**分割整数的最大乘积**
...
...
@@ -2552,6 +2624,20 @@ public int uniquePaths(int m, int n) {
}
```
也可以直接用数学公式求解,这是一个组合问题。机器人总共移动的次数 S=m+n-2,向下移动的次数 D=m-1,那么问题可以看成从 S 从取出 D 个位置的组合数量,这个问题的解为 C(S, D)。
```
java
public
int
uniquePaths
(
int
m
,
int
n
)
{
int
S
=
m
+
n
-
2
;
// 总共的移动次数
int
D
=
m
-
1
;
// 向下的移动次数
long
ret
=
1
;
for
(
int
i
=
1
;
i
<=
D
;
i
++)
{
ret
=
ret
*
(
S
-
D
+
i
)
/
i
;
}
return
(
int
)
ret
;
}
```
**矩阵的最小路径和**
[
Leetcode : 64. Minimum Path Sum (Medium)
](
https://leetcode.com/problems/minimum-path-sum/description/
)
...
...
@@ -2616,43 +2702,6 @@ public int maxProfit(int[] prices) {
}
```
**一组整数对能够构成的最长链**
[
Leetcode : 646. Maximum Length of Pair Chain (Medium)
](
https://leetcode.com/problems/maximum-length-of-pair-chain/description/
)
```
html
Input: [[1,2], [2,3], [3,4]]
Output: 2
Explanation: The longest chain is [1,2] -> [3,4]
```
对于 (a, b) 和 (c, d) ,如果 b < c,则它们可以构成一条链。
```
java
public
int
findLongestChain
(
int
[][]
pairs
)
{
if
(
pairs
==
null
||
pairs
.
length
==
0
)
{
return
0
;
}
Arrays
.
sort
(
pairs
,
(
a
,
b
)
->
(
a
[
0
]
-
b
[
0
]));
int
n
=
pairs
.
length
;
int
[]
dp
=
new
int
[
n
];
Arrays
.
fill
(
dp
,
1
);
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
for
(
int
j
=
0
;
j
<
i
;
j
++)
{
if
(
pairs
[
i
][
0
]
>
pairs
[
j
][
1
]){
dp
[
i
]
=
Math
.
max
(
dp
[
i
],
dp
[
j
]
+
1
);
}
}
}
int
ret
=
0
;
for
(
int
num
:
dp
)
{
ret
=
Math
.
max
(
ret
,
num
);
}
return
ret
;
}
```
**买入和售出股票最大的收益**
[
Leetcode : 121. Best Time to Buy and Sell Stock (Easy)
](
https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/
)
...
...
@@ -2679,6 +2728,18 @@ public int maxProfit(int[] prices) {
[
Leetcode : 650. 2 Keys Keyboard (Medium)
](
https://leetcode.com/problems/2-keys-keyboard/description/
)
题目描述:最开始只有一个字符 A,问需要多少次操作能够得到 n 个字符 A,每次操作可以复制当前所有的字符,或者粘贴。
```
Input: 3
Output: 3
Explanation:
Intitally, we have one character 'A'.
In step 1, we use Copy All operation.
In step 2, we use Paste operation to get 'AA'.
In step 3, we use Paste operation to get 'AAA'.
```
```
java
public
int
minSteps
(
int
n
)
{
int
[]
dp
=
new
int
[
n
+
1
];
...
...
notes/分布式问题分析.md
浏览文件 @
7ca1fcc0
...
...
@@ -127,14 +127,14 @@
<div
align=
"center"
>
<img
src=
"../pics//0ee0f61b-c782-441e-bf34-665650198ae0.jpg"
/>
</div><br>
### 6. 源地址哈希法 (IP Hash)
### 6.源地址哈希法(ip hash)
源地址哈希通过对客户端IP哈希计算得到的一个数值,用该数值对服务器数量进行取模运算,取模结果便是目标服务器的序号。
-
优点:保证同一IP的客户端都会被hash到同一台服务器上。
-
缺点:不利于集群扩展,后台服务器数量变更都会影响hash结果。可以采用一致性Hash改进。
源地址哈希通过对客户端 IP 哈希计算得到的一个数值,用该数值对服务器数量进行取模运算,取模结果便是目标服务器的序号。
<div
align=
"center"
>
<img
src=
"../pics//2018040302.jpg"
/>
</div><br>
-
优点:保证同一 IP 的客户端都会被 hash 到同一台服务器上。
-
缺点:不利于集群扩展,后台服务器数量变更都会影响 hash 结果。可以采用一致性 Hash 改进。
<div
align=
"center"
>
<img
src=
"../pics//2018040302.jpg"
/>
</div><br>
## 实现
...
...
pics/2018040302.jpg
查看替换文件 @
3e35079c
浏览文件 @
7ca1fcc0
32.3 KB
|
W:
|
H:
33.0 KB
|
W:
|
H:
2-up
Swipe
Onion skin
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录