題目:
0,1,...n-1這n個數字排成一個圓圈,從數字0開始每次從這個圓圈里刪除第m個數字,求出這個圓圈里剩下的最后一個數字。
思路:
1、環形鏈表模擬圓圈
創建一個n個節點的環形鏈表,然后每次在這個鏈表中刪除第m個節點;
可以用std::list來模擬環形鏈表,list本身不是環形結構,因此每當迭代器掃描到鏈表末尾的時候,需要將迭代器移到鏈表的頭部。
2、分析每次被刪除的數字的規律,動態規划
假設從0-n-1中刪除了第m個數字,則下一輪的數字排列為m,m+1,.....n,1,2,3...m-2,將該數字排列重新映射為0~n-2,則為
m 0
m+1 1
.... ....
n-1 n-1-m
0 n-m
1 n-m+1
... ....
m-2 n-2
可以看出從右往左的映射關系為left=(right+m)%n,即0~n-1序列中最后剩下的數字等於(0~n-2序列中最后剩下的數字+m)%n,很明顯當n=1時,只有一個數,那么剩下的數字就是0.
問題轉化為動態規划問題,關系表示為:
f(n)=(f(n-1)+m)%n; 當n=1,f(1)=0;
代碼:
1、環形鏈表
#include <iostream>
#include <list>
using namespace std;
int lastRemaining(unsigned int n,unsigned int m){
if(n<1 || m<1)
return -1;
std::list<int> numbers;
for(unsigned int i=0;i<n;i++)
numbers.push_back(i);
std::list<int>::iterator current=numbers.begin();
std::list<int>::iterator next;
while(numbers.size()>1){
for(unsigned int i=1;i<m;i++){
current++;
if(current==numbers.end())
current=numbers.begin();
}
next=++current;
if(next==numbers.end())
next=numbers.begin();
--current;
numbers.erase(current);
current=next;
}
return *(current);
}
int main()
{
cout << lastRemaining(5,3) << endl;
return 0;
}
2、映射規律,動態規划
int lastRemaining_1(unsigned int n,unsigned 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;
}
int lastRemaining_2(unsigned int n,unsigned int m){
if(n<1 || m<1)
return -1;
if(n==1)
return 0;
return (lastRemaining_2(n-1,m)+m)%n;
}
在線測試OJ:
http://www.nowcoder.com/books/coding-interviews/f78a359491e64a50bce2d89cff857eb6?rp=2
AC代碼:
1、環形鏈表
class Solution {
public:
int LastRemaining_Solution(unsigned int n, unsigned int m)
{
if(n<1 || m<1)
return -1;
std::list<int> numbers;
for(unsigned int i=0;i<n;i++)
numbers.push_back(i);
std::list<int>::iterator current=numbers.begin();
std::list<int>::iterator next;
while(numbers.size()>1){
for(unsigned int i=1;i<m;i++){
++current;
if(current==numbers.end())
current=numbers.begin();
}
next=++current;
if(next==numbers.end())
next=numbers.begin();
--current;
numbers.erase(current);
current=next;
}
return *current;
}
};
2、序列規律,動態規划
class Solution {
public:
int LastRemaining_Solution(unsigned int n, unsigned 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;
}
};
class Solution {
public:
int LastRemaining_Solution(unsigned int n, unsigned int m)
{
if(n<1 || m<1)
return -1;
if(n==1)
return 0;
return (LastRemaining_Solution(n-1,m)+m)%n;
}
};
