面试题45:圆圈中最后剩下的数字
2015-07-08 11:06
295 查看
题目:0,1,...,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前四个数字一次是2、0、4、1,最后剩下的数字为3.
本题是有名的约瑟夫环问题。
解法一:经典的解法,用环形链表模拟圆圈
如果面试官没有特殊要求,可以用模板库中的list来模拟一个环形链表,而list本身不是一个环形结构,因此每当迭代器扫描到链表末尾的时候,
要记得把迭代器移到链表的头部。
这种思路的时间复杂度为O(MN),空间复杂度为O(N)。
解法二:创新的解法
首先定义一个关于n和m的方程f(n,m),表示每次在n个数字0,1,...,n-1中每次删除第m个数字后最后剩下的数字。经过分析(过程参考《剑指Offer》)得到:
n = 1时,f(n,m) = 0;
n > 1时,f(n,m) = [f(n-1,m)+m]%n;
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前四个数字一次是2、0、4、1,最后剩下的数字为3.
本题是有名的约瑟夫环问题。
解法一:经典的解法,用环形链表模拟圆圈
如果面试官没有特殊要求,可以用模板库中的list来模拟一个环形链表,而list本身不是一个环形结构,因此每当迭代器扫描到链表末尾的时候,
要记得把迭代器移到链表的头部。
int lastRemaining(unsigned int n, unsigned int m) { if (n < 1 || m < 1) return -1; list <int>numbers; for (int i = 0; i < n; ++i) numbers.push_back(i); list<int>::iterator current = numbers.begin(); while (numbers.size() > 1) { for (int j = 1; j < m; ++j) { ++current; if (current == numbers.end()) current = numbers.begin(); } current = numbers.erase(current); if (current == numbers.end()) current = numbers.begin(); } return *current; }
这种思路的时间复杂度为O(MN),空间复杂度为O(N)。
解法二:创新的解法
首先定义一个关于n和m的方程f(n,m),表示每次在n个数字0,1,...,n-1中每次删除第m个数字后最后剩下的数字。经过分析(过程参考《剑指Offer》)得到:
n = 1时,f(n,m) = 0;
n > 1时,f(n,m) = [f(n-1,m)+m]%n;
int lastRemaining(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; }
相关文章推荐
- 大公司最喜欢问的Java集合类面试题
- 面试知识点总结01
- php相关问题学习(以备面试)
- 黑马程序员——OC—类和对象的使用
- [异能程序员]第一章 酒后事发,上头条
- 解析程序员的几个成长阶段
- 对程序员非常重要的24个软技能
- 黑马程序员——Java基础---String
- 黑马程序员---Java基本语法(二)
- 黑马程序员————第十九天
- 也谈论程序员的"尊重"问题
- 20条不得不看的职场哲理漫画
- 黑马程序员————第十八天
- 关于面试的一些小记
- 大话软件测试与职业生涯
- 黑马程序员————第十七天
- 怎么做一个优秀的程序员
- 【剑指Offer学习】【面试题47:不用加减乘除做加法】
- 黑马程序员---OC基础---Foundation框架学习
- 【剑指Offer学习】【面试题45:圆圈中最后剩下的数字(约瑟夫环问题)】