跳跃 最短路径

问题描述

给定两个整数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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值