Update 剑指 offer 题解.md

This commit is contained in:
LuoJianPing 2018-12-08 11:27:10 +08:00 committed by GitHub
parent 46e3021222
commit 4a9691f458
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -2813,7 +2813,7 @@ public boolean isContinuous(int[] nums) {
让小朋友们围成一个大圈。然后,随机指定一个数 m让编号为 0 的小朋友开始报数。每次喊到 m-1 的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续 0...m-1 报数 .... 这样下去 .... 直到剩下最后一个小朋友,可以不用表演。
## 解题思路
## 解题思路1
约瑟夫环,圆圈长度为 n 的解可以看成长度为 n-1 的解再加上报数的长度 m。因为是圆圈所以最后需要对 n 取余。
@ -2826,6 +2826,55 @@ public int LastRemaining_Solution(int n, int m) {
return (LastRemaining_Solution(n - 1, m) + m) % n;
}
```
## 解题思路2
创新的解法,采用数学公式推导找到规律,推导过程如下:
Step1.
首先定义一个关于 m 和 n 的函数f(n, m)表示在n个数字 0,1,2…,n-1 中每次删除第m个数字最后剩下的那个数字。
注意f(n, m)表示的是在经过了多次删除后最后剩下的那个数字也就是说f(n,m)本质上是个数。
Step2.
n个数中第一个被删除的数是(m - 1) % n把它记为k此时数组中还剩下0,1,2… k-1, k+1,…n-1 这几个数字。接下来从k+1开始计数相当于在剩下的序列中k+1排在最前面从而形成k+1,… n-1,… 0,1,2…k-1。本题中第一个被删除的是数字2因此数组还剩下 0,1,3,4,5相当于3,4,5,0,1。由于这个序列是不连续的在2那个地方断开了所以不能写为f(n-1, m)。在此记为g(n-1, m)。
最初序列最后剩下的数字一定是删除一个数字后剩下的数字因此f(n, m) = g(n-1, m)
Step3.
将[3,4,5,0,1]重新映射为[0,1,2,3,4]映射的公式是p(x) = (x - k - 1) % n。其中k = 2n = 6。
3 —-> 0
4 —-> 1
5 —-> 2
0 —-> 3
1 —-> 4
映射以后的序列是0,1,2,3,4是一个连续的序列因此可以用f(n-1, m)来表示。
此时的f(n-1, m)是不等于g(n-1, m),因为二者对应的序列不同,存在一个映射关系。
该映射的逆映射是 p(x) = (x + k + 1) % n
因此g(n-1, m) = p[f(n-1, m)] = [f(n-1, m) + k + 1] % n
f(n, m) = [f(n-1, m) + k + 1] % n
带入k = (m - 1) % n, 得到f(n, m) = [f(n-1, m) +m] % n (n > 1)
Step4.
当n = 1时只有一个人此时剩余的数字为0
综上,约瑟夫环的公式是:
f(n, m) = 0 (n = 1)
f(n, m) = [f(n-1, m) +m] % n (n > 1)
```java
public class Solution {
public int LastRemaining_Solution(int n, int m) {
// 不合法输入的判断
if(n == 0 || m < 1) {
return -1;
}
int last = 0;
for(int i = 2; i <= n; i++) {
last = (last + m) % i;
}
return last;
}
}
```
# 63. 股票的最大利润