因为对STL中的 list 容器和 iterator 迭代器的使用不熟悉,花了很多时间现补知识。
最开始的代码会报段错误,如果把 iter++ 放在erase里面就不会报段错误,但还是会返回错误的结果。
int LastRemaining_Solution(int n, int m)
{
if(n<=0 || m<=0) return -1;
list<int> circlelist;
list<int>::iterator iter;
for(int i=0; i<n; i++){
circlelist.push_back(i);
}
iter = circlelist.begin();
int count = -1;
while(circlelist.size()>1){
for(; iter != circlelist.end(); iter++){ // 迭代器不能用小于,只能用 !=
count++;
if(count == m-1) {
circlelist.erase(iter); //用erase不能用remove的原因?两者区别?
iter++;
count = 0;
}
}
iter = circlelist.begin();
}
int result = *(iter);
return result;
}
因为不太清楚 iter 指向的元素删除后iter如何变化,把 iter++ 改成 用另一个迭代器 next 指向被删除的元素的下一个元素 ,在删除后将 next 赋值给 iter。这样做可以AC。
10.25更新:关于STL中容器删除元素使用erase函数的注意事项:https://blog.youkuaiyun.com/Baoli1008/article/details/47122753
iter = circlelist.begin();
int count = -1;
while(circlelist.size()>1){
for(; iter != circlelist.end(); iter++){
count++;
if(count == m-1) {
list<int>::iterator next = ++iter;
if(next==circlelist.end()){
next = circlelist.begin();
}
circlelist.erase(--iter);
//iter++;
count = 0;
iter = next;
}
}
iter = circlelist.begin();
}
int result = *(iter);
return result;
书上的环形链表法的思路更顺畅,可读性也更好:
注意点:i 从1开始计数,因为一开始iter就已经指向第0个节点,第一次结束for循环就指向第1个节点了,第m-1次for循环结束,iter刚好指向第m-1个节点,要删除的就是这个节点。简单来说:从0到m-1只需要走m-1次,所以循环m-1次就够了
int LastRemaining_Solution(int n, int m)
{
if(n<=0 || m<=0) return -1;
list<int> circlelist;
for(int i=0; i<n; i++){
circlelist.push_back(i);
}
list<int>::iterator iter = circlelist.begin();
while(circlelist.size()>1){
for(int i=1; i<m; i++){ //i从1开始计数,因为一开始iter就指向第0个元素
iter++;
if(iter==circlelist.end()) iter = circlelist.begin();
}
//在删除目标节点之前,需要把下一个节点保存下来
list<int>::iterator next = ++iter;
if(next==circlelist.end()) next = circlelist.begin();
circlelist.erase(--iter);
iter = next;
}
return *(iter);
}
第二种方法:总结递归公式的解法(书上公式有误)
递归形式:内存超限:您的程序使用了超过限制的内存(原因:待补充)
class Solution {
public:
int LastRemaining_Solution(int n, int m)
{
if(n==1) return 0;
return (LastRemaining_Solution(n-1, m)+m) % n; //改成 n-1依然内存超限
}
};
循环形式:
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; // 此处不是n,此处应为n-1,书上公式有误
}
return last;
}
博客探讨了在解决约瑟夫环问题时遇到的STL list容器和iterator迭代器使用问题。作者最初遇到段错误,通过使用辅助迭代器next避免了错误,并提供了书中的环形链表解决方案。此外,还提到了STL中删除元素时erase函数的注意事项,以及一种递归解法的内存超限问题。
960

被折叠的 条评论
为什么被折叠?



