leetcode
leetcode 3001 ~ 3050
搭桥过河

搭桥过河

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 1073 ms, 内存: 56.5 MB


/*
 * 思路:
 * 1. 首先对浮木进行排序,按照起始位置排序。
 * 2. 遍历浮木,检查每一块浮木与前一块浮木是否重叠。
 * 3. 如果不重叠,计算需要移动的距离,使其与前一块浮木重叠。
 * 4. 累加所有需要移动的距离,即为结果。
 */

import java.util.Arrays;
import java.util.stream.IntStream;

public class Solution {
    public int minForce(int num, int[][] wood) {
        // 按起始位置排序浮木
        Arrays.sort(wood, (a, b) -> Integer.compare(a[0], b[0]));
        int[] totalForce = {0};
        IntStream.range(1, wood.length).forEach(i -> {
            if (wood[i][0] > wood[i - 1][1]) { // 如果当前浮木与前一个浮木不重叠
                int moveForce = wood[i][0] - wood[i - 1][1] - 1;
                totalForce[0] += moveForce;
                // 移动当前浮木
                wood[i][0] -= moveForce;
                wood[i][1] -= moveForce;
            }
        });
        return totalForce[0];
    }

    public static void main(String[] args) {
        Solution sol = new Solution();
        int[][] wood = {{1, 2}, {4, 7}, {8, 9}};
        System.out.println(sol.minForce(10, wood)); // 输出 3
    }
}

解释

方法:

这道题目主要涉及到优化浮木位置使勇者可以跨越河流,使用最小的能量。思路是利用两个堆来跟踪浮木移动的范围。左堆(left_heap)负责跟踪当前浮木的最左端,而右堆(right_heap)跟踪最右端。在遍历每个浮木时,比较其位置与当前跨越范围(由堆维护),并相应地调整堆,并更新总花费的能量。如果当前浮木已在跨越范围内,则无需移动。如果浮木在跨越范围外,则需要移动到范围内,并更新堆和总花费。通过维护两个堆,可以在每次遍历时高效地找到需要的最左和最右的位置。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
题解中提到使用两个堆来跟踪浮木的移动范围,左堆和右堆分别是如何初始化和更新的?具体的操作逻辑是什么?
在题解中,左堆(left_heap)用于维持当前可跨越范围的最左端点,而右堆(right_heap)维持最右端点。左堆为最大堆,右堆为最小堆。初始化时,将第一个浮木的左端点加入左堆(以负值形式存储以实现最大堆的效果),右端点加入右堆。堆的更新发生在浮木位置调整时。如果浮木需要向左移动以进入覆盖区间,左堆的堆顶(当前最左端点)被弹出,新的位置被压入。类似地,如果需要向右移动,右堆的堆顶被弹出,新的位置压入。这样确保了每次都可以快速地获取并更新覆盖区间的边界。
🦆
在浮木位置调整的过程中,如何确保每次移动都是最优的?是否有可能存在更少的移动次数仍能实现目标?
算法通过维护左右端点的最优位置(即当前最左和最右的位置),确保移动总距离最小化。堆结构使得每次都能快速访问和更新这些端点。尽管算法试图通过贪心策略保证每步移动都是局部最优,但不排除存在全局更优的解决方案。由于问题的复杂性及解空间的大小,可能需要更复杂的策略或算法(如动态规划)来找到绝对最优解。当前策略是实践中效率和实现的良好折中。
🦆
题解中提到有三种情况处理浮木的位置,能否详细解释这三种情况下的逻辑处理,并给出具体的例子?
三种情况分别是:1)浮木在当前跨越区域的左侧,需要将浮木右移至至少覆盖区域的最左端。这时,左堆的堆顶被弹出,新位置加入左堆,右堆加入更新的最左端点,更新移动花费。例如,如果最左端是5,浮木左端是2,浮木被移动到5,总花费增加3。2)浮木在当前跨越区域内,无需移动,但需要更新左右堆以保持覆盖。3)浮木在当前跨越区域的右侧,需要左移至至少覆盖区域的最右端。这时右堆的堆顶被弹出,新位置加入右堆,左堆加入更新的最右端点,更新移动花费。例如,如果最右端是10,浮木右端是12,浮木被移动到10,总花费增加2。

相关问题