Leetcode 72 数组列表中的最大距离

1 题目

624. 数组列表中的最大距离

给定 m 个数组,每个数组都已经按照升序排好序了。

现在你需要从两个不同的数组中选择两个整数(每个数组选一个)并且计算它们的距离。两个整数 a 和 b 之间的距离定义为它们差的绝对值 |a-b| 。

返回最大距离。

示例 1:

复制代码
输入:[[1,2,3],[4,5],[1,2,3]]
输出:4
解释:
一种得到答案 4 的方法是从第一个数组或者第三个数组中选择 1,同时从第二个数组中选择 5 。

示例 2:

复制代码
输入:arrays = [[1],[1]]
输出:0

提示:

  • m == arrays.length
  • 2 <= m <= 105
  • 1 <= arrays[i].length <= 500
  • -104 <= arrays[i][j] <= 104
  • arrays[i] 以 升序 排序。
  • 所有数组中最多有 105 个整数。

2 代码实现

cpp 复制代码
class Solution {
public:
    int maxDistance(vector<vector<int>>& arrays) {
        int res = 0 ;
        int min_val = arrays[0][0];
        int max_val = arrays[0].back();

        for (int i = 1 ; i < arrays.size() ; ++i){
            int curr_min = arrays[i][0];
            int curr_max = arrays[i].back();

            res = max(res,abs(curr_max - min_val));
            res = max(res,abs(max_val - curr_min));

            min_val = min (min_val , curr_min);
            max_val = max (max_val , curr_max);
        }
        return res;
    }
};

乱七八糟的想

...之前的题都做了,以后再做这个题还是一点头绪也没有,最大距离不就是找最大数和最小数的差,最小好说,就是一边遍历一边更新minNum , 最大呢?每一个数组元素的大小又不是一样固定的怎么防止越界。(每次都取一遍size() 吧?)

我特别理解你的困惑 ------ 一开始会觉得 "找最大最小差" 很直观,但卡就卡在「最大 / 最小可能来自同一个数组」这个坑上,还有对 "数组首尾元素" 的利用不熟练。我用更通俗的方式拆解,把你纠结的点逐个说透:

先解决你最核心的疑问:为什么只看数组首尾?

你提到 "每一个数组元素的大小又不是一样固定的怎么防止越界",其实题目里明确说每个数组都是升序排列,这是关键!

  • 升序数组的最小值一定在第一个位置(索引 0) ,不可能在中间或最后(比如[1,2,3],最小只能是 1);
  • 升序数组的最大值一定在最后一个位置(索引 - 1) ,不可能在中间或开头(比如[4,5],最大只能是 5);所以根本不用遍历数组内部元素,只看arr[0](最小)和arr[-1](最大)就够了,完全不会 "越界"------ 因为题目保证每个数组长度≥1,arr[0]和arr[-1]一定存在。

再解决:为什么不能只记全局最大 / 最小?

你一开始想的 "一边遍历更 minNum" 是对的,但只记一个 minNum 和一个 maxNum 会踩坑:比如假设有数组[[1, 100], [2, 3]]:

  • 全局最小是 1(第一个数组),全局最大是 100(也是第一个数组);
  • 如果直接算 100-1=99,就错了!因为题目要求 "两个不同数组选数",1 和 100 来自同一个数组,不能选;
  • 正确的最大距离应该是 100-2=98(第一个数组的最大 + 第二个数组的最小),或者 3-1=2(第二个数组的最大 + 第一个数组的最小),取 98。

所以核心问题不是 "找最大 / 最小",而是 "找来自不同数组的最大和最小"------ 这就是为什么我们要记「最小 + 次小」「最大 + 次大」:

  • 如果全局最小和全局最大来自不同数组,直接用它们的差(最优解);
  • 如果来自同一个数组,就用 "全局最小 + 次大" 或 "全局最大 + 次小",选更大的那个。

用你的思路重写(更贴近你的直觉)

你说 "最小好说,一边遍历一边更新 minNum",那我们就先按这个思路走,再补全 "防同数组" 的逻辑:

python 复制代码
def maxDistance(arrays):
    # 第一步:遍历所有数组,记录每个数组的min(arr[0])和max(arr[-1])
    # 同时记录全局最小、全局最大,以及它们的数组索引
    global_min = float('inf')
    global_min_idx = -1
    global_max = float('-inf')
    global_max_idx = -1

    # 先找全局最小和全局最大(带索引)
    for i in range(len(arrays)):
        curr_min = arrays[i][0]
        curr_max = arrays[i][-1]
        # 更新全局最小
        if curr_min < global_min:
            global_min = curr_min
            global_min_idx = i
        # 更新全局最大
        if curr_max > global_max:
            global_max = curr_max
            global_max_idx = i

    # 第二步:判断是否来自不同数组
    if global_min_idx != global_max_idx:
        return global_max - global_min
    # 第三步:如果来自同一个数组,需要找次小/次大
    else:
        # 找次小值(排除全局最小所在的数组)
        second_min = float('inf')
        for i in range(len(arrays)):
            if i == global_min_idx:
                continue
            if arrays[i][0] < second_min:
                second_min = arrays[i][0]
        # 找次大值(排除全局最大所在的数组)
        second_max = float('-inf')
        for i in range(len(arrays)):
            if i == global_max_idx:
                continue
            if arrays[i][-1] > second_max:
                second_max = arrays[i][-1]
        # 取两种情况的最大值
        return max(global_max - second_min, second_max - global_min)

这个版本更贴近你的初始思路:

  1. 先按你想的 "遍历更 minNum/maxNum",同时记索引;
  2. 发现同数组后,再遍历一次找 "排除该数组后的次小 / 次大";
  3. 最后比较两种情况。

虽然比之前的版本多了一次遍历,但逻辑更直白,完全对应你 "先找最小 / 最大,再处理异常" 的思考路径。

总结你纠结的点

你的疑问 核心答案
为什么只看 arr 0/arr -1? 数组升序,首尾就是每个数组的最小 / 最大,不用看中间元素
怎么防止越界? 题目保证数组长度≥1,arr 0 和 arr -1 一定存在,不会越界
只记 min/max 为什么不行? 可能来自同一个数组,违反 "不同数组选数" 的规则
怎么处理同数组的情况? 找 "排除该数组后的次小 / 次大",再计算差值

其实你一开始的思路已经对了 80%,只差最后一步 "处理同数组的异常情况"。这类题的关键就是:先抓核心规律(升序数组首尾是极值),再补全边界条件(不同数组)。

你可以把这个思路套到之前做过的题里对比:

    1. 买卖股票:核心是 "低买高卖",边界是 "买在卖之前";
    1. 最大增量:核心是 "后数 - 前数最大",边界是 "后数 > 前数";
  • 本题:核心是 "最大 - 最小",边界是 "最大最小来自不同数组"。

本质都是 "先找核心解,再修边界",掌握这个逻辑,这类题就通了。


题解

先明确核心前提(题目给的关键条件)

题目里说:每个数组都是升序排列的 → 这意味着:

  • 任意一个数组的最小值一定是第一个元素 (arrays[i][0]);
  • 任意一个数组的最大值一定是最后一个元素 (arrays[i].back());
  • 我们要找的 "最大距离",本质是「一个数组的最大值 - 另一个数组的最小值」(因为差的绝对值最大,正数直接减就行)。

代码逐行拆解(带示例:输入[[1,2,3],[4,5],[1,2,3]])

我们以示例 1 的输入为例,一步步走代码流程,先贴完整代码 + 标注行号:

cpp 复制代码
class Solution {
public:
    int maxDistance(vector<vector<int>>& arrays) {
        // 行1:初始化最终结果为0(最大距离初始为0)
        int res = 0 ;
        // 行2:初始化全局最小值为第一个数组的最小值(arrays[0][0]=1)
        int min_val = arrays[0][0];
        // 行3:初始化全局最大值为第一个数组的最大值(arrays[0].back()=3)
        int max_val = arrays[0].back();

        // 行4:从第二个数组开始遍历(i=1,因为第一个数组已经作为基准了)
        for (int i = 1 ; i < arrays.size() ; ++i){
            // 行5:当前数组的最小值(比如i=1时,arrays[1][0]=4)
            int curr_min = arrays[i][0];
            // 行6:当前数组的最大值(比如i=1时,arrays[1].back()=5)
            int curr_max = arrays[i].back();

            // 行7:计算「当前数组最大值 - 之前所有数组的最小值」,更新最大距离
            res = max(res,abs(curr_max - min_val));
            // 行8:计算「之前所有数组的最大值 - 当前数组的最小值」,更新最大距离
            res = max(res,abs(max_val - curr_min));

            // 行9:更新全局最小值(把当前数组的最小值加入比较)
            min_val = min (min_val , curr_min);
            // 行10:更新全局最大值(把当前数组的最大值加入比较)
            max_val = max (max_val , curr_max);
        }
        // 行11:返回最终的最大距离
        return res;
    }
};

逐行 + 逐轮遍历解释(示例输入:[[1,2,3],[4,5],[1,2,3]])

第一步:初始化(行 1-3)
  • res = 0:还没计算任何距离,先把结果设为 0;
  • min_val = arrays[0][0] = 1:第一个数组[1,2,3]的最小值是 1;
  • max_val = arrays[0].back() = 3:第一个数组[1,2,3]的最大值是 3;
第二步:第一次循环(i=1,对应第二个数组[4,5])
  • 行 5:curr_min = arrays[1][0] = 4(第二个数组的最小值);

  • 行 6:curr_max = arrays[1].back() = 5(第二个数组的最大值);

  • 行 7:计算abs(5 - 1) = 4 → 现在res是max(0,4)=4;

  • ✨ 含义:第二个数组的最大值(5) - 第一个数组的最小值(1),这是一个候选的最大距离;

  • 行 8:计算abs(3 - 4) = 1 → 现在res是max(4,1)=4;

  • ✨ 含义:第一个数组的最大值(3) - 第二个数组的最小值(4),这个距离更小,不更新;

  • 行 9:更新min_val = min(1,4) = 1(当前全局最小值还是 1);

  • 行 10:更新max_val = max(3,5) = 5(当前全局最大值变成 5);

  • → 本轮结束后:res=4,min_val=1,max_val=5。

第三步:第二次循环(i=2,对应第三个数组[1,2,3])
  • 行 5:curr_min = arrays[2][0] = 1(第三个数组的最小值);

  • 行 6:curr_max = arrays[2].back() = 3(第三个数组的最大值);

  • 行 7:计算abs(3 - 1) = 2 → res是max(4,2)=4;

  • ✨ 含义:第三个数组的最大值(3) - 前两个数组的最小值(1),距离 2,比当前 res 小;

  • 行 8:计算abs(5 - 1) = 4 → res是max(4,4)=4;

  • ✨ 含义:前两个数组的最大值(5) - 第三个数组的最小值(1),距离 4,和当前 res 相等;

  • 行 9:更新min_val = min(1,1) = 1(全局最小值还是 1);

  • 行 10:更新max_val = max(5,3) = 5(全局最大值还是 5);

  • → 本轮结束后:res=4,min_val=1,max_val=5。

第四步:返回结果(行 11)

循环结束,返回res=4,和示例的正确输出一致!

再用 "极值同数组" 的例子验证(输入[[1,100],[2,3],[4,5]])

初始化:
  • res=0,min_val=1(第一个数组最小值),max_val=100(第一个数组最大值);
第一次循环(i=1,数组[2,3]):
  • curr_min=2,curr_max=3;
  • 行 7:abs(3-1)=2 → res=2;
  • 行 8:abs(100-2)=98 → res=98;
  • 行 9:min_val=min(1,2)=1;
  • 行 10:max_val=max(100,3)=100;
第二次循环(i=2,数组[4,5]):
  • curr_min=4,curr_max=5;
  • 行 7:abs(5-1)=4 → res=max(98,4)=98;
  • 行 8:abs(100-4)=96 → res=max(98,96)=98;
  • 行 9:min_val=1;
  • 行 10:max_val=100;
返回结果:98(正确,因为最大距离是 100-2=98)。

核心逻辑的 "底层原理"(为什么这样写能解决问题)

  1. 为什么从 i=1 开始遍历? 第一个数组作为 "基准",后续每个数组只和 "前面所有数组" 比较,天然避免了 "同一个数组选数" 的坑(比如不会出现 "100-1" 这种同数组的情况)。

  2. **为什么要算行 7 和行 8 两种情况?**最大距离只有两种可能:

    • 情况 1:当前数组的最大值,减去 "前面所有数组" 的最小值(比如 5-1=4);
    • 情况 2:"前面所有数组" 的最大值,减去当前数组的最小值(比如 100-2=98);这两种情况覆盖了 "跨数组找最大距离" 的所有可能性,不用再考虑其他组合。
  3. **为什么要更新 min_val 和 max_val?**遍历到下一个数组时,"前面所有数组" 的范围变大了,需要把当前数组的极值加入,让后续计算更全面(比如遍历到第三个数组时,"前面所有数组" 包含前两个,所以要更新全局极值)。

总结(一句话记住核心)

遍历每个数组时,只和 "前面所有数组" 的最小 / 最大值算距离,同时把当前数组的极值加入全局,最终的最大距离就是答案。

这个写法的优点:

  • 只用 3 个核心变量(res/min_val/max_val),没有复杂的索引、次小次大;
  • 遍历一次就搞定,时间复杂度 O (m)(m 是数组个数),效率最高;
  • 天然避开 "同数组选数" 的坑,不用处理复杂的边界条件。
相关推荐
weixin_307779131 小时前
C++代码实现MATLAB中的dlarray函数功能
开发语言·c++·算法·matlab
Frank_refuel4 小时前
C++11之一场名为“搬家”的 C++ 之旅
开发语言·c++
海绵宝宝转agent5 小时前
learn-claude-code第1-5章开源学习笔记分享
人工智能·笔记·python·学习
每天都要写算法(努力版)5 小时前
【行业前沿报告】DAgger:让智能体在自己走到的状态上学习
人工智能·学习·机器学习
hetao17338376 小时前
2026-10-03~04 hetao1733837 的刷题记录
c++·算法
Zootopia6267 小时前
飞行力学知识梳理1|飞行性能与稳定性
人工智能·python·算法·机器学习·无人机·学习方法·信息与通信
longlongzihan7 小时前
从LeetCode 70. 爬楼梯看动态规划:如何精准推导状态转移方程?
c++·算法·leetcode·动态规划
91刘仁德8 小时前
HTTP协议详解:从URL到HTTP服务器的完整实战
服务器·网络·笔记·网络协议·http
2601_960356388 小时前
2027校招采购岗解析:数学基础如何迁移到需求预测、成本与供应商分析
人工智能·算法
h_a_o777oah9 小时前
【树论】树链剖分:将树形结构转化为线性结构以处理树上路径问题(洛谷 P3384 附C++代码模板)
数据结构·算法·线段树·acm·树链剖分·树论·重链剖分