[Daily Practice] -约瑟夫环问题

问题描述

0,1,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
该题目来源于leetcode,点击进入

读题

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

解法一

比较直观的解法

public int lastRemaining(int n, int m) {
        LinkedList<Integer> list = new LinkedList<>();
        // 全部加进去
        for (int i = 0; i < n; i++) {
            list.add(i);
        }
        // 只要链表长度不为 1,就不断循环
        while (list.size() != 1) {
            for (int i = 0; i < m; i++) {
            	// 取出第一个元素并删除
                Integer pre = list.pollFirst();
                if (i != m - 1) {
                	// 如果不是第m个,就加到末尾
                    list.add(pre);
                }
            }
        }
        return list.pollFirst();
}

解法二

首先,我们设定n个数值中不断删除m位,最后得到的值为f(n,m)
第一次删掉的数字为(m-1)%n 记做x
那么剩下的n-1个数字就变成了(此处假设n大于2)

0 1 x-1 x+1 n-1

因为需要从被删掉的数字后面一位重新计数,我们把X+1放到首位,从新排列后的数字顺序为

原始数组 对应顺序位置
x+1 0
x+2 1
n-1 n-x-2
0 n-x-1
x-1 n-2

为什么0对应的位置是n-x-1?
我们第一步的时候删除了一个数字,可以理解成把这个链表分成了两部分,
第一部分的长度为x(因为是从0开始的),
那么第二部分的长度就为 n-x-1
现在把第一部分拼接到第二部分的后面,
那么第一分部的第一个数,也就是0,就变成了n-x-1+1个数字,也就是n-x个数字,因为是从0开始的,所以对应的就是n-x-1
关键点:
假设对应的顺序位置为A,原始数值为B
那么顺序位置A与数值B的关系我们可以得出公式:

B = (A+x+1) mod n

由最初的定义可以得到:
n-1个数字中不断删除第m个,最后得到的值为f(n-1,m)
从我们上面的公式可以反推回它的值为(f(n-1,m)+x+1)%n
这个值也就是我们开始定义的f(n-1,m)
x=(m-1)%n代入简化可得:

f(n,m)=f(n−1,m)+m) mod n,且f(1,m) = 0

代码实现

 public static int lastRemaining(int n, int m) {
        return n == 1 ? 0 : (lastRemaining(n-1,m) + m) % n;
    }

或者

public int lastRemaining(int n, int m) {
    int flag = 0;   
    for (int i = 2; i <= n; i++) {
        flag = (flag + m) % i;
    }
    return flag;
}
发布了26 篇原创文章 · 获赞 6 · 访问量 2933

猜你喜欢

转载自blog.csdn.net/weixin_45676630/article/details/105211561