题目:
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、暴力法:就是模拟删除,思路很简单,但是通不过大数据测试。因为其时间复杂度是O(n),空间复杂度是O(n)。
2、找规律:事实上我们只要找到每一趟第一个需要删除的数字即可,而这可以通过观察和推导得出结论:1)步长规律:第一列的步长是2,第二列的步长是4,第三列的步长是8......也就是说步长在每轮循环中是上一轮的两倍。2)元素递减规律:元素个数显然是按照1/2的速度递减的,当递减元素个数减少到1时,就得到了最终的剩余元素。3)头部元素:从左侧开始的头部元素是上一次的头部元素加上步长。对于从右侧开始的迭代过程,可以分为两种情况:如果剩余元素是奇数个时,同左侧开始的情况;否则头部元素不变。这种思路的时间复杂度是O(logn),空间复杂度是O(1)。
代码:
1、暴力法:
class Solution { public: int lastRemaining(int n) { list<int> my_list; for (int i = 1; i <= n; ++i) { my_list.push_back(i); } bool forward = true; while (my_list.size() > 1) { list<int>::iterator it = my_list.begin(); if (!forward && my_list.size() % 2 == 0) { ++it; } while (it != my_list.end()) { it = my_list.erase(it); if (it != my_list.end()) { ++it; } } forward = !forward; } return my_list.front(); } };2、找规律:
class Solution { public: int lastRemaining(int n) { int head = 1, step = 1; int forward = true; while(n > 1) { if(forward || n % 2 == 1) { head += step; } step *= 2; n /= 2; forward = !forward; } return head; } };