丢手帕问题
来源:互联网 发布:mini metro mac破解 编辑:程序博客网 时间:2024/04/28 23:34
最近看到一道经典的题目,就是丢手帕问题。这道题目在多年前曾看到过,但当时有没有看过或者思考过解答,已经完全不记得了。于是从头开始实现。
问题是这样的:有N个小朋友围成一圈,老师让报数,从1报到M。凡是报到M的小朋友站出圈。假设小朋友们的ID从0到N-1,请问最后一个留在圈中的小朋友的ID是多少?
先想用数组,那么为了实现出圈这个操作,就需要把全数组默认值设为1,出圈的位置设为0.这样理论上应该没问题,但增加了对0和1的判断。又想了下,发现刚好可以用环形链表来做:每次出圈只要把相应节点delete掉就可以了,很省事。于是开始写程序。写了一会儿,又重新整理了一下思路,有程序如下:
#include <iostream>using namespace std;struct Node { int value; Node * next;}; Node * createCircleLinkedList(int size) { Node * head = nullptr; Node * previous = head; for (int i=0; i<size; ++i) { Node * tmp = new Node; tmp->value = i; if (i==0) { previous = head = tmp; } else { previous->next = tmp; previous = tmp; if (i == size - 1) { tmp->next = head; } } } return head;}void printCircleLinkedList(Node * head) { if (head == nullptr) return; Node * tmp = head; while (tmp->next != head) { cout << tmp->value << " "; tmp = tmp->next; } cout << tmp->next->value << endl;}int getLastOne(Node * head, int size, int interval) { if (size <= 0) { return 0; } if (size == 1) { return head->value; } if (interval <= 0) { return 0; } if (interval == 1) { return size - 1; } // p1代表当前节点的前一个节点,p2代表当前节点,p3代表当前节点的下一个几点 Node *p1, *p2, *p3; p1 = head; p2 = head->next; p3 = p2->next; // 每次总删除当前节点p2,故当p2是head->next时,相当于报数2了。 // 注意,若interval为1,则直接返回size-1即可。 int count = 2; int result = -1; while (p3->next != p3) { // 循环结束的条件:只剩最后一个节点了,必然是next节点仍是自己。 if (count == interval) { p1->next = p3; cout << "Deleted ID: " << p2->value << endl; delete p2; p2 = p3; if (p3->next != p3) { p3 = p3->next; } else { result = p3->value; delete p3; break; } count = 1; // 做删除后,p2处于下一个位置了,故相当于报数为1了。 } p1 = p2; p2 = p3; p3 = p3->next; count ++; } return result;}void deleteCircleLinkedList(Node * head) { if (head == nullptr) { return; } else if (head->next == head) { delete head; return; } Node *p1, *p2; p1 = head->next; p2 = p1->next; while (p2->next != p2) { cout << "Delete " << p1->value << endl; delete p1; head->next = p2; p1 = p2; p2 = p2->next; } cout << "Delete " << p2->value << endl; delete p2;}int main(){ int size = 20; int interval = 3; Node * head = createCircleLinkedList(size); printCircleLinkedList(head); // deleteCircleLinkedList(head); int lastOne = getLastOne(head, size, interval); cout << "Last One is " << lastOne << endl; return 0;}
执行结果如下:
Deleted ID: 2Deleted ID: 5Deleted ID: 8Deleted ID: 11Deleted ID: 14Deleted ID: 17Deleted ID: 0Deleted ID: 4Deleted ID: 9Deleted ID: 13Deleted ID: 18Deleted ID: 3Deleted ID: 10Deleted ID: 16Deleted ID: 6Deleted ID: 15Deleted ID: 7Deleted ID: 1Deleted ID: 12Last One is 19
这个程序带给我一点点启示:对链表做一些操作的时候,如果写出p1, p2, p3这样的形式,往往对于理清思路比较有好处。除了本程序之外,在本程序中的写出来却并没有被用到的函数deleteCircleLinkedList()也是个例子,它是用来删除一个环形链表的。
1 0
- 丢手帕问题
- 丢手帕问题
- 丢手帕问题
- 【蓝桥杯】【丢手帕问题】
- 丢手帕问题(约瑟夫问题)
- 丢手帕问题-约瑟夫问题
- 丢手帕问题 java实现
- 丢手帕问题 (java实现)
- 丢手帕问题java 实现
- 丢手帕问题java实现
- 丢手帕问题(约瑟夫问题)
- 约瑟夫问题(也叫丢手帕问题)
- JAVA约瑟夫问题(丢手帕问题)
- 丢手帕问题(约瑟夫问题)
- PHP约瑟夫问题,丢手帕问题
- 丢手帕问题(Josephus问题)
- 丢手帕问题 (约瑟夫问题)
- 采用Ruby 实现丢手帕问题
- Dynamics CRM2016 Web API之Retrieve Multiple
- HDU 5646-DZY Loves Partition
- android主界面(ViewPager)
- 贪心 00 1
- JavascriptDOM对象小结
- 丢手帕问题
- python+opencv实现简单的图片搜索功能
- Linux进程管理指令
- Redis常用命令及5种数据类型操作
- Fragment的基本应用
- C++实验2-模拟ATM
- 再谈数据库优化(database tuning)的真谛和误区
- Android--Intent在活动间传递数据
- hdu2825(AC自动机+状态压缩dp)