圓圈中最後剩下的數字
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;
}