JZ-C-45

剑指offer第四十五题:圆圈中最后剩下的数字:0,1,..,n-1这n个数排成一个圆圈,从数字0开始每次从圆圈中删除第m个数字。求出圆圈中剩下的最后一个数字(约瑟夫环★)

  1 //============================================================================
  2 // Name        : JZ-C-45.cpp
  3 // Author      : Laughing_Lz
  4 // Version     :
  5 // Copyright   : All Right Reserved
  6 // Description : 圆圈中最后剩下的数字:0,1,..,n-1这n个数排成一个圆圈,从数字0开始每次从圆圈中删除第m个数字。求出圆圈中剩下的最后一个数字(约瑟夫环★)
  7 //============================================================================
  8 
  9 #include <iostream>
 10 #include <stdio.h>
 11 #include <list>
 12 using namespace std;
 13 
 14 // ====================方法1====================
 15 /**
 16  * 使用环形链表模拟圆圈,这里用模板库的std::list模拟环形链表,当迭代器扫描到链表末尾时候,将迭代器移到链表的头部
 17  * 每删除一个数字都需要m步运算,共n个数字,所以时间复杂度为O(m*n),并且还需要一个辅助链表模拟圆圈,所以空间复杂度为O(n)
 18  */
 19 int LastRemaining_Solution1(unsigned int n, unsigned int m) {
 20     if (n < 1 || m < 1)
 21         return -1;
 22     unsigned int i = 0;
 23 
 24     list<int> numbers;
 25     for (i = 0; i < n; ++i)
 26         numbers.push_back(i);
 27 
 28     list<int>::iterator current = numbers.begin();
 29     while (numbers.size() > 1) {
 30         for (int i = 1; i < m; ++i) { //m也可以为1
 31             current++;
 32             if (current == numbers.end()) //当迭代器扫描到链表末尾时候,将迭代器移到链表的头部
 33                 current = numbers.begin();
 34         }
 35 
 36         list<int>::iterator next = ++current;
 37         if (next == numbers.end()) //当迭代器扫描到链表末尾时候,将迭代器移到链表的头部
 38             next = numbers.begin();
 39 
 40         --current;
 41         numbers.erase(current);
 42         current = next;
 43     }
 44 
 45     return *(current);
 46 }
 47 
 48 // ====================方法2====================
 49 /**
 50  * n>1时:f(n,m) = [f(n-1,m)+m]%n;
 51  * n=1时:f(n,m) = 0;
 52  * 这种算法的时间复杂度为O(n),空间复杂度为O(1)
 53  * 求解释!!!★★★
 54  */
 55 int LastRemaining_Solution2(unsigned int n, unsigned int m) {
 56     if (n < 1 || m < 1)
 57         return -1;
 58 
 59     int last = 0;
 60     for (int i = 2; i <= n; i++)
 61         last = (last + m) % i;
 62 
 63     return last;
 64 }
 65 
 66 // ====================测试代码====================
 67 void Test(char* testName, unsigned int n, unsigned int m, int expected) {
 68     if (testName != NULL)
 69         printf("%s begins: 
", testName);
 70 
 71     if (LastRemaining_Solution1(n, m) == expected)
 72         printf("Solution1 passed.
");
 73     else
 74         printf("Solution1 failed.
");
 75 
 76     if (LastRemaining_Solution2(n, m) == expected)
 77         printf("Solution2 passed.
");
 78     else
 79         printf("Solution2 failed.
");
 80 
 81     printf("
");
 82 }
 83 
 84 void Test1() {
 85     Test("Test1", 5, 3, 3);
 86 }
 87 
 88 void Test2() {
 89     Test("Test2", 5, 2, 2);
 90 }
 91 
 92 void Test3() {
 93     Test("Test3", 6, 7, 4);
 94 }
 95 
 96 void Test4() {
 97     Test("Test4", 6, 6, 3);
 98 }
 99 
100 void Test5() {
101     Test("Test5", 0, 0, -1);
102 }
103 
104 void Test6() {
105     Test("Test6", 4000, 997, 1027);
106 }
107 
108 int main(int argc, char** argv) {
109     Test1();
110     Test2();
111     Test3();
112     Test4();
113     Test5();
114     Test6();
115     return 0;
116 }