一些认识:

一些认识:

约瑟夫问题

牛客网-程序员代码面试指南-环形链表的约瑟夫问题(进阶)-CD110

难度:⭐⭐⭐

自己解决程度:之前在Leetcode上看见过,这次做的时候花了好多时间想了起来。

关键词:数学

容易想到的是直接通过环形链表模拟,时间复杂度为O(mn),n是链表上的人数,m是报数的大小。如果想要找一个时间复杂度为O(n)的方法,这里主要用到的是数学推理。通过已知最后剩下的人一定位于最后一行的第一列,反推其位于上一行的哪一列,直到第一行。具体的例子在代码下面的注释中已经给出。

int main(void){
    // 处理输入
    int n, m;
    cin >> n >> m;
    cin.get(); 	// 别忘了吃掉这个回车

    int posi = 1;
    for(int i = 2; i <= n; i++){
        int delta = m;
        if(m >= i) delta = m % i;
        posi = posi + delta;
        if(posi > i) posi = posi % i;
    }
    cout << posi;
    return 0;
}

/* 下面有一个例子:
 * n = 7, m = 3
 * 1 2 (3) 4 5 6 7          4 位于第4列:因为这里3%7=3,所以删掉的是第3列,1+3=4,1是下面行的位置1,3是3%7的3
 * 4 5 (6) 7 1 2            4 位于第1列:因为这里3%6=3,所以删掉的是第3列,4+3=7,7%6=1,4是下面行的位置4,3是3%6的3
 * 7 1 (2) 4 5              4 位于第4列:因为这里3%5=3,所以删掉的是第3列,1+3=4,1是下面行的位置1,3是3%5的3
 * 4 5 (7) 1                4 位于第1列:因为这里3%4=3,所以删掉的是第3列,2+3=5,5%4=1,2是下面行的位置2,3是3%4的3
 * 1 4 (5)                  4 位于第2列:因为这里3%3=0,因为没有第0行,要加3,所以删掉的是第3列,2+0=2 2是下面行的位置2,0是3%3的0
 * 1 4 (1)                  4 位于第2列:因为这里3%2=1,所以删掉的是第1列,1+1=2 一个1是下面行的位置1,一个1是3%2的1
 * 4 4 (4)                  4 位于第1列:这里是已知的
 */