圆圈中最后剩下的数字
0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例 1:
输入: n = 5, m = 3
输出: 3
示例 2:
输入: n = 10, m = 17
输出: 2
限制:
1 <= n <= 10^5
1 <= m <= 10^6
思路:
拿n=5,m=3为例模拟删除过程,用首尾拼接的方式表示循环数组
第一轮:0 1 2 3 4 0 1 2 3 4,删除2,此时3的下标为(0 + 3) % 5 = 3
第二轮:3 4 0 1 3 4 0 1,删除0,此时3的下标为(1 + 3) % 4 = 0
第三轮:1 3 4 1 3 4,删除4,此时3的下标为(1 + 3) % 3 = 1
第四轮:1 3 1 3,删除1,此时3的下标为(0 + 3) % 2 = 1
第五轮:3,此时3的下标为0
因为每轮循环都以被删除的节点的下一个节点作为头节点,所以从一轮循环到下一轮循环就相当于把所有节点的下标往前移动3个单位,反过来就是从一轮循环推导前一轮就相当于把所有节点的下标往后移动3个单位,所以可以通过安全的节点最后的下标依次推导出刚开始的下标
注意:为了避免越界,每次求下标都需要modmod上一轮数组的长度
时间复杂度 O(n)
class Solution {
public:
int lastRemaining(int n, int m) {
int res = 0;
for (int i = 2; i <= n; i ++)
{
res = (res + m)%i;
}
return res;
}
};
抓住那头牛
农夫知道一头牛的位置,想要抓住它。
农夫和牛都位于数轴上,农夫起始位于点 N,牛位于点 K。
农夫有两种移动方式:
- 从 XX移动到 X−1 或 X+1,每次移动花费一分钟
- 从 X 移动到 2∗X,每次移动花费一分钟
假设牛没有意识到农夫的行动,站在原地不动。
农夫最少要花多少时间才能抓住牛?
输入格式
共一行,包含两个整数N和K。
输出格式
输出一个整数,表示抓到牛所花费的最少时间。
数据范围
0≤N,K≤1050≤N,K≤105
输入样例:
5 17
输出样例:
4
思路:
算法
广度优先搜索(深度优先搜索)
bfs:
特判:若终点小于起点只有倒退一种走法,直接输出差值。
常规:开两队列,分别储存到达的点和最短到达的时间。
(可用book数组记录访问过的值,避免一个数被重复压入队列)
dfs:
同理上。
此题上性能不如bfs好,故不推荐。
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
int n,m;
int g[100010]={};
int check(int x,int y){//两种情况判断
if(x==1) return x;
return y;
}
void bfs(){
queue<int> ans;
queue<int> qx;
qx.push(n);
ans.push(0);
while(!qx.empty()){
for(int i=1;i<=2;i++){
int tx=qx.front()+check(i,qx.front());
if(tx>=0 && tx<m){//判断边界
qx.push(tx);//满足就压入
ans.push(ans.front()+1);
}
if(tx==m){//到达终点直接输出并返回
int k=ans.front()+1;
cout<<k;//输出结果
return;
}
}
qx.pop(),ans.pop();
}
}
int main(){
cin>>n>>m;
if(m<=n) cout<<n-m;//首先特判起点和终点我位置关系,先解决起点小于终点的简单情况
else bfs();
return 0;
}