问题描述
给定两个整数a, b。当处于a时,下一次可以到达的位置有a+1, a-1和2a三种选择,求a到b的最短路径,并输出每一步的值。
问题分析:
每一个可以选择的路径有三种,则a可以到达的位置类似于一个三叉树。如果把相同的值当成同一个节点,则相当于一个有向图。
算法思路1:
有向图的最短路径可以采用BFS算法。
1、使用一个哈希表存储当前已经访问过的节点。
2、从a开始进行广度优先搜索。
3、当前结点值为val,则下三个节点的值为val+1, val-1, 2*val, 若这三个值都不等于b,继续向下搜索,若其中有一个等于b,搜索结束,返回当前节点.
4。从返回的节点向上回溯都根节点,所经过的节点即为所求的路径。
算法实现:
import java.util.*;
public class Main {
public static void main(String[] args){
System.out.println(MinPath(10, 165));
}
public static List<Integer> MinPath(final int a, final int b){
Queue<TreeNode> queue = new LinkedList<TreeNode>();
HashSet<Integer> set = new HashSet<Integer>(100);
queue.add(new TreeNode(a, null));
set.add(a);
TreeNode node = null;
while(!queue.isEmpty()){
node = queue.poll();
if(node.val+1 == b || node.val-1 == b || node.val*2 == b){
break;
}
if(!set.contains(node.val+1)){
queue.add(new TreeNode(node.val+1, node));
set.add(node.val+1);
}
if(!set.contains(node.val-1)){
queue.add(new TreeNode(node.val-1, node));
set.add(node.val+1);
}
if(!set.contains(node.val*2)){
queue.add(new TreeNode(node.val*2, node));
set.add(node.val+1);
}
}
if(queue.isEmpty())
System.out.printf("Can't not find a way from %d to %d\n", a, b);
List<Integer> result = new ArrayList<>();
result.add(b);
while(node != null){
result.add(node.val);
node = node.parent;
}
Collections.reverse(result);
return result;
}
}
class TreeNode{
public int val;
public TreeNode parent;
public TreeNode(int val, TreeNode parent) {
this.val = val;
this.parent = parent;
}
}
优化
当a=10000, b=5000时,上述算法树的深度达到了5000,运行时间和所需内存明显增加。
当ab>0, 且|a| > |b| 时, a到b的最短路径长度为|a-b|
例如a=20, b=10, 则最短路径为20,19,18……12,11,10
a=-10, b=-20,则最短路径为-10, -11, -12……-18,-19,-20
import java.util.*;
public class Main {
public static void main(String[] args){
System.out.println(MinPath(10000, 100000));
}
/**
* 求a到b的最短路径
* @param a
* @param b
* @return a到b的最短路径
*/
public static List<Integer> MinPath(int a, int b){
List<Integer> result = new LinkedList<Integer>();
if(a <= 0 && b <= 0){
if(a <= b){
for(int i=a;i<=b;++i)
result.add(i);
return result;
}
return MinPath2(a, b);
}
if(a > 0 && b > 0){
if(a >= b){
for(int i=a;i<=b;--i)
result.add(i);
return result;
}
return MinPath2(a, b);
}
if(a > b){
for(int i=a;i>0;--i)
result.add(i);
}
else{
for(int i=a;i<0;++i)
result.add(i);
}
//此时变成了0到b的问题
result.addAll(MinPath2(0, b));
return result;
}
/**
* a,b 同号,且abs(a) < abs(b)
* @param a
* @param b
* @return a到b的最短路径
*/
public static List<Integer> MinPath2(int a, int b){
int flag = b > 0? 1:-1;
b=Math.abs(b);
a=Math.abs(a);
final int MAX_FLOOR = 2 * b - a;
List<Integer> result = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<TreeNode>();
HashSet<Integer> set = new HashSet<Integer>();
queue.add(new TreeNode(a, null));
set.add(a);
TreeNode node = null;
while(!queue.isEmpty()){
node = queue.poll();
if(node.val+1 == b || node.val-1 == b || node.val*2 == b){
break;
}
if(node.val+1 < MAX_FLOOR && !set.contains(node.val+1)){
queue.add(new TreeNode(node.val+1, node));
set.add(node.val+1);
}
if(node.val-1 > 0 && !set.contains(node.val-1)){
queue.add(new TreeNode(node.val-1, node));
set.add(node.val+1);
}
if(node.val*2 < MAX_FLOOR && !set.contains(node.val*2)){
queue.add(new TreeNode(node.val*2, node));
set.add(node.val+1);
}
}
if(queue.isEmpty())
System.out.printf("Can't not find a way from %d to %d\n", a, b);
result.add(b*flag);
while(node != null){
result.add(node.val*flag);
node = node.parent;
}
Collections.reverse(result);
return result;
}
}
class TreeNode{
public int val;//节点值
public TreeNode parent;
public TreeNode(int val, TreeNode parent) {
this.val = val;
this.parent = parent;
}
}