1. 解析
题目大意,按照以下规则删除[1, n]范围内的元素,直到剩下1个:
①从左——>右,然后右——>左,依次重复
②每次隔一个间隔删除
2. 分析
我想到的解法:根据题目所给定的规则进行筛选。利用两个数组,nums存储[1, n],刚开始左——>右,temp保存经过删除后剩下的元素,然后将其反转,这样就会变成右——>左,依次迭代执行,直到剩下一个元素。可以OJ,但空间复杂度比较高
例如:1, 2, 3, 4, 5, 6, 7, 8, 9
左——>右:删除1, 3, 5, 7, 9,temp = [2, 4, 6, 8],将其反转[8, 6, 4, 2]
右——>左:删除8, 4,temp = [6, 2],将其反转[2, 6]
左——>右:删除2,temp = [6]
class Solution {
public:
int lastRemaining(int n) {
vector<int> nums(n);
vector<int> temp;
for (int i = 0; i < n; ++i) nums[i] = i+1;
while (nums.size() > 1){
for (int i = 1; i < nums.size(); i = i + 2)
temp.push_back(nums[i]);
reverse(temp.begin(), temp.end());
nums = temp;
temp.clear();
}
return nums.back();
}
};
3. 找规律
参考@Grandyang的博客,这种解法还是比较难想的,从上面的例子我们可以发现,实际上,每删除一次,间距都会增大1倍
例如:
1 2 3 4 5 6 7 8 9 间距为2
2 4 6 8 间距为4
2 6
1 2 3 4 5 6 7 间距为2
2 4 6 间距为4
4
综合以上例子,我们可以发现若从左往右,则从当前剩余的第1个数开始删;从右往左,可能会删除当前剩余的数中的第1个也有可能删除第2个数,如果所剩余的个数为奇数,则删除第1个; 若为偶数,则删除第二个。
class Solution {
public:
int lastRemaining(int n){
int res = 1, step = 1;
while (step * 2 <= n){
res += step; //默认从第一个开始删
step *= 2; //左往右
if (step * 2 > n) break; //右往左
if ((n/step) % 2 == 1) res += step; //奇数,从第二个数开始删
step *= 2; //间距增大一倍
}
return res;
}
};