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個數字,從左往右開始每隔一位刪除一個數字,到達最右側後,再從右往左每隔一位刪除一個數字,如此反覆,直到剩下最後一個數字。問最後剩下的數字是多少。java
先從一個例子入手,當n等於7時,數字序列爲1,2,3,4,5,6,7, 刪除序列以下:函數
1 2 3 4 5 6 7 2 4 6 4
能夠看到,第一輪刪除後剩下的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),也就是所謂的鏡像刪除問題。
舉個例子:this
從左往右開始刪除 1 2 3 4 5 6 2 4 6 4 從右往左開始刪除 1 2 3 4 5 6 1 3 5 3
能夠看到兩者剩餘的值加起來必定爲n+1即7。
根據這個原理,咱們能夠優化上面的遞歸,無需再利用left值來標記是從左往右刪除仍是從右往左刪除,直接執行鏡像刪除便可。code
public int lastRemaining2(int n) { return n == 1 ? 1 : (1 + n / 2 - lastRemaining2(n/2)) * 2; }