【Lintcode】1364. The Minium Distance

题目地址:

https://www.lintcode.com/problem/the-minium-distance/description

给定一个 m m m n n n列的二维矩阵 A A A,其中 − 2 -2 2代表起点, − 3 -3 3代表终点, − 1 -1 1代表障碍物, 0 0 0代表空地,正整数代表传送门。从起点出发,每次可以朝四个方向走一步,不能走到障碍物上;如果当前位于传送门,则除了能朝四周走之外,还可以花 1 1 1步走到别的编号相同的传送门上。问从起点到终点最少花多少步能到。

思路是双向BFS。直接套用模板即可,只需求下一步能走到的位置的时候考虑一下传送门。代码如下:

import java.util.*;

public class Solution {
    
    class Pair {
        int x, y;
        
        public Pair(int x, int y) {
            this.x = x;
            this.y = y;
        }
        
        @Override
        public boolean equals(Object o) {
            Pair pair = (Pair) o;
            return x == pair.x && y == pair.y;
        }
        
        @Override
        public int hashCode() {
            return Objects.hash(x, y);
        }
    }
    
    /**
     * @param grid: a 2D grid
     * @return: return the minium distance
     */
    public int getMinDistance(int[][] grid) {
        // write your code here
        // map存传送门,key是编号,value是该编号的传送门坐标
        Map<Integer, List<Pair>> map = new HashMap<>();
        Pair start = new Pair(0, 0), end = new Pair(0, 0);
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == -2) {
                    start.x = i;
                    start.y = j;
                } else if (grid[i][j] == -3) {
                    end.x = i;
                    end.y = j;
                } else if (grid[i][j] > 0) {
                    map.putIfAbsent(grid[i][j], new ArrayList<>());
                    map.get(grid[i][j]).add(new Pair(i, j));
                }
            }
        }
        
        Queue<Pair> beginQueue = new LinkedList<>(), endQueue = new LinkedList<>();
        Set<Pair> beginSet = new HashSet<>(), endSet = new HashSet<>();
        beginQueue.offer(start);
        beginSet.add(start);
        endQueue.offer(end);
        endSet.add(end);
        
        int step = 0;
        while (!beginQueue.isEmpty() && !endQueue.isEmpty()) {
            step++;
            if (oneStep(beginQueue, beginSet, endSet, grid, map)) {
                return step;
            }
            
            step++;
            if (oneStep(endQueue, endSet, beginSet, grid, map)) {
                return step;
            }
        }
        
        return -1;
    }
    
    private boolean oneStep(Queue<Pair> beginQueue, Set<Pair> beginSet, Set<Pair> endSet, int[][] grid, Map<Integer, List<Pair>> map) {
        int size = beginQueue.size();
        for (int i = 0; i < size; i++) {
            Pair cur = beginQueue.poll();
            for (Pair next : getNexts(cur, grid, beginSet, endSet, map)) {
                if (endSet.contains(next)) {
                    return true;
                }
                
                beginQueue.offer(next);
                beginSet.add(next);
            }
        }
        
        return false;
    }
    
    // 将能走到的且之前未访问的位置返回
    private Set<Pair> getNexts(Pair cur, int[][] grid, Set<Pair> beginSet, Set<Pair> endSet, Map<Integer, List<Pair>> map) {
    	// 这里用Set的原因是,有可能从某个点走一步能到另一个点,但走传送门也能到那个点,这样就有可能重复计算。所以这里采取Set去一下重
        Set<Pair> nexts = new HashSet<>();
        int[] d = {1, 0, -1, 0, 1};
        int x = cur.x, y = cur.y;
        for (int i = 0; i < 4; i++) {
            int nextX = x + d[i], nextY = y + d[i + 1];
            if (inBound(nextX, nextY, grid) && grid[nextX][nextY] != -1) {
                Pair next = new Pair(nextX, nextY);
                if (endSet.contains(next)) {
                    nexts.clear();
                    nexts.add(next);
                    return nexts;
                }
                if (!beginSet.contains(next)) {
                    nexts.add(next);
                }
            }
        }
        
        // 看一下是否是传送门
        if (grid[x][y] > 0) {
            for (Pair next : map.get(grid[x][y])) {
                if (endSet.contains(next)) {
                    nexts.clear();
                    nexts.add(next);
                    return nexts;
                }
                if (!beginSet.contains(next)) {
                    nexts.add(next);
                }
            }
        }
        
        return nexts;
    }
    
    private boolean inBound(int x, int y, int[][] grid) {
        return 0 <= x && x < grid.length && 0 <= y && y < grid[0].length;
    }
}

时空复杂度 O ( m n ) O(mn) O(mn)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值