链表类问题,一个比较常用的trick就是逆转链表,时间复杂度为O(n),空间复杂度为O(1) 。
在初始化链表中的节点的时候,无论是单向链表的节点还是双向链表的节点,都要记得初始化它的指针为nullptr,不然可能会因为指针值是一个随意的值而出现意想不到的问题。
难度:⭐⭐⭐
自己解决程度:之前在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列:这里是已知的
*/