LeetCode刷题进阶之圆圈中最后剩下的数字(剑指Offer 62)

一、题目
LeetCode刷题进阶之圆圈中最后剩下的数字(剑指Offer 62)
演示示例:
LeetCode刷题进阶之圆圈中最后剩下的数字(剑指Offer 62)
二、测试代码

//方法一  数组模拟队列
class Solution {
    public int lastRemaining(int n, int m) {
        ArrayList<Integer> list=new ArrayList<>();
        for(int i=0;i<n;i++)//将0到n-1全部放入list中
        {
            list.add(i);
        }
        int index = 0;
        while (n > 1) {//模拟删除固定位置的数字
            index = (index + m - 1) % n;
            list.remove(index);
            n--;
        }
    return list.get(0);//直到list只剩下最后一个元素取出即可
    }
}


//方法二 数学解法
class Solution {
    public int lastRemaining(int n, int m) {
        int ans = 0;//记录最后一个剩余数字的位置
        for (int i = 2; i <= n; i++) // 最后一轮剩下2个人,即从2开始反推
        {
            ans = (ans + m) % i;
        }
        return ans;
    }
}

三、运行情况

方法一:
LeetCode刷题进阶之圆圈中最后剩下的数字(剑指Offer 62)
方法二:
LeetCode刷题进阶之圆圈中最后剩下的数字(剑指Offer 62)
四、刷题总结

本题是典型的约瑟夫环问题

1、方法一的主要思路:我们利用ArrayList将0~n-1存放到其中,再对ArrayList模拟对固定位置数字的删除直到剩余最后一个数字。假设当前删除位置是index,则下一个删除数字位置为index+m。但因为将当前位置的数字删除了,后面的数字会向前移动一位,则实际的下一个删除数字的位置为index+m-1。又因为遍历一遍后会继续从头再次遍历,我们可以采用取模的方法,即(index+m-1) % n.

2、方法二的主要思路:我们以一个实例对n=5,m=3来进行解释.

第一轮为[ 0 ,1,2,3,4 ],即为[ 0,1,2,3,4 ]数组的多个复制,此轮删除2;
第二轮开始时从3 开始,即为[3,4,0,1 ]数组的多个复制,此轮删除0;
第三轮开始时从 1开始,即为[ 1,3,4 ]数组的多个复制,此轮删除4;
第四轮开始从1开始,即为[ 1,3]数组的多个复制,此轮删除1。 即最后剩下的数字为3,下标为0。

现在我们开始反推。

第四轮反推,补上m个位置,在对当时数组长度取模,此时数组长度为2,位置是(0+3)%2=1;
第三轮反推,补上m个位置,在对当时数组长度取模,此时数组长度为3,位置是(1+3)%3=1;
第二轮反推,补上m个位置,在对当时数组长度取模,此时数组长度为4,位置是(1+3)%4=0;
第一轮反推,补上m个位置,在对当时数组长度取模,此时数组长度为5,位置是(0+3)%5=3。

即最终剩下的数组为3。
即为本题的思路,我们采用反推方法,即(当前的index下标+m)%上一轮剩余数字个数,

上一篇:linux shell正则表达式如何匹配域名(包含中文域名)


下一篇:【大话数据结构C语言】62 散列表(哈希表)查找