腾讯提前批笔试题-1-圆桌会议

腾讯提前批笔试题1–圆桌会议

题目描述:

  有n个人围坐在一个圆桌周围进行一场圆桌会议。会议开始前从第s个人开始报数,数到第m的人就出列退出会议,然后从出列的下一个人重新开始报数,数到第m的人又出列,…,如此重复直到所有人全部出列为止。现在希望你能够求出按退出会议次序得到的人员的序号序列。
  输入描述:三个正整数n, s, m,均小于10000。
  输出描述:退出会议次序序号,一行一个。

相似题目:剑指offer50题(孩子们的游戏(圆圈中最后剩下的数))

题目描述:

  每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

简洁描述:

  0,1,…,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。(约瑟夫环问题)

解决方案1:维护一个环形链表

  时间复杂度o(mn),空间复杂度o(n)

解决方案2:寻找递推公式

  1. 定义一个关于n和m的方程f(m, n),表示每次在n个数字(0,1,…,n-1)中删除第m个数字后剩下的数字。
  2. 第一个被删除的数字是(m-1)%n,设为k。
  3. 剩下的n-1个数字为:0,1,…,k-1,k+1,…,n-1;将下次起始的k+1排在最前面得到k+1,…,n-1,0,1,…,k-1,该序列最后剩下的数字也是关于n和m的函数,但因序列的起始位置不同而与最初的序列不同,所以用方程记为g(n-1,m)。
  4. 显然,两个序列删除后剩余的数字是一样的,即f(n,m)=g(n-1,m)。
  5. 将k+1,…,n-1,0,1,…,k-1映射为0,…,n-2的序列,映射关系记为p,则p(x)=(x-k-1)%n,逆映射p^(-1)(x)=(x+k+1)%n。
  6. 映射后的序列与最初系列有相同的形式,可得g(n-1,m)=p^(-1)[f(n-1,m)]=[f(n-1,m)+k+1]%n
  7. 因g(n-1,m)=f(n,m),k=(m-1)%n,可得f(n,m)=[f(n-1,m)+(m-1)%n+1]%n
  8. 书上得到的最后的递推公式为f(n,m)=[f(n-1,m)+m]%n,但是目前还没有想通转化方法。
const LastRemaining_Solution = (n, m) => {
    if(n <= 0 || m <= 0) return -1
    if(n === 1) return 0;
    let result = 0;
    for(let i = 2; i <= n; i++){
        result = (result + (m - 1) % i + 1) % i;
    }
    return result
};

  时间复杂度o(n),空间复杂度o(1)

原题目解决方案

  由于需要知道过程的量,因此只能需求复杂度更高的方法,记录过程,提供一种递归的方法的结果。

const a = 10;
const b = 5;
const c = 3 % a;

const main = (n, m, s) => {
    const array = [];
    const result = [];
    for(let i = 0; i < n; i++){
        array.push(i);
    }
    helper(s - 1);
    console.log(result);
    function helper(start) {
        if(array.length === 0) return;
        let len = array.length;
        let pos = (start + m - 1) % len;
        result.push(array[pos]);
        array.splice(pos, 1);
        helper(pos);
    }
};

main(a, b, c);

你可能感兴趣的:(算法题)