G
N
I
D
A
O
L

2023 年力扣杯春季编程大赛题解

题目集合:

  • 2 分 - 补给马车
  • 4 分 - 探险营地
  • 6 分 - 最强祝福力场
  • 8 分 - 传送卷轴
  • 10 分 - 魔法棋盘

# T1. 补给马车

# 思路

模拟

# 代码

a
class Solution {
    public int[] supplyWagon(int[] supplies) {
        int n = supplies.length;
        int newLen = n / 2;
        for (int i = n; i > newLen; --i) {
            int k = 0;
            int mv = Integer.MAX_VALUE;
            for (int j = 0; j < i - 1; ++j) {
                if (supplies[j] + supplies[j + 1] < mv) {
                    mv = supplies[j] + supplies[j + 1];
                    k = j;
                }
            }
            supplies[k] += supplies[k + 1];
            for (int j = k + 1; j < i - 1; ++j) {
                supplies[j] = supplies[j + 1];
            }
        }
        
        int[] ans = new int[newLen];
        
        System.arraycopy(supplies, 0, ans, 0, newLen);
        
        return ans;
    }
}

# T2. 探险营地

# 思路

模拟

# 代码

a
class Solution {
    public int adventureCamp(String[] es) {
        Set<String> old = new HashSet<>();
        String[] ss = es[0].split("->");
        for (String s : ss) old.add(s);
        int cnt = 0;
        int idx = -1;
        for (int i = 1; i < es.length; ++i) {
            ss = es[i].split("->");
            int c = 0;
            for (String s : ss) {
                if (s.length() > 0 && !old.contains(s)) {
                    old.add(s);
                    ++c;
                }
            }
            if (c > cnt) {
                cnt = c;
                idx = i;
            }
        }
        return idx;
    }
}

# T3. 最强祝福力场

# 解题思路

  1. 坐标离散化
  2. 坐标点整数化
  3. 建图进行二维差分(矩阵)
  4. 求矩阵的前缀和

具体看代码注释

# 代码

a
class Solution {
    public int fieldOfGreatestBlessing(int[][] forceField) {
        // 1. 坐标点离散化
        // 有序集合:唯一 + 有序
        Set<Long> xs = new TreeSet<>();
        Set<Long> ys = new TreeSet<>();
        for (int[] fo : forceField) {
            // x - side / 2:
            // 考虑到可能为小数,故将坐标转成整数:2 * x - side
            // 左上角坐标
            long x = 2L * fo[0] - fo[2];
            long y = 2L * fo[1] - fo[2];
            xs.add(x);
            ys.add(y);
            // 右下角坐标
            x = 2L * fo[0] + fo[2];
            y = 2L * fo[1] + fo[2];
            xs.add(x);
            ys.add(y);
        }
        int xn = xs.size();
        int yn = ys.size();
        long[] xAxis = new long[xn];
        long[] yAxis = new long[yn];
        int k = 0;
        for (long x : xs) xAxis[k++] = x;
        k = 0;
        for (long y : ys) yAxis[k++] = y;
        // 2. 二维差分
        int[][] m = new int[xn][yn];
        for (int[] f : forceField) {
            long lx = 2L * f[0] - f[2];
            long rx = 2L * f[0] + f[2];
            long ty = 2L * f[1] - f[2];
            long by = 2L * f[1] + f[2];
            // 通过二分找到当前坐标的离散化后的下标
            int lxi = Arrays.binarySearch(xAxis, lx);
            int rxi = Arrays.binarySearch(xAxis, rx);
            int tyi = Arrays.binarySearch(yAxis, ty);
            int byi = Arrays.binarySearch(yAxis, by);
            
            if (lxi >= 0 && tyi >= 0 && rxi >= 0 && byi >= 0) {
                // 左上 +1
                ++m[lxi][tyi];
                // 左下 -1
                if (byi + 1 < yn) --m[lxi][byi + 1];
                // 右上 -1
                if (rxi + 1 < xn) --m[rxi + 1][tyi];
                // 右下 +1
                if (byi + 1 < yn && rxi + 1 < xn) ++m[rxi + 1][byi + 1];
            }
        }
        
        // 二维前缀和计算答案
        int max = 0;
        for (int i = 0; i < xn; ++i) {
            for (int j = 0; j < yn; ++j) {
                if (j > 0) m[i][j] += m[i][j - 1];
                if (i > 0) m[i][j] += m[i - 1][j];
                if (i > 0 && j > 0) m[i][j] -= m[i - 1][j - 1];
                max = Math.max(m[i][j], max);
            }
        }
        
        return max;
    }
}

# T4. 传送卷轴

# 解题思路

BFS + 二分枚举

# 代码

a
class Solution {
    final int[] dx = new int[] {0, 0, -1, 1};
    final int[] dy = new int[] {1, -1, 0, 0};
    char[][] mat;
    public int challengeOfTheKeeper(String[] maze) {
        /**
         * 1. 找到【初始位置】和【魔法水晶】位置
         * 2. bfs 计算【魔法水晶】位置到每个可达点的最短距离 dis [i][j]
         * 3. 二分答案
         */
        int n = maze.length;
        mat = new char[n][];
        // 【初始位置】的坐标
        int startX = -1, startY = -1;
        // 【魔法水晶】的位置坐标
        int endX = -1, endY = -1;
        for (int i = 0; i < n; ++i) {
            mat[i] = maze[i].toCharArray();
            if (startX + startY < 0 || endX + endY < 0) {
                for (int j = 0; j < n; ++j) {
                    if (mat[i][j] == 'S') {
                        startX = j;
                        startY = i;
                    } else if (mat[i][j] == 'T') {
                        endX = j;
                        endY = i;
                    }
                }
            }
        }
        // 2. 计算【魔法水晶】到各个点的最短距离
        int[][] dis = new int[n][n];
        Queue<int[]> que = new ArrayDeque<>();
        for (int i = 0; i < n; ++i) Arrays.fill(dis[i], Integer.MAX_VALUE);
        que.offer(new int[]{endX, endY});
        dis[endY][endX] = 0;
        while (!que.isEmpty()) {
            for (int i = que.size(); i > 0; --i) {
                int[] cur = que.poll();
                int curX = cur[0];
                int curY = cur[1];
                for (int j = 0; j < dx.length; ++j) {
                    int nxtX = curX + dx[j];
                    int nxtY = curY + dy[j];
                    if (0 <= nxtX && nxtX < n && 0 <= nxtY && nxtY < n
                            // 不是墙壁
                            && mat[nxtY][nxtX] != '#'
                            // 还未访问过
                            && dis[nxtY][nxtX] == Integer.MAX_VALUE) {
                        que.offer(new int[] {nxtX, nxtY});
                        dis[nxtY][nxtX] = dis[curY][curX] + 1;
                    }
                }
            }
        }
        // 初始位置本身就无法达到【魔法水晶】
        if (dis[startY][startX] == Integer.MAX_VALUE) return -1;
        // 3. 二分枚举答案
        int l = -1, r = n * n + 1;
        int [][] vis = new int[n][n];
        while (l + 1 < r) {
            int step = (l + r) / 2;
            if (dfs(startX, startY, step, vis, dis)) r = step;
            else l = step;
        }
        return r > n * n ? -1 : r;
    }
    // 判断是否能在 maxStep 步数内能否到达【魔法水晶】
    private boolean dfs(int x, int y, int maxStep, int[][] vis, int[][] dis) {
        int n = mat.length;
        if (x < 0 || x >= n || y < 0 || y >= n // 越界
                || mat[y][x] == '#' // 走到墙壁
                || vis[y][x] == maxStep + 1) // 没有走过
            return false;
        // 到达终点
        if (mat[y][x] == 'T') return true;
        vis[y][x] = maxStep + 1;
        // 守护者使用卷轴,如果无法在 maxDis 内到达,则返回 false
        if (mat[y][x] == '.'
                && (mat[y][n - 1 - x] != '#' && dis[y][n - 1 - x] > maxStep
                || mat[n - 1 - y][x] != '#' && dis[n - 1 - y][x] > maxStep))
            return false;
        for (int i = 0; i < dx.length; ++i) {
            if (dfs(x + dx[i], y + dy[i], maxStep, vis, dis))
                return true;
        }
        return false;
    }
}
更新于 阅读次数

😉觉得写的还不错,请我喝杯咖啡吧😁

独步凌波 微信支付

微信支付

独步凌波 支付宝

支付宝