1、整数变换1
给定数字A和B,A<B,A可以进行两种变换,A+=1或者A*=2,也就是A可以加一也可以翻倍,请问,最少多少步A变换到B。
逆向思维:B可以通过B/=2或者B-=1最少的步数得到A,但是B只有是偶数的时候才能B/=2,如果B是奇数,B先减1,然后再B/=2,直到A的值大于B/2的时候,B不能再B/=2,否则B永远无法到A,这个时候只能B一直减减。
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
class Solution {
public:
int convert_num(int a, int b){
int res=0;
while(a<b){
if(a>b/2){
res+=b-a;
break;
}else {
if(b%2==1){
res+=2;
b--;
}else{
res++;
}
b/=2;
}
}
return res;
}
private:
};
int main()
{
Solution so;
int a=2,b=11;
cout<<so.convert_num(a,b)<<endl;
return 0;
}
2、整数变换2
给定数字A和B,A可以进行两种变换,A=A*10+1或者A*=2,也就是A可以乘10加一也可以翻倍,请问,最少多少步A变换到B。
我们可以采用逆向思维,从整数B出发,反向推导到A。这样可能在某些情况下更高效,尤其是当B较大时。允许的逆向操作如下:
- 逆向操作1:若当前数是偶数,则前一步可能是当前数除以2(对应正向的乘以2)。
- 逆向操作2:若当前数减1后能被10整除,则前一步可能是(当前数-1)除以10(对应正向的乘以10加1)。
方法思路
- 初始检查:如果A等于B,直接返回0步。
- 队列初始化:使用队列存储当前数值及其对应的步数,起始点为B,步数为0。
- 访问记录:使用哈希集合记录已访问的数值,避免重复处理。
- 逆向BFS遍历:每次从队列中取出当前数值,生成两种可能的逆向操作:
- 逆向操作1:若当前数为偶数,则生成当前数除以2的结果。
- 逆向操作2:若当前数减1能被10整除,则生成(当前数-1)除以10的结果。
- 目标检查:若生成的数值等于A,返回当前步数加1。
- 边界处理:生成的前驱数值必须大于等于A,否则跳过。
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
using namespace std;
class Solution {
public:
int convert_num(int a, int b){
if(a==b) return 0;
queue<pair<int,int>> q; // 存储当前数字和步数
set<int> visited;
q.push(pair<int,int>(b,0));
visited.insert(b);
int res=-1;
while(!q.empty()){
int step=q.front().second;
int cur=q.front().first;
q.pop();
// 逆向操作1: 当前数是偶数时,尝试除以2
if(cur%2==0){
int next=cur/2;
if(next==a){
if(res!=-1){
res=min(res,step+1);
} else {
res=step+1;
}
}else if(next>=a && visited.find(next)==visited.end()){
q.push(pair<int,int>(next,step+1));
visited.insert(next);
}
}
// 逆向操作2: 当前数减1后能被10整除时,尝试除以10
if((cur-1)%10==0){
int next=(cur-1)/10;
if(next==a){
if(res!=-1){
res=min(res,step+1);
} else {
res=step+1;
}
}else if(next>=a&&visited.find(next)==visited.end()){
q.push(pair<int,int>(next,step+1));
visited.insert(next);
}
}
}
return res;
}
};
int main()
{
Solution so;
int a=2,b=129;
cout<<so.convert_num(a,b)<<endl;
return 0;
}