leetcode390.Elimination Game
題目要求
There is a list of sorted integers from 1 to n. Starting from left to right, remove the first number and every other number afterward until you reach the end of the list. Repeat the previous step again, but this time from right to left, remove the right most number and every other number from the remaining numbers. We keep repeating the steps again, alternating left to right and right to left, until a single number remains. Find the last number that remains starting with a list of length n. Example: Input: n = 9, 1 2 3 4 5 6 7 8 9 2 4 6 8 2 6 6 Output: 6
假設有1-n一共n個數字,從左往右開始每隔一位刪除一個數字,到達最右側後,再從右往左每隔一位刪除一個數字,如此反覆,直到剩下最後一個數字。問最後剩下的數字是多少。
思路一:遞迴
先從一個例子入手,當n等於7時,數字序列為1,2,3,4,5,6,7, 刪除序列如下:
可以看到,第一輪刪除後剩下的2,4,6就相當於是1,2,3的兩倍,我們可以等價於從右往左刪除1,2,3後剩餘的結果乘2。由此可見,假如我們定義一個遞迴函式f(n, left),我們可以有f(n/2, right)來獲取結果。
public int lastRemaining(int n) { return lastRemaining(n, true); } public int lastRemaining(int n, boolean left) { if(n == 1) { return 1; } if(n % 2 == 1) { return lastRemaining(n / 2, !left) * 2; }else{ if( left ) { return lastRemaining(n/2, !left) * 2; }else { return lastRemaining(n/2, !left) * 2 -1; } } }
思路二
這裡其實存在一個映象刪除的問題,也就是說,對於任何一個1~n的序列來說,從左往右開始刪除和從右往左開始刪除剩餘的結果的和一定為(n+1),也就是所謂的映象刪除問題。
舉個例子:
從左往右開始刪除 1 2 3 4 5 6 246 4 從右往左開始刪除 1 2 3 4 5 6 135 3
可以看到二者剩餘的值加起來一定為n+1即7。
根據這個原理,我們可以優化上面的遞迴,無需再利用left值來標記是從左往右刪除還是從右往左刪除,直接執行映象刪除即可。
public int lastRemaining2(int n) { return n == 1 ? 1 : (1 + n / 2 - lastRemaining2(n/2)) * 2; }