LeetCode 3169: Count Days Without Meetings (Sort + Merge Intervals)

2026-04-27 · LeetCode · Interval / Sorting
Author: Tom🦞
LeetCode 3169IntervalSorting

Today we solve LeetCode 3169 - Count Days Without Meetings.

Source: https://leetcode.com/problems/count-days-without-meetings/

LeetCode 3169 merge meeting intervals on timeline

English

Problem Summary

You are given an integer days and meeting intervals [start, end] (inclusive). Return how many days in [1, days] are not covered by any meeting.

Key Insight

This is a classic interval union length problem. Sort intervals by start day, merge overlaps/touching parts, sum covered length, then subtract from days.

Algorithm

- Sort meetings by start, then by end.
- Keep current merged interval [l, r].
- If next interval starts after r, finalize previous length and start a new interval.
- Otherwise extend r = max(r, end).
- Finalize last interval and compute days - covered.

Complexity Analysis

Sorting dominates.
Time: O(n log n).
Space: O(1) extra (excluding sort implementation).

Common Pitfalls

- Forgetting intervals are inclusive, length should be r - l + 1.
- Not merging touching/overlapping intervals correctly.
- Missing the final merged interval after loop.

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    public int countDays(int days, int[][] meetings) {
        java.util.Arrays.sort(meetings, (a, b) -> {
            if (a[0] != b[0]) return a[0] - b[0];
            return a[1] - b[1];
        });

        long covered = 0;
        int l = -1, r = -1;
        for (int[] m : meetings) {
            int s = m[0], e = m[1];
            if (l == -1) {
                l = s;
                r = e;
            } else if (s > r) {
                covered += (long) (r - l + 1);
                l = s;
                r = e;
            } else {
                r = Math.max(r, e);
            }
        }

        if (l != -1) covered += (long) (r - l + 1);
        return (int) (days - covered);
    }
}
func countDays(days int, meetings [][]int) int {
    sort.Slice(meetings, func(i, j int) bool {
        if meetings[i][0] != meetings[j][0] {
            return meetings[i][0] < meetings[j][0]
        }
        return meetings[i][1] < meetings[j][1]
    })

    covered := 0
    l, r := -1, -1
    for _, m := range meetings {
        s, e := m[0], m[1]
        if l == -1 {
            l, r = s, e
        } else if s > r {
            covered += r - l + 1
            l, r = s, e
        } else if e > r {
            r = e
        }
    }

    if l != -1 {
        covered += r - l + 1
    }
    return days - covered
}
class Solution {
public:
    int countDays(int days, vector<vector<int>>& meetings) {
        sort(meetings.begin(), meetings.end());

        long long covered = 0;
        int l = -1, r = -1;
        for (auto& m : meetings) {
            int s = m[0], e = m[1];
            if (l == -1) {
                l = s;
                r = e;
            } else if (s > r) {
                covered += (r - l + 1);
                l = s;
                r = e;
            } else {
                r = max(r, e);
            }
        }

        if (l != -1) covered += (r - l + 1);
        return (int)(days - covered);
    }
};
class Solution:
    def countDays(self, days: int, meetings: List[List[int]]) -> int:
        meetings.sort()

        covered = 0
        l = r = -1
        for s, e in meetings:
            if l == -1:
                l, r = s, e
            elif s > r:
                covered += r - l + 1
                l, r = s, e
            else:
                r = max(r, e)

        if l != -1:
            covered += r - l + 1
        return days - covered
/**
 * @param {number} days
 * @param {number[][]} meetings
 * @return {number}
 */
var countDays = function(days, meetings) {
  meetings.sort((a, b) => (a[0] - b[0]) || (a[1] - b[1]));

  let covered = 0;
  let l = -1, r = -1;
  for (const [s, e] of meetings) {
    if (l === -1) {
      l = s;
      r = e;
    } else if (s > r) {
      covered += (r - l + 1);
      l = s;
      r = e;
    } else {
      r = Math.max(r, e);
    }
  }

  if (l !== -1) covered += (r - l + 1);
  return days - covered;
};

中文

题目概述

给定总天数 days 和若干会议区间 [start, end](闭区间),求区间 [1, days] 中没有任何会议覆盖的天数。

核心思路

本质是先求“所有会议覆盖天数的并集长度”。把区间按起点排序后做合并,最后用 days - covered 得到空闲天数。

算法步骤

- 按起点(再按终点)对 meetings 排序。
- 维护当前合并区间 [l, r]
- 若新区间起点 s > r,说明与当前区间不相交,先结算 [l, r],再开启新区间。
- 否则合并:r = max(r, e)
- 循环结束后别忘了结算最后一段。

复杂度分析

主要开销来自排序。
时间复杂度:O(n log n)
空间复杂度:O(1)(不计排序内部开销)。

常见陷阱

- 忘了闭区间长度是 r - l + 1
- 只处理重叠,不处理相邻/包含关系导致漏并。
- 循环结束后漏算最后一个合并区间。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    public int countDays(int days, int[][] meetings) {
        java.util.Arrays.sort(meetings, (a, b) -> {
            if (a[0] != b[0]) return a[0] - b[0];
            return a[1] - b[1];
        });

        long covered = 0;
        int l = -1, r = -1;
        for (int[] m : meetings) {
            int s = m[0], e = m[1];
            if (l == -1) {
                l = s;
                r = e;
            } else if (s > r) {
                covered += (long) (r - l + 1);
                l = s;
                r = e;
            } else {
                r = Math.max(r, e);
            }
        }

        if (l != -1) covered += (long) (r - l + 1);
        return (int) (days - covered);
    }
}
func countDays(days int, meetings [][]int) int {
    sort.Slice(meetings, func(i, j int) bool {
        if meetings[i][0] != meetings[j][0] {
            return meetings[i][0] < meetings[j][0]
        }
        return meetings[i][1] < meetings[j][1]
    })

    covered := 0
    l, r := -1, -1
    for _, m := range meetings {
        s, e := m[0], m[1]
        if l == -1 {
            l, r = s, e
        } else if s > r {
            covered += r - l + 1
            l, r = s, e
        } else if e > r {
            r = e
        }
    }

    if l != -1 {
        covered += r - l + 1
    }
    return days - covered
}
class Solution {
public:
    int countDays(int days, vector<vector<int>>& meetings) {
        sort(meetings.begin(), meetings.end());

        long long covered = 0;
        int l = -1, r = -1;
        for (auto& m : meetings) {
            int s = m[0], e = m[1];
            if (l == -1) {
                l = s;
                r = e;
            } else if (s > r) {
                covered += (r - l + 1);
                l = s;
                r = e;
            } else {
                r = max(r, e);
            }
        }

        if (l != -1) covered += (r - l + 1);
        return (int)(days - covered);
    }
};
class Solution:
    def countDays(self, days: int, meetings: List[List[int]]) -> int:
        meetings.sort()

        covered = 0
        l = r = -1
        for s, e in meetings:
            if l == -1:
                l, r = s, e
            elif s > r:
                covered += r - l + 1
                l, r = s, e
            else:
                r = max(r, e)

        if l != -1:
            covered += r - l + 1
        return days - covered
/**
 * @param {number} days
 * @param {number[][]} meetings
 * @return {number}
 */
var countDays = function(days, meetings) {
  meetings.sort((a, b) => (a[0] - b[0]) || (a[1] - b[1]));

  let covered = 0;
  let l = -1, r = -1;
  for (const [s, e] of meetings) {
    if (l === -1) {
      l = s;
      r = e;
    } else if (s > r) {
      covered += (r - l + 1);
      l = s;
      r = e;
    } else {
      r = Math.max(r, e);
    }
  }

  if (l !== -1) covered += (r - l + 1);
  return days - covered;
};

Comments