面试题45:圆圈中的数字

面试题45:圆圈中的数字                          

 
1.题目:0,1,2.....,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈中删除掉第m个数字,求出这个圆圈里剩下的最后一个数字。
分析

例如,0,1,2,3,4这5个数字组成的一个圆圈,从数字0开始每次删除第三个数字,则删除的前四个数字依次是2,0,4,1,最后剩下的数字是3. 其实就是著名的Josephuse环问题。

 

解法一:
采用类似环形链表的方法来模型这个圆圈,可以使用模板库中的list来模拟环形链表,当每次迭代器到链表末尾的时候,把迭代器移到链表的头部,这样就相当于是环形遍历了。这种方法的时间复杂度是O(mn),空间复杂度是O(n)。
解法二:
可以定义一个关于n和m的方程,表示每次在n个数字0,...,n-1中每次删除第m个数字最后剩下的数字。
在第n个数字中,第一个被删除的数字是(m-1)/n,可以记为k,那么删除k之后剩下的n-1个数字为0,1,..k-1,k+1,...n-1,并且下一次删除的数字从k+1开始计数,相当于k+1排在前面,形成排列K+1,...n-1,0,1,...k-1。剩下的数字也是关于m和n的函数,可以记为f‘(n-1,m),最初的序列最后剩下的数字一定是删除一个数字之后剩下的数字,即f(n,m)=f'(n-1,m).可以将新序列做出如下的映射。

 

 

源码:

 
// JosephuseCircle.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
/** 
* 功能说明:Description 
* 作者:K0713 
* 日期:2016-10-9 
**/  
#include<iostream>  
#include <list>  

using namespace std;  

// ====================方法1====================  
int LastRemaining_Solution1(unsigned int n, unsigned int m)  
{  
    if (n < 1 || m < 1)  
        return -1;  
	
    unsigned int i = 0;  
	
    list<int> numbers;  
    for (i = 0; i < n; ++i)  
        numbers.push_back(i);//构建list  
	
    list<int>::iterator current = numbers.begin();  
    while (numbers.size() > 1)  
    {  
        for (int i = 1; i < m; ++i)//找到第m个数  
        {  
            current++;  
            if (current == numbers.end())//模拟环形  
                current = numbers.begin();  
        }  
#if 0		
//         list<int>::iterator next = ++current;//保留指针  
//         if (next == numbers.end())  
//             next = numbers.begin();  
// 		
//         --current;  
//         numbers.erase(current);//释放当前第m个位置的元素  
//         current = next;  
#else
		current =numbers.erase(current);//释放当前第m个位置的元素 
		if (current == numbers.end())//  
                current = numbers.begin(); 
#endif
    }  
	
    return *(current);  
}  

// ====================方法2====================  
int LastRemaining_Solution2(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;  
}  

// ====================方法3====================  
int LastRemaining_Solution3(unsigned int n, unsigned int m)  
{  
    if (n < 1 || m < 1)  
        return -1;  
	if (n==1)
	{
		return 0;
	} 
	else
	{
		return (LastRemaining_Solution3(n-1,m)+m) % n ;
	}
//     int last = 0;  
//     for (int i = 2; i <= n; i++)  
//         last = (last + m) % i;  
// 	
//     return last;  
}

int main()  
{  
	
    cout << "---------方法1---------" << endl;  
    int result1 = LastRemaining_Solution1(5, 3);  
    cout << "result: " << result1 << endl;  
    cout << "---------方法2---------" << endl;  
    int result2 = LastRemaining_Solution2(5, 3);  
    cout << "result: " << result2 << endl;  
	cout << "---------方法3---------" << endl;  
	int result3 = LastRemaining_Solution3(5, 3);  
    cout << "result: " << result3 << endl;  
    system("PAUSE");  
    return 0;  
}  

/*
---------方法1---------
result: 3
---------方法2---------
result: 3
---------方法3---------
result: 3
请按任意键继续. . .
*/

 

posted @ 2017-05-03 13:39  sky20080101  阅读(120)  评论(0)    收藏  举报