每日一题14:数组与链表组合方案下的Josephus问题

愚人节与自己开了个很大的玩笑,几天没写程序,今天继续!Josephus问题是说N个人围成一个圈传热土豆,先约定一个数M,当传递了M次的时候拿着土豆的人出局,然后将土豆给出局人的下一个人,游戏继续,直到最后只剩下一个人,求出局人的序列(按出局顺序排列)。

这个问题可以用数组实现,但是需要标记代表出局人的元素,并且没遍历一个元素就要检查该元素是否已被标记为出局,这样程序运行时间必然会变慢。另一种方式是使用一个链表,每次把出局的节点删除掉。这样的解决方案非常直观,只需要关注链表中的节点,因为在链表中的节点就是没有出局的。删除节点只是指针的调整,非常迅速,但是释放删除的节点占用的空间会比较费时,当输入N很大时会占用大量的时间。所以采用一种链表与数组结合的方式,可以克服两种方式的缺点。

结合的方式就是把链表放在一个数组中!初始时,每个元素的next指针指向数组的下一个元素,最后一个指向第一个(我们需要的是一个循环链表)。这样我们就可以实现在数组中跳跃性的访问而不必关心访问的节点是否是被标记为出局,最后只要一次性释放掉数组所占用的空间就好了,不用管链表节点的释放!

#include "stdafx.h"
#include <iostream>

using namespace std;

struct person
{
    int id;
    person* next;
};

struct person_list
{
    int count;
    person* first;
    person* last;
};

person_list* init(int n)
{
    person* p = new person[n];
    for (int i = 0; i < n - 1; ++i)
    {
        p[i].id = i + 1;
        p[i].next = &p[i+1];
    }
    p[n - 1].id = n;
    p[n - 1].next = &p[0];
    person_list* persons = new person_list;
    persons->count = n;
    persons->first = p;
    persons->last = &p[n - 1];
    return persons;
}

int* solve(int n,int m)
{
    if(n < 1 || m < 0) return NULL;
    person_list* persons = init(n);
    person* first = persons->first;
    person* t = first;
    int count = persons->count;
    int *losers = new int[n];
    int j = 0;
    while(count > 1)
    {
        person* q = NULL;
        for (int i = 0; i < m; ++i)
        {
            q = first;
            first = first->next;
        }
        if(first == persons->first)
        {
            persons->first = first->next;
            persons->last =  persons->first;
        }
        else if(first == persons->last)
        {
            q->next = first->next;
            persons->last = q;
        }
        else
        {
            q->next = first->next;
        }
        --count;
        losers[j++] = first->id;
        first = first->next;
    }
    losers[j] = persons->first->id;
    delete []t;
    delete persons;
    return losers;
}

int _tmain(int argc, _TCHAR* argv[])
{
    int n = 5, m = 1;
    int* losers = solve(n,m);
    for (int i = 0; i < n; ++i)
    {
        cout<<losers[i]<<‘ ‘;
    }
    cout<<endl;
    delete[]losers;
    return 0;
}

程序中losers数组的最后一个元素保存的是最后胜利的人,之前才是出局人序列。

生活中许多事情也像写程序,哪里不会出点bug呢,但是bug总会被修复的不是吗?

时间: 2024-10-08 06:49:34

每日一题14:数组与链表组合方案下的Josephus问题的相关文章

【算法题 14 LeetCode 147 链表的插入排序】

算法题 14 LeetCode 147 链表的插入排序: 解题代码: # Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None class Solution(object): def insertionSortList(self, head): """ :type head: ListNode

&#8203;老男孩教育每日一题-第62天-统计/var/log/下所有文件个数

统计/var/log/下所有文件个数 题目解析: 1./var/log/下所有文件包括当前目录和子目录以及子目录的子目录下面的文件 2.linux下文件有很多类型,包括 普通文件.链接文件.字符设备文件.块设备文件.socket文件等 以下给出三种方法与大家分享 [[email protected] ~]# find /var/log/ ! -type d |wc -l 74 [[email protected] ~]# ll -R /var/log/ |egrep "^[sl-][rwx-]{

每日一题之LeetCode237删除链表中的节点876链表的中间节点

237class ListNode:def init(self, x):self.val = xself.next = None class Solution:def deleteNode(self, node):""":type node: ListNode:rtype: void Do not return anything, modify node in-place instead.""" node.val=node.next.val no

C语言每日一题之No.1

鉴于在学校弱弱的接触过C,基本上很少编程,C语言基础太薄弱.刚好目前从事的是软件编程,难度可想而知.严重影响工作效率,已无法再拖下去了.为此,痛下决心恶补C语言.此前只停留在看书,光看好像也记不住,C这东西毕竟是练出来的,所以从今天开始,每日一道C语言题目,从题目入手来补知识漏洞.题目比较基础,如不堪入目,还请见谅. 题目:输入三个整数,输出最大的数 思路:定义三个变量用来存储输入的整数 比较三个变量的大小,找到最大的数 定义一个变量存储来存储最大的数 程序: 1 #include <stdio

C语言每日一题之No.8

正式面对自己第二天,突然一种强烈的要放弃的冲动,在害怕什么?害怕很难赶上步伐?害怕这样坚持到底是对还是错?估计是今天那个来了,所以身体激素有变化导致情绪起伏比较大比较神经质吧(☆_☆)~矮油,女人每个月总有这么几天的....晚上闺蜜打电话来,共同探讨了作为单身女性身在一线城市的生活,互相安慰互相关心,心里一下子就温暖了许多.总在这个时候,你会觉得,这个冷静的城市里你不是一个人在行走,还有另一颗心牵挂着你.嘿嘿,回来该学习还学习.现在不管坚持是对的还是错的,你都踏上了研发这条不归路,那就一条黑走到

老男孩教育每日一题-第69天-shell脚本知识点:linux系统脚本中trap信号都有哪些,如何进行使用?

题目 shell脚本知识点:linux系统脚本中trap信号都有哪些,如何进行使用? 参考答案: [trap信号命令说明] trap命令用于指定在接收到信号后将要采取的行动,trap命令的一种常见用途是在脚本程序被中断时完成清理工作.历史上,shell总是用数字来代表信号,而新的脚本程序应该使用信号的名字,它们保存在用#include命令包含进来的signal.h头文件中,在使用信号名时需要省略SIG前缀.可以在命令提示符下输入命令trap -l来查看信号编号及其关联的名称. [trap信号命令

找出数组中所有组合中最大的值

面试中,经常有算法题: 比如找出一个数组中的所有组合,并找出最大的值. 代码如下: 1 package com.company.algorithm; 2 3 /** 4 * 选择数组中和的值最大的一组,例如:[2,-7,5,-9],组大的一组是:2,-7,5值为0 5 */ 6 public class SelectValueMaxGroup { 7 public static void main(String[] args) { 8 int[] list = {6, -1, 2, -9, 4,

老男孩教育每日一题-第126天-通过shell脚本打印乘法口诀表

问题背景: 生成9*9乘法表 [[email protected] ~]# seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}' 1x1=1 1x2=2   2x2=4 1x3=3   2x3=6   3x3=9 1x4=4   2x4=8   3x4=12  4x4=16 1x5=5

老男孩教育每日一题-2017年5月17日-使用三剑客进行变化格式

1.题目 原始数据: 17/Apr/2015:09:29:24 +0800 17/Apr/2015:09:30:26 +0800 17/Apr/2015:09:31:56 +0800 18/Apr/2015:09:34:12 +0800 18/Apr/2015:09:35:23 +0800 19/Apr/2015:09:23:34 +0800 19/Apr/2015:09:22:21 +0800 20/Apr/2015:09:45:22 +0800 期望结果: 2015-04-17 09:29: