解法1:链表模拟环
首先看第1次删除的是第k = m%n个数(注意索引从0开始所以删除的是数字索引=k-1)。
class Solution {
public int iceBreakingGame(int num, int target) {
List<Integer> circle = new LinkedList<>();
for (int i = 0; i < num; ++i) {
circle.add(i);
}
int removeIdx = (target - 1) % num; // 第target个数,索引是target - 1
while (num > 1) {
--num;
circle.remove(circle.get(removeIdx));
removeIdx = (removeIdx + target - 1) % num;
}
return circle.get(0);
}
}
解法2:需要好好理解推导过程!
f(n, m)表示长度为n的序列,需要你删除n-1次后,最后留下元素的索引;
则f(n-1, m)表示长度为n-1的序列,需要删除n-2次,最后留下元素的索引;
答案参考:https://leetcode.cn/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/solutions/177639/javajie-jue-yue-se-fu-huan-wen-ti-gao-su-ni-wei-sh/
class Solution {
public int lastRemaining(int n, int m) {
int ans = 0;
// 最后一轮剩下2个人,所以从2开始反推
for (int i = 2; i <= n; i++) {
ans = (ans + m) % i;
}
return ans;
}
}
作者:Sweetiee🍬的小号
链接:https://leetcode.cn/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/solutions/177639/javajie-jue-yue-se-fu-huan-wen-ti-gao-su-ni-wei-sh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
##Solution1:
当年第一遍做时,自己想的垃圾算法
class Solution {
public:
int LastRemaining_Solution(int n, int m) {
vector<int> nums(n,0);
int temp_count = 0, count = 0, i = 0; //nums[]初始化为n个0,temp_count检查是否到了m,count检查数组中1的数目是否到了n-1,i是计数用的
while(count < n - 1) {
if(nums[i] == 0) { //nums[i] == 0的情况,temp_count计数+1
temp_count++;
if(temp_count == m) { //temp_count到了m
nums[i] = 1;
count++;
temp_count = 0;
i++;
if(i == n)
i = 0;
}
else { //temp_count未到m
i++;
if(i == n)
i = 0;
}
}
else { //nums[i]==1的情况,直接跳过
i++;
if(i == n)
i = 0;
}
}
for(i = 0; i < n; i++){
if(nums[i] == 0)
return i;
}
return -1; //无解情况返回-1,一般都这样
}
};
##Solution2:
20190910重做。
书上的思路1:用链表模拟圆圈。
学习的两个点:
1.list(双向链表)和forward_list(单向链表),链接:https://blog.csdn.net/u013006553/article/details/78158717
2.顺序容器中利用迭代器和erase()函数删除元素,参考博客:https://blog.csdn.net/Allenlzcoder/article/details/82560220
public:
//用环形链表模拟圆圈
int LastRemaining_Solution(int n, int m) {
if (n < 1 || m < 1) return -1;
int i = 0;
//STL中的双向链表list容器,再任何位置插入和删除非常快
list<int> nums;
for (int i = 0; i < n; i++)
nums.push_back(i);
auto cur = nums.begin();
while (nums.size() > 1) {
for (int i = 1; i < m; i++) {
cur++;
if (cur == nums.end())
cur = nums.begin();
}
//erase()返回下一个有效的迭代器
cur = nums.erase(cur);
if (cur == nums.end())
cur = nums.begin();
}
return *cur;
}
};
##Solution3:
20190910重做。
书上的思路2:推导公式。除非碰上重题或类似题,否则真不容易想到类似的方法。
f
(
n
,
m
)
=
0
(
n
=
1
)
f(n, m) = 0 (n = 1)
f(n,m)=0 (n=1)
f
(
n
,
m
)
=
[
f
(
n
−
1
,
m
)
+
m
]
f(n, m) = [f(n-1, m) +m] % n (n > 1)
f(n,m)=[f(n−1,m)+m]
代码:
class Solution {
public:
int LastRemaining_Solution(int n, int m) {
if (n < 1 || m < 1) return -1;
int last = 0;
for (int i = 2; i <= n; i++)
last = (last + m) % i;
return last;
}
};