算法学习之圆圈中最后剩下的数字

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

解法一:使用LinkedList仿圆就可以了,很简单

import java.util.*;
public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        if(n<=0||m<=0)return -1;
        LinkedList<Integer> list = new LinkedList();
        for(int i =0;i<n;i++){
            list.add(i);
        }
        int cur = 0;
        while(list.size()>1){
            cur = (cur+m-1)%list.size();
            list.remove(cur);
        }
        return list.getFirst();
    }
}

时间复杂度:O(n)

空间复杂度:O(n)

解法二:使用数学公式递推(动态规划思想)

1、首先定义剩下的数:f(n,m)

2、第一个被删除的数字为s,由解法一我们可以知道s=(m-1)%n

3、当删完s以后,剩下的数字为0,1...,s-1,s+1,...n-2当从s+1处继续开始数m个数,我们以s+1为开头

当前数组排列为:s+1,s+2,  ... 0,     1,       ...s-1

对应映射数组为:0    ,1    ,  ... n-2-s,n-1-s...,n-2

这里设映射数字为x,当前数字为y。y=(x+s+1)%n

在映射的数组中,因为我们定义的n个数最后一个数字为f(n,m),所以在删除了s之后n-1个数字最后一个数为f(n-1,m)

把f(n-1,m)转换成当前数组中的数字即带入上方公式得:(f(n-1,m)+s+1)%n

4、最终我们有第一步定义的f(n,m) = (f(n-1,m)+s+1)%n,把s=(m-1)%n带入可简化为:(取余部分可直接提出,因为一次跟两次效果是一样的)

f(n,m) = (f(n-1,m)+m)%n

当n=1时:f(1,m) = 0

推的是不是很烦!!!看看代码就高兴了,因为很少,哈哈

import java.util.*;
public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        if(n<=0||m<=0)return -1;
        
        // 因为f(1,m) = 0;所以last取0,n从2开始
        // 并且f(n,m) = (f(n-1,m)+m)%n所以循环条件i可以=n
        int last = 0;
        
        for(int i =2;i<=n;i++){
            last = (last+m)%i; // 注意这里除数是i,因为f(n,m)从1开始,f(2,m) = (last+m)%2 ... 
        } 
        return last;
    }
}

时间复杂度:O(n)

空间复杂度:O(1)

练习地址:https://www.nowcoder.com/practice/f78a359491e64a50bce2d89cff857eb6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值