笔试算法题(11):Josephus环 & Fibonacci序列
2014-05-19 09:30
211 查看
出题:Josephus Cycle,约瑟夫环问题。k个数字连成一个环,第一个数字为1。首先从1开始计数删除第m个数字;然后从上次被删除的数字的下一个数字开始计数,删除第m个数字;重复进行第二步直到只剩下一个数字;输出最后剩下的一个数字;
分析:
解法1:考虑到问题的特殊性,可以使用哑元素表示删除的元素从而避免由于删除元素带来的额外操作,所以链表实现的话不用考虑删除操作,数组实现的话不用考虑内存移动操作。当然完全可以不适用哑元素,对于链表而言可以节省查找时间,数组的话需要增加数组元素的平移开销;
解法2:直接使用数学推导,设最终剩下的数字为f(k,m),其中(k为所有数字个数,m为跨距),可以推导当k=1时,f(k,m)=0;当k>1时,f(k,m)=[f(k-1,m)+m]%k。具体推导过程可以参考网页:(其实推导过程可以更简单)
http://zhedahht.blog.163.com/blog/static/2541117420072250322938/
解题:
出题:Fibonacci数列定义如下,要求用O(N)的时间找到第n个元素,O(logN)呢
0 n=0
f(n) = 1 n=1
f(n-1)+f(n-2) n>=2
分析:
解法1:如果使用Top Down的分解方式,f(n)=f(n-1)+f(n-2), n>=2,这样下一层需要处理的项变成2n-3,再下一层变成4n-12,6n-17,……,树的总深度为n,时间复杂度为O(N3),此策略最大的缺点在于重复计算;
解法2:如果使用Bottom Up的分解方式,所以BU可以利用n-1和n-2的结果计算n,时间复杂度为O(N),基本满足要求。因此使用递归实现并不一定适合递归形式定义的命题;
解法3:利用矩阵性质:{f(n), f(n-1), f(n-1), f(n-2)}={1, 1, 1, 0}n-1,可以在O(logN)的时间复杂度下求得结果,具体思路请参见:
http://zhedahht.blog.163.com/blog/static/25411174200722991933440/
解题:
分析:
解法1:考虑到问题的特殊性,可以使用哑元素表示删除的元素从而避免由于删除元素带来的额外操作,所以链表实现的话不用考虑删除操作,数组实现的话不用考虑内存移动操作。当然完全可以不适用哑元素,对于链表而言可以节省查找时间,数组的话需要增加数组元素的平移开销;
解法2:直接使用数学推导,设最终剩下的数字为f(k,m),其中(k为所有数字个数,m为跨距),可以推导当k=1时,f(k,m)=0;当k>1时,f(k,m)=[f(k-1,m)+m]%k。具体推导过程可以参考网页:(其实推导过程可以更简单)
http://zhedahht.blog.163.com/blog/static/2541117420072250322938/
解题:
struct Node { int v; Node *next; }; /** * 哑元素为-1 * 简单起见总长度缺省为8,m为指定的跨距 * */ int ListJose(int m) { Node* b1=new Node(); b1->v=1; Node* b2=new Node(); b2->v=2;b1->next=b2; Node* b3=new Node(); b3->v=3;b2->next=b3; Node* b4=new Node(); b4->v=4;b3->next=b4; Node* b5=new Node(); b5->v=5;b4->next=b5; Node* b6=new Node(); b6->v=6;b5->next=b6; Node* b7=new Node(); b7->v=7;b6->next=b7; Node* b8=new Node(); b8->v=8;b7->next=b8; b8->next=b1; Node *current=b1, *temp; int count; while(true) { /** * 每删除一个数字都需要重设count * */ count=1; temp=current->next; /** * 这个循环用于寻找从current开始计数 * 的第m个数 * */ while(true) { if(temp->v != -1) { count++; } if(count == m) break; temp=temp->next; } /** * 此时temp索引的就是需要删除的第m * 个数 * */ temp->v=-1; /** * 这个循环用于寻找被删除元素的下一个元素 * 注意需要是非-1值的节点 * */ temp=temp->next; while(temp->v == -1) { temp=temp->next; } /** * 此时temp索引的就是下一个可计数的元素,但是 * 检查其是否就是current本身,是的话说明已经 * 只有一个元素;否则更新current,进入下一次 * 循环 * */ if(temp == current) break; else current=temp; } return current->v; } /** * 数组的实现与链表类似,不过需要使用%取模操作符使得数组变成循环 * 结构 * */ int ArrayJose(int m) {}
出题:Fibonacci数列定义如下,要求用O(N)的时间找到第n个元素,O(logN)呢
0 n=0
f(n) = 1 n=1
f(n-1)+f(n-2) n>=2
分析:
解法1:如果使用Top Down的分解方式,f(n)=f(n-1)+f(n-2), n>=2,这样下一层需要处理的项变成2n-3,再下一层变成4n-12,6n-17,……,树的总深度为n,时间复杂度为O(N3),此策略最大的缺点在于重复计算;
解法2:如果使用Bottom Up的分解方式,所以BU可以利用n-1和n-2的结果计算n,时间复杂度为O(N),基本满足要求。因此使用递归实现并不一定适合递归形式定义的命题;
解法3:利用矩阵性质:{f(n), f(n-1), f(n-1), f(n-2)}={1, 1, 1, 0}n-1,可以在O(logN)的时间复杂度下求得结果,具体思路请参见:
http://zhedahht.blog.163.com/blog/static/25411174200722991933440/
解题:
double Fibonacci(double n) { double first=0.0; double second=1.0; double current=0.0; for(int i=2;i<=n;i++) { current=first+second; first=second; second=current; } return current; }
相关文章推荐
- 笔试算法题(35):最长递增子序列 & 判定一个字符串是否可由另一个字符串旋转得到
- 笔试算法题(14):整数二进制表示中的1 & 判定栈的push和pop序列是否对应
- 笔试算法题(03):最小第K个数 & 判定BST后序序列
- 笔试算法题(34):从数字序列中寻找仅出现一次的数字 & 最大公约数(GCD)问题
- 笔试算法题(15):-1到N中包含1的数字的个数 & 连续和为N的序列
- 笔试算法题(12):整数的string到int转换 & 两个栈实现队列
- 笔试算法题(13):反转链表 & 左旋转字符串
- 笔试算法题(01):字符串倒置 & 八皇后问题
- 笔试算法题(02):N阶阶乘 & 双向循环链表实现
- JAVA答案整理---->微软等公司数据结构、算法面试笔试题(v_JULY_v博主发布)
- 笔试算法题(22):二分法求旋转数组最小值 & 骰子值概率
- 笔试算法题(10):深度优先,广度优先以及层序遍历 & 第一个仅出现一次的字符
- 【算法11】和为n的连续正数序列
- 笔试算法题(25):复制拥有多个指针的链表 & 判断二元树B是否为A的子树
- Python巧妙实现Fibonacci序列算法
- 笔试算法题(18):常数时间删除节点 & 找到仅出现一次的两个数字
- 笔试算法题(19):判断两条单向链表的公共节点 & 字符集删除函数
- 编程珠玑读书笔记之----->使用线性算法求解连续子序列的最大和
- n个无序整数,已知第i个数在排好序的序列中的位置为j,满足|i-j|<=K,请设计一种排序算法,对该序列进行排序。注:算法时间复杂度为O(nlgn)的得0分,复杂度为O(nk) 的得两分,总分是20分
- 【实现】最大连续子序列和——第7周《算法》课程提到的 google笔试题/浙大研究生复试机试题