题目
用单向环形链表描述约瑟夫环并呈现整个自杀过程。详细题目见原书。
要求
- 输入:一个环形单向链表头节点head和报数的值m
- 返回:最后生存下来的节点,并且这个节点自己组成环形单向链表,其他节点都删除;
- 进阶:如果链表节点数位N,要求在时间复杂度*O(N)*内完成原问题的要求。
代码
#include<iostream>
using namespace std;
struct node {
int value;
node* next;
node(int val)
{
value = val;
}
};
node* createListCircle(int* in, int len)
{
node* head = new node(in[0]);
node* p = head;
for (int i = 1; i < len; i++)
{
node* pNode = new node(in[i]);
p->next = pNode;
p = p->next;
}
p->next = head;
return head;
}
void printList(node* head)
{
if (head == NULL)
cout << "NULL" << endl;
cout << "Whole list:" << endl;
while (head != NULL)
{
cout << head->value << " ";
head = head->next;
}
cout << endl;
}
/*解法1,时间复杂度为O(mn)*/
node* josephusKill1(node* head, int m)
{
if (head == NULL || head->next == head || m < 1)
return head;
node* last = head;
while (last->next != head)
last = last->next;
int count = 0;
while (head != last)
{
if (++count == m)
{
last->next = head->next;
count = 0;
}
else
last = last->next;
head = last->next;
}
return head;
}
int getLive(int i, int m)
{
if (i == 1)
return 1;
return (getLive(i - 1, m) + m - 1) % i + 1;
}
/*解法2:适用于当仅需要求解最后一个剩下的数字的序号时
推导得到的递推公式num(i) = (num(i-1)+m-1)%i + 1*/
node* josephusKill2(node* head, int m)
{
if (head == NULL || head->next == head || m < 1)
return head;
node* cur = head->next;
int tmp = 1;
while (cur != head)
{
tmp++;
cur = cur->next;
}
tmp = getLive(tmp, m);
while (--tmp != 0)
head = head->next;
head->next = head;
return head;
}
/**************数组模拟整个环的过程(剑指offer)*************/
int LastRemaining_Solution(int n, int m)
{
if (n < 1 || m < 1)
return -1;
int* res = new int[n];
for (int i = 0; i < n; i++)
res[i] = 1;
int count = n;
int i = -1; //i = -1这一点
int step = 0;
while (count > 0)
{
i++;
if (i >= n)
i = 0;
if (res[i] == 0)
continue;
step++;
if (step == m)
{
step = 0;
res[i] = 0;
count--;
}
}
return i;
}
/********************************************/
int main()
{
int input[] = { 1, 2, 3, 4, 5 };
int len = 5;
node* p1 = createListCircle(input, len);
node* p2 = createListCircle(input, len);
node* res1 = josephusKill1(p1, 3);
node* res2 = josephusKill2(p2, 3);
cout << res1->value << endl;
cout << res2->value << endl;
getchar();
return 0;
}
/*使用递推公式的解法可以达到时间复杂度为*O(N)*,但只使用于只需得到最后
一个存活的人的序号时使用。使用链表模拟整个过程使得整体的时间复杂度
为*O(MN)*,可以得到整个过程的全部序号;使用数组模拟整个过程的时间复杂度仍为*O(MN)*,不过貌似更加简洁*/