【leetcode】剑指 Offer 62. 圆圈中最后剩下的数字

题目

题目:

0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

示例 1:

输入: n = 5, m = 3
输出: 3

示例 2:

输入: n = 10, m = 17
输出: 2

限制:

1 <= n <= 105
1 <= m <= 106


补充:

这种问题可以说是约瑟夫环问题


思路-递归

补充一个定理:

  • (a+b)%c=((a%c)+(b%c))%c
  • a%c=(a%c)%c

首先,长度为 n 的序列会先删除第 m % n 个元素,然后剩下一个长度为 n - 1 的序列。那么,我们可以递归地求解 f(n - 1, m),就可以知道对于剩下的 n - 1 个元素,最终会留下第几个元素,我们设答案为 x = f(n - 1, m)

暗含在其中的数学逻辑是:

  • 因为要从0数m个数,那最后肯定落到了下标为m-1的数身上了,但这个下标可能超过我们有的最大下标(n-1)了。所以攒满n个就归零接着数,逢n归零,所以要模n。所以有n个数的时候,我们划掉了下标为(m-1)%n的数字

  • 往后数x+1,它下标肯定变成了(m-1)%n +x+1,和第一步的想法一样,你肯定还是得取模,所以答案为[(m-1)%n+x+1]%n

所以f(n,m)= [(m-1)%n+x+1]%n = (m+x)%n,而且x = f(n - 1, m);
使用递归的思想

class Solution {
    public int lastRemaining(int n, int m) {

    if (n == 1) {
        return 0;
    }

    return (m + lastRemaining(n - 1, m)) % n;

    }  
}

思路-迭代

递归和迭代的思想差不多

class Solution {
    public int lastRemaining(int n, int m) {
        int f = 0;
        for (int i = 2; i != n + 1; ++i) {
            f = (m + f) % i;
        }
        return f;
    }
}

思路-单循环链表

通过循环链表来进行运算

这个算法是网上的算法看来的,还未结合leetcode进行整合
但思路都大同小异,函数名不一样而已

//运用循环单链表的方式实现
private void josephusList(Node first, int n, int m){
    if(n < 1 || m < 1)
        return;
    if(n==1){
        System.out.print(first.data+" ");
    }
    else{
        Node pre = first;  //当前节点的前驱
        Node p = first.next; //当前节点
        int count = 2;
        while(p!=pre){
            if(count==m){
                System.out.print(p.data+" ");
                Node r = p.next;  //删除当前节点
                pre.next = r;
                p=r;
                count = 1;
            }
            else{
                pre = p;
                p = p.next;
                count++;
            }
        }
        System.out.println("\n最后一个删除的元素:"+p.data);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农研究僧

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值