题意整理
- 有n和m两个数字。
- 并且约定三种操作,其一是将n加一,其二是将n减一,其三是将n变为自己的平方数。
- 求至少需要操作n多少次,能将其变为m。
方法一(BFS)
1.解题思路
- 首先进行特殊情况的判断,如果n和m都是1,直接返回0;如果n大于m,只能执行减一操作,直接返回n-m。
- 然后初始化一个队列和set集合,队列用于存储每一次n的值,和已经所走的步数step,set集合保证不走重复的路。
- 每一次都判断队首元素的num值是否为m,如果是,则找到了目标路径,返回step,如果不是,则分情况将三种操作对应的分支入队。由于加一操作和平方操作总会使num变大,所以在num小于目标值m时,才执行对应操作。
动图展示:
2.代码实现
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型 表示牛牛的数字
* @param m int整型 表示牛妹的数字
* @return int整型
*/
public int solve (int n, int m) {
//特殊情况判断
if(n==1&&m==1) return 0;
if(n>=m){
return n-m;
}
//初始化队列和set集合
LinkedList<int[]> queue=new LinkedList<>();
Set<Integer> set=new HashSet<>();
queue.offer(new int[]{n,0});
set.add(n);
while(!queue.isEmpty()){
int[] cur=queue.poll();
int num=cur[0];
int step=cur[1];
//如果数字num变为m,则返回对应步数
if(num==m){
return step;
}
//如果set集合没出现num-1,则将num减一加入队列
if(!set.contains(num-1)){
set.add(num-1);
queue.offer(new int[]{num-1,step+1});
}
//如果num小于m并且set集合没出现num+1,则将num加一加入队列
if(num<m&&!set.contains(num+1)){
set.add(num+1);
queue.offer(new int[]{num+1,step+1});
}
//如果num小于m并且set集合没出现num*num,则将num*num加入队列
if(num<m&&!set.contains(num*num)){
set.add(num*num);
queue.offer(new int[]{num*num,step+1});
}
}
return -1;
}
}3.复杂度分析
- 时间复杂度:最坏情况下,全部执行加一操作,所以时间复杂度是
。
- 空间复杂度:最坏情况下,需要额外大小为m-n的队列和set集合,所以空间复杂度是
。
方法二(递归)
1.解题思路
- 递归终止条件:n大于等于m。
- 递归如何推进:若上一层递归在k(m的平方根)处,第一种选择是全部执行加一操作,第二种选择是先从k处平方到对应位置,再执行对应步数的加一或减一操作。比较两种选择哪个步数小,小的那个作为当前层步数。
- 每一层返回什么:返回对应层的步数。
2.代码实现
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型 表示牛牛的数字
* @param m int整型 表示牛妹的数字
* @return int整型
*/
public int solve (int n, int m) {
//如果n大于等于m,直接返回n-m
if(n>=m) return n-m;
//取当前m的平方根
int k=(int)Math.sqrt(m);
//判断平方根下取整和上取整哪一个离m更近,取较近的那一个
if(m-k*k>(k+1)*(k+1)-m){
k++;
}
/*有两种选择,一种是直接全部执行加一操作,另一种是从k处
执行平方操作,再执行加一操作、或减一操作到m*/
int choose1=m-n;
int choose2=solve(n,k)+Math.abs(m-k*k)+1;
return Math.min(choose1,choose2);
}
} 3.复杂度分析
- 时间复杂度:最坏情况下,全部执行加一操作,所以时间复杂度是
。
- 空间复杂度:最坏情况下,需要深度为m-n的递归栈开销,所以空间复杂度是
。

京公网安备 11010502036488号