环形单链表的约瑟夫问题

题目

用单向环形链表描述约瑟夫环并呈现整个自杀过程。详细题目见原书。

要求

  • 输入:一个环形单向链表头节点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)*,不过貌似更加简洁*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值