【编程题目】n 个数字(0,1,…,n-1)形成一个圆圈,从数字 0 开始

第 18 题(数组):
题目:n 个数字(0,1,…,n-1)形成一个圆圈,从数字 0 开始,
每次从这个圆圈中删除第 m 个数字(第一个为当前数字本身,第二个为当前数字的下一个
数字)。当一个数字删除后,从被删除数字的下一个继续删除第 m 个数字。
求出在这个圆圈中剩下的最后一个数字。

思路:看到这道题,直觉是不难,模拟一下过程就好了。我用的是数组来表示的,用first表示当前第一个数字是哪一个数,若删除一个数字则将后面的数字平移到前面。

/*
第 18 题(数组):
题目:n 个数字(0,1,…,n-1)形成一个圆圈,从数字 0 开始,
每次从这个圆圈中删除第 m 个数字(第一个为当前数字本身,第二个为当前数字的下一个
数字)。当一个数字删除后,从被删除数字的下一个继续删除第 m 个数字。
求出在这个圆圈中剩下的最后一个数字。
start time = 10:38
end time = 11:30
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int findlast(int * n, int len, int m, int first) // n是输入数字的数组 len是输入数字的长度 m是要删除第几个数字 first是第一个数字是第几个数字
{
    if(len == 1)
    {
        return n[0];
    }
    else
    {
        int d = (m % len) + first - 1;
        for(int i = d - 1; i < len - 1; i++)
        {
            n[i] = n[i + 1];
        }
        return findlast(n, len - 1, m, d %(len - 1));
    }
}

int findlastn(int n, int m)
{
    int * num = (int *)malloc(sizeof(int) * n);
    for(int i = 0; i < n; i++)
    {
        num[i] = i;
    }
    return findlast(num, n, m, 1);
}

int main()
{

    int ans = findlastn(5, 7);

    return 0;
}

上网找答案,发现这是一个很经典的问题 约瑟夫环。有模拟O(MN)、数学O(N)两种常见方法。

网上的模拟都是用的循环链表:

来源http://www.cnblogs.com/dartagnan/archive/2011/09/16/2179143.html



int LastRemaining_Solution1(unsigned int n, unsigned int m)   

{   

      // invalid input   

      if(n < 1 || m < 1)   

            return -1;   

      unsigned int i = 0;   

      // initiate a list with n integers (0, 1, ... n - 1)   

       list<int> integers;   

      for(i = 0; i < n; ++ i)   

             integers.push_back(i);   

       list<int>::iterator curinteger = integers.begin();   

      while(integers.size() > 1)   

       {   

            // find the mth integer. Note that std::list is not a circle   

            // so we should handle it manually   

            for(int i = 1; i < m; ++ i)   

             {   

                   curinteger ++;   

                  if(curinteger == integers.end())   

                         curinteger = integers.begin();   

             }   

            // remove the mth integer. Note that std::list is not a circle   

            // so we should handle it manually   

             list<int>::iterator nextinteger = ++ curinteger;   

            if(nextinteger == integers.end())   

                   nextinteger = integers.begin();   

             -- curinteger;   

             integers.erase(curinteger);   

             curinteger = nextinteger;   

       }   

      return *(curinteger);   

}  

///////////////////////////////////////////////////////////////////////

// n integers (0, 1, ... n - 1) form a circle. Remove the mth from 

// the circle at every time. Find the last number remaining 

// Input: n - the number of integers in the circle initially

//         m - remove the mth number at every time

// Output: the last number remaining when the input is valid,

//          otherwise -1

///////////////////////////////////////////////////////////////////////

int LastRemaining_Solution1(unsigned int n, unsigned int m)

{

      // invalid input

      if(n < 1 || m < 1)

            return -1;

      unsigned int i = 0;

      // initiate a list with n integers (0, 1, ... n - 1)

       list<int> integers;

      for(i = 0; i < n; ++ i)

             integers.push_back(i);

       list<int>::iterator curinteger = integers.begin();

      while(integers.size() > 1)

       {

            // find the mth integer. Note that std::list is not a circle

            // so we should handle it manually

            for(int i = 1; i < m; ++ i)

             {

                   curinteger ++;

                  if(curinteger == integers.end())

                         curinteger = integers.begin();

             }

            // remove the mth integer. Note that std::list is not a circle

            // so we should handle it manually

             list<int>::iterator nextinteger = ++ curinteger;

            if(nextinteger == integers.end())

                   nextinteger = integers.begin();

             -- curinteger;

             integers.erase(curinteger);

             curinteger = nextinteger;

       }

      return *(curinteger);

}

 

数学方法很有启发性,从后向前推倒。把最后剩下的数字依次回推到最开始的值

过程http://www.360doc.com/content/12/0314/13/1429048_194255548.shtml

代码:http://www.cnblogs.com/dartagnan/archive/2011/09/16/2179143.html

int LastRemaining_Solution2(int n, unsigned int m)   

{   

      // invalid input   

      if(n <= 0 || m < 0)   

            return -1;   

      // if there are only one integer in the circle initially,   

      // of course the last remaining one is 0   

      int lastinteger = 0;   

      // find the last remaining one in the circle with n integers   

      for (int i = 2; i <= n; i ++)    

             lastinteger = (lastinteger + m) % i;   

      return lastinteger;   

} 

【编程题目】n 个数字(0,1,…,n-1)形成一个圆圈,从数字 0 开始

时间: 2024-10-10 16:00:32

【编程题目】n 个数字(0,1,…,n-1)形成一个圆圈,从数字 0 开始的相关文章

18.n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始, 每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。 当一个数字删除后,从被删除数字的下一个继续删除第m个数字。 求出在这个圆圈中剩下的最后一个数字。

转载请注明出处:http://www.cnblogs.com/wuzetiandaren/p/4263868.html 声明:现大部分文章为寻找问题时在网上相互转载,此博是为自己做个记录记录,方便自己也方便有类似问题的朋友,本文的思想也许有所借鉴,但源码均为本人实现,如有侵权,请发邮件表明文章和原出处地址,我一定在文章中注明.谢谢. 题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始, 每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字). 当一个数字

华为 2015 机试 输出:数字后面的连续出现的(2个或多个)相同字符(数字或者字符),删去一个,非数字后面的不要删除,例如,对应输出为:33aabb55pin。

1 package 华为机试; 2 //C++ 输入:由数字和字母组成的字符串,例如:333aaabb55ppin 3 //输出:数字后面的连续出现的(2个或多个)相同字符(数字或者字符),删去一个,非数字后面的不要删除,例如,对应输出为:33aabb55pin. 4 5 //这句话的核心就是在字符串删除一些字符,感觉处理很复杂,删除哪些字符呢?我们观察发现, 本字符串中删除了一个3,一个a,一个p,满足的规则是啥呢? 333中删除最后一个3,3aa删除了一个a,5pp中删除一个p, 6 //规

【目录】编程题目

编程题目 如何对n个数进行排序,要求时间复杂度O(n),空间复杂度O(1) 一个数组是由一个递减数列左移若干位形成的,在这种数组中查找某一个数.☆ 请修改 append 函数,利用这个函数实现两个非降序链表的并集 一串首尾相连的珠子(m 个),有 N 种颜色(N<=10),取出其中一段,要求包含所有 N 中颜色,并使长度最短. 求一个有向连通图的割点,割点的定义是,如果除去此节点和与其相关的边, 有向图不再连通 有 n 个长为 m+1 的字符串,如果某个字符串的最后 m 个字符与某个字符串的前

【编程题目】输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。

第 14 题(数组):题目:输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字.要求时间复杂度是 O(n).如果有多对数字的和等于输入的数字,输出任意一对即可.例如输入数组 1.2.4.7.11.15 和数字 15.由于 4+11=15,因此输出 4 和 11. 要求时间是O(n)肯定就只能扫描一遍. 又有两个数字要找,那就只能一个从头向后找 一个从后向前找 初始把大值设为最后一个数, 小值设为第一个数,如果数字和大于和,则减小大数的数值, 反之增大小

【编程题目】找出数组中两个只出现一次的数字 ★★(自己没做出来)

61.找出数组中两个只出现一次的数字(数组)题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度是 O(n),空间复杂度是 O(1). 思路:瞄到了一眼提示,说是位运算. 根据异或的运算性质: a ⊕ b ⊕ a = b 把所有的数字都异或一遍得到的结果就是 那两个只出现一次的数字异或的结果. 可怎么分出那两个数字就卡住了. 看了下网上答案,要根据得到的异或值把数字分为两组,再对每一组异或就可以得到这两个数字了! 代码如下: /* 61

【编程题目】数组中超过出现次数超过一半的数字 ☆

74.数组中超过出现次数超过一半的数字(数组)题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字. 思路:分治算法 两两一对 相同留下一个 不同扔掉 多出来的数字单独对比 /* 74.数组中超过出现次数超过一半的数字(数组) 题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字. */ //思路:分治算法 两两一对 相同留下一个 不同扔掉 多出来的数字单独对比 #include <stdio.h> #include <stdlib.h> int fin

【编程题目】n 支队伍比赛,分别编号为 0,1,2。。。。n-1,已知它们之间的实力对比关系,

36.引用自网友:longzuo(运算)谷歌笔试: 19n 支队伍比赛,分别编号为 0,1,2....n-1,已知它们之间的实力对比关系,存储在一个二维数组 w[n][n]中,w[i][j] 的值代表编号为 i,j 的队伍中更强的一支.所以 w[i][j]=i 或者 j,现在给出它们的出场顺序,并存储在数组 order[n]中,比如 order[n] = {4,3,5,8,1......},那么第一轮比赛就是 4 对 3, 5 对 8........胜者晋级,败者淘汰,同一轮淘汰的所有队伍排名不

【编程题目】有两个序列 a,b,大小都为 n,序列元素的值任意整数,无序;(需要回头仔细研究)

32.(数组.规划)有两个序列 a,b,大小都为 n,序列元素的值任意整数,无序:要求:通过交换 a,b 中的元素,使[序列 a 元素的和]与[序列 b 元素的和]之间的差最小.例如: var a=[100,99,98,1,2,3];var b=[1,2,3,4,5,40]; 首先,目标一定是先找到n个数字,使得数字和比总和的一半小,但是最接近. 思路一:开始看这道题跟之前学的动态规划很像,就想用动态规划来解.但是....做不出来........... 必须要选一半的数字让我头都大了. 思路二:

【编程题目】判断整数序列是不是二元查找树的后序遍历结果,如果是,构建该二元查找树

判断整数序列是不是二元查找树的后序遍历结果题目:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果.如果是返回 true,否则返回 false.例如输入 5.7.6.9.11.10.8,由于这一整数序列是如下树的后序遍历结果:8/ \6 10/ \ / \5 7 9 11因此返回 true.如果输入 7.4.6.5,没有哪棵树的后序遍历的结果是这个序列,因此返回 false. 做这个题目的时候最开始傻了,想着从前到后根据数字的大小关系判断.后来幡然醒悟,根据后序遍历的特点.序列最后一