java二维数组找最短路径问题-美团面试

题目
首先输入一个(n,k)的值,其中n构成一个n*n的二维数字,而二维数字具体的参数则是1-k某一具体的值。问题是要找到遍历1…k这些所有值经过的最短路径。但是如果输入的二维数组缺少从0-k的某个值时,那么就没有最短路径。路径的求法是:比如aij和bij的路径是|ai-bi|+|aj-bj|。

思路
1、输入部分就不多说了,做好之后建议输入输出测试一下,方便只有的调试。
2、关于找出最短路径的问题,刚开始想可以用回溯用递归,加上没有最短路径的问题,结果思路就很乱。于是就选择最简单最直接的这种方法。
首先,要找到从1…k所经过的最短路径,此时应该判断该二维数组应该包含从1-k的所有值,该条件成立之后才能找最短路径。
对于找1-k的最短路径,就是找1->2的最短路径、2->3的最短路径、3->4的最短路径…对他们求和,求出来的就是最短路径。
找1->2的最短路径的最短路径时,考虑到出现1和2的数组位置是变化的,很难动态的找出谁是最短路径,所以就把出现过1和2的所有数组都保存下来,最后在求出距离最小的。
在考虑求保存出现数组下标i、j时最开始出现了一个错误的想法,因为保存的是两个元素,所以很容易选择了hashmap,但是输出结果时就发现少了不少元素,当key相同时,hashmap会更新值,所以最后选择数组保存就OK了。
最后对保存的元素相减求最小值。

下面直接上代码了。

import java.util.*;

/**
 * 功能描述
 * 最短路径问题
 * @author Newton
 * @date 2021/4/5 10:14
 * @Version 1.0
 */
public class meituan {
    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        int n=in.nextInt();
        int k=in.nextInt();
        int[][] nums = new int[n][n];

        //输入数组
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                nums[i][j]=in.nextInt();
            }
        }
        int sum=0;
        //找出相邻两个k之间的最短距离
        for (int i = 1; i < k; i++) {
            int flag=0;
            flag=test1(n,i,i+1,nums);
            if (flag==-1){
                System.out.println("无法到达");
            }
            else{
                sum=sum+flag;
                System.out.println("从"+i+"->"+(i+1)+",最短路劲为:"+flag);
            }
        }
        System.out.println("最短路劲为:"+sum);


    }

    //找出相邻两个k之间的最短距离并返回最短距离
    public static int test1(int n,int a,int b,int[][] nums){

        //把找到的相邻两个key之间的所有元素放在hashmap中,如果为空则不满足条件
        //【思路更正】最开始的思路是上面的,但是hashmap不满足提议,因为相同key的时候会替换,所有把他们分别放到数组中,基数为i,偶数为j
        List<Integer> listai=new ArrayList<>();
        List<Integer> listaj=new ArrayList<>();
        List<Integer> listbi=new ArrayList<>();
        List<Integer> listbj=new ArrayList<>();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (nums[i][j]==a){
                    listai.add(i);
                    listaj.add(j);
                }
                if (nums[i][j]==b){
                    listbi.add(i);
                    listbj.add(j);
                }
            }
        }

        int min=abs((listai.get(0)-listbi.get(0)))+abs((listaj.get(0)-listbj.get(0)));
        int len=0;
        //如果hashmap为空说明缺少k,返回-1
        if(listai.size()==0 || listaj.size()==0){
            return -1;
        }
        //找出从a->b的最短距离
        else{
            for (int i = 0; i < listai.size(); i++) {
                int ai=listai.get(i);
                int aj=listaj.get(i);
//                System.out.println("ai:"+ai+"  aj:"+aj);
                for (int j = 0; j < listbi.size(); j++) {
                    int bi=listbi.get(j);
                    int bj=listbj.get(j);
//                    System.out.println("bi:"+bi+"  bj:"+aj);
                    len=abs((ai-bi))+abs((aj-bj));
//                    System.out.println(len);
                    min=(min<=len)? min: len;
//                    System.out.println(min);
                }
            }
            return min;
        }

    }
    public static int abs(int a) {
        return (a < 0) ? -a : a;
    }
}

运行结果:
在这里插入图片描述
代码其实还有改进的空间,比如输入元素的判断等等,大家可以自行改进。

参考资源链接:[2019常州市程序设计小能手比赛试题.pdf](https://wenku.youkuaiyun.com/doc/6401ac1acce7214c316eaa43?utm_source=wenku_answer2doc_content) 在面对二维数组最短路径问题时,动态规划是常用且有效的算法之一。通过分析题目的具体要求,我们可以设计出一种适应于这类问题的解题框架。 以2019常州市程序设计小能手比赛的试题为例,我们可以假设存在一个二维数组,其中的每个元素代表了不同的权重或者成本,我们的目标是到从起点到终点的最短路径。 动态规划的方法中,通常会构建一个与原数组同样大小的二维数组dp,其中dp[i][j]表示到达位置(i, j)的最短路径长度。通过填充这个dp数组,我们可以到最终的答案。 具体步骤如下: 1. 初始化dp数组,通常起点的dp值设为0,其他位置设为一个较大的数。 2. 对于二维数组中的每个元素,根据题目的约束条件更新dp数组中的值。常见的操作是从上、下、左、右四个方向,取当前位置的最短路径加上当前路径长度。 3. 遍历dp数组,到终点位置的值,即为整个二维数组最短路径长度。 在实现时,需要特别注意边界条件以及避免路径上的无效移动,如题目中可能存在的障碍物或不通行区域。 通过上述方法,结合2019常州市程序设计小能手比赛的试题,不仅可以加深对动态规划算法的理解,还可以学会如何将理论应用到实际的编程题目中去。 参考资源链接:[2019常州市程序设计小能手比赛试题.pdf](https://wenku.youkuaiyun.com/doc/6401ac1acce7214c316eaa43?utm_source=wenku_answer2doc_content)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值