題目
從撲克牌中隨機抽5張牌,判斷是不是一個順子,即這5張牌是不是連續的。2~10爲數字本身,A爲1,J爲11,Q爲12,K爲13,而大、小王可以看成任意數字。
思路一
用模板庫中的std::list來模擬一個環形鏈表。由於std::list本身不是一個環形結構,因此每當迭代器掃描到末尾的時候,我們要記得把迭代器移動到鏈表的頭部,這樣就相當於在一個圓圈裏遍歷了。
時間複雜度:O(n * m)
空間複雜度:O(n)
思路二
定義一個關於n和m的方程f(n,m),表示每次在n個數字0,1,…,n-1中每次刪除第m個數字最後剩下的數字。
時間複雜度:O(n)
空間複雜度:O(1)
代碼
#include <iostream>
#include <list>
using namespace std;
// 用list<int>實現約瑟夫環,裏面存放0~n-1 這n個數,每次刪除第m個數
// 返回最後的一個數字
int LastRemaining_A(unsigned n, unsigned m)
{
if (n < 1 || m < 1)
return -1;
unsigned i = 0;
list<int> numbers;
for (i = 0; i < n; ++i)
numbers.push_back(i);
list<int>::iterator current = numbers.begin();
while (numbers.size() > 1)
{
// 尋找第m個數
for (int i = 1; i < m; ++i)
{
current++;
if (current == numbers.end()) // 如果到達尾部,則跳轉到開頭
current = numbers.begin();
}
// 由於list<int>刪除元素時,會使後面迭代器失效
// 則在刪除當前元素前,先保存下一個迭代器next
list<int>::iterator next = ++current;
if (next == numbers.end())
next = numbers.begin();
--current;
numbers.erase(current);
current = next;
}
return *(current);
}
// 利用數學公式解決瑟夫環問題
// f(n,m)表示從0~n-1 這n個數,刪除第m個數後,下次開始的下標
// n=1 : f(n,m) = 0
// n>1 : f(n,m) = [f(n-1,m) + m] % n
int LastRemaining_B(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;
}
int main()
{
int n = 5;
int m = 3;
cout << "the result of method A:" << LastRemaining_A(n, m) << endl;
cout << "the result of method B:" << LastRemaining_B(n, m) << endl;
return 0;
}