题目描述

✅ 646. 最长数对链

image-20260929102037310

题意分析

可以从数对中选择一部分并任意重排,求能组成的最长链。若前一个数对为 [a, b],下一个为 [c, d],必须满足 b < c;端点相等也不能连接。

解法:按右端点排序的贪心

核心思路

[!blue]
在当前能够连接的数对中,优先选择右端最小的。 每加入一个数对,后续只能使用左端更大的数对;新右端越小,给后续留下的选择就越多。先按右端升序排序,就能在扫描时直接找到这样的候选。

这个选择可用交换证明。固定已经选好的链,设贪心接下来选 $G$,某个最优延长方案的下一项是 $O$。两者都能接在当前链后,且 $G$ 的右端不大于 $O$;将 $O$ 换成 $G$ 后,原来能接在 $O$ 后的数对也仍能接在 $G$ 后,链长不变。因此总有一个最优方案采用本次贪心选择,反复应用即可得到最长链。

curEnd 保存已选链最后一项的右端,count 保存长度。当前左端严格大于 curEnd 就加入并更新两者,否则跳过。由于按右端排序,被跳过的当前数对不会比已选末端结束得更早,替换它也无法增加后续机会。

空链的末端要初始化为小于所有合法端点的值,让第一个数对自然被选中,负数端点也能正确处理。排序只改变数对的处理顺序,不改变每个数对内部的左右端含义。

解题步骤

  1. 按右端点升序排序。
  2. 初始化空链和足够小的末端。
  3. 当前左端严格超过末端时,增加长度并更新末端。
  4. 返回链长。

代码实现

class Solution {
    public int findLongestChain(int[][] pairs) {
        Arrays.sort(pairs, (a, b) -> a[1] - b[1]);

        int count = 0;
        int curEnd = Integer.MIN_VALUE;

        for (int[] pair : pairs) {
            // 端点相等不能连接,只有严格超过末端才选择当前数对。
            if (pair[0] > curEnd) {
                count++;
                curEnd = pair[1];
            }
        }

        return count;
    }
}
import "sort"

func findLongestChain(pairs [][]int) int {
    sort.Slice(pairs, func(i, j int) bool {
        return pairs[i][1] < pairs[j][1]
    })

    count := 0
    curEnd := -1 << 60

    for _, pair := range pairs {
        // 端点相等不能连接,只有严格超过末端才选择当前数对。
        if pair[0] > curEnd {
            count++
            curEnd = pair[1]
        }
    }

    return count
}

复杂度分析

  • 时间复杂度:$O(n\log(n+1))$,排序后扫描。
  • 空间复杂度:扫描辅助空间 $O(1)$;Java 对象数组排序工作区为 $O(n)$,Go 排序栈为 $O(\log(n+1))$,输入会被重排。

关键点总结

[!green]

  • 结束更早不会减少未来接续机会。
  • 可以重排数对,因此排序不破坏题目要求。
  • 接续是严格不等,端点相同不能连接。

易错点总结

[!yellow]

  • 按左端最早就选:左端早但右端很晚的数对,可能挡住后面多组本可连接的数对。
  • 末端初值为零:负数端点可能全部被跳过。
  • 接续使用大于等于:接受题目不允许的端点相接。
  • 未选中也更新末端:破坏已选链的真实状态。

相似题目

题目 难度 关联与区别
435. 无重叠区间 中等 同样按结束位置贪心选最多区间,但本题衔接要求严格小于,原题常允许端点相接。
300. 最长递增子序列 中等 同样求最长可衔接链,本题前项结束值小于后项开始值,非单个值之间的递增关系。
452. 用最少数量的箭引爆气球 中等 按结束位置判断区间重叠并进行贪心选择;本题将数对连接视为不重叠区间选择,该题用最少位置覆盖所有区间。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2021/34661161
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!