From 6c0c79565c83b130a25ec86b3a2ce067639c1f34 Mon Sep 17 00:00:00 2001 From: ShusenTang Date: Mon, 23 Dec 2019 21:45:58 +0800 Subject: [PATCH] Create 390. Elimination Game.md --- solutions/390. Elimination Game.md | 58 ++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 solutions/390. Elimination Game.md diff --git a/solutions/390. Elimination Game.md b/solutions/390. Elimination Game.md new file mode 100644 index 0000000..c05eab6 --- /dev/null +++ b/solutions/390. Elimination Game.md @@ -0,0 +1,58 @@ +# [390. Elimination Game](https://leetcode.com/problems/elimination-game/) + +# 思路 +给定1,2,...,n,然后按照题目的规则不断删除一些数,求最后剩下的数。 + +## 思路一 +我首先想到的就是按照题目的规则进行模拟,但不要纯暴力模拟,那样肯定超时,还是要根据其中一些规律。 +有一个很容易发现的规律:每次剩下的数都是一个等差数列,而且等差分别为1、2、4...。 +为此我们可以用一个循环,每次记录剩下的数的第一个数start和最后一个数end以及等差diff,不断循环直到 start = end 。 + +## 思路二 +逛[评论区](https://leetcode.com/problems/elimination-game/discuss/87128/C-1-line-solution-with-explanation)还发现了一个代码很简洁的递归解法。 + +我们设 +* `ML(n)`代表第一次是从左往后的情况下最终剩下的数,这就是要我们写的函数; +* `MR(n)`代表第一次是从右往左的情况下最终剩下的数; + +注意我们第一次将所有奇数都删除了,将剩下所有偶数都除2就得到序列1,2,...,n/2。即我们有`ML(n) = 2 * MR(n/2)`。 +又因为我们有`ML(n) + MR(n) = n + 1`(证明见[讨论区](https://leetcode.com/problems/elimination-game/discuss/87128/C-1-line-solution-with-explanation)), +所以`ML(n) = 2 * (n/2 + 1 - ML(n/2))`。根据这个公式我们就可以写出递归函数了,就一行。 + + +# C++ +## 思路一 +``` C++ +class Solution { +public: + int lastRemaining(int n) { + int start = 1, end = n, diff = 1; + int i = 0; // i记录循环的次数 + while(start != end){ + if(!(i & 1)){ // 从前往后, start可直接写出 + start += diff; + diff <<= 1; + end = (end - start) / diff * diff + start; + } + else{ // 从后往前, end可直接写出 + end -= diff; + diff <<= 1; + start = end - (end - start) / diff * diff; + } + + i++; + } + return start; + } +}; +``` + +## 思路二 +``` C++ +class Solution { +public: + int lastRemaining(int n) { + return n == 1 ? 1 : 2 * (1 + n / 2 - lastRemaining(n / 2)); + } +}; +```