Maximum Population Year
EasyPrompt
You are given a 2D integer array logs where each logs[i] = [birthi, deathi] indicates the birth and death years of the ith person.
The population of some year x is the number of people alive during that year. The ith person is counted in year x's population if x is in the inclusive range [birthi, deathi - 1]. Note that the person is not counted in the year that they die.
Return the earliest year with the maximum population.
Example 1:
Input: logs = [[1993,1999],[2000,2010]]
Output: 1993
Explanation: The maximum population is 1, and 1993 is the earliest year with this population.Example 2:
Input: logs = [[1950,1961],[1960,1971],[1970,1981]]
Output: 1960
Explanation:
The maximum population is 2, and it had happened in years 1960 and 1970.
The earlier year between them is 1960.
Constraints:
1 <= logs.length <= 1001950 <= birthi < deathi <= 2050
Approaches
2 approaches with complexity analysis and trade-offs.
This approach involves iterating through every possible year within the given range and, for each year, counting the number of people alive. It's a straightforward simulation of the population count over time.
Algorithm
- Initialize
maxPopulation = 0andresultYear = 0. - Iterate through each year
yfrom 1950 to 2050. - For each
y, initializecurrentPopulation = 0. - Iterate through each log
[birth, death]in the inputlogs. - If
y >= birthandy < death, incrementcurrentPopulation. - After iterating through all logs, check if
currentPopulation > maxPopulation. - If it is, update
maxPopulation = currentPopulationandresultYear = y. - Return
resultYearafter the outer loop finishes.
Walkthrough
The core idea is to check each year from 1950 to 2050. For every year, we iterate through the entire logs array.
We maintain a counter for the current year's population. For each person's log [birth, death], we check if the current year falls within their lifespan [birth, death - 1].
If it does, we increment the population counter for the current year.
After checking all people for a given year, we compare the calculated population with the maximum population found so far. If the current year's population is greater, we update the maximum population and store the current year as the result.
Since the problem asks for the earliest year, we only update the result year when we find a strictly greater population. This ensures that if multiple years have the same maximum population, the first one we encounter (the earliest) is kept.
class Solution { public int maximumPopulation(int[][] logs) { int maxPopulation = 0; int resultYear = 0; // Iterate through each year from 1950 to 2050 for (int year = 1950; year <= 2050; year++) { int currentPopulation = 0; // For each year, check all logs for (int[] log : logs) { int birth = log[0]; int death = log[1]; // A person is alive if the current year is in [birth, death - 1] if (year >= birth && year < death) { currentPopulation++; } } // If we find a new maximum population, update our result if (currentPopulation > maxPopulation) { maxPopulation = currentPopulation; resultYear = year; } } return resultYear; }}Complexity
Time
O(Y * N), where Y is the number of years in the range (e.g., 2050 - 1950 + 1) and N is the number of logs. We iterate through each year, and for each year, we iterate through all the logs.
Space
O(1), as we only use a few variables to keep track of the maximum population and the result year, regardless of the input size.
Trade-offs
Pros
Simple to understand and implement.
Uses constant extra space, making it memory-efficient.
Cons
Inefficient for a large range of years or a large number of logs, as it re-calculates the population for each year from scratch.
A more efficient approach uses a difference array, a technique often associated with sweep-line algorithms. Instead of calculating the population for each year from scratch, we record the changes in population at birth and death years. A birth year marks a +1 change, and a death year marks a -1 change. By calculating a running sum of these changes, we can find the population for any year efficiently.
Algorithm
- Create an integer array
populationChangesof size 101, initialized to all zeros. This array will map years 1950-2050 to indices 0-100. - Iterate through each log
[birth, death]inlogs. - For each log, increment
populationChanges[birth - 1950]and decrementpopulationChanges[death - 1950]. - Initialize
maxPopulation = 0,resultYear = 1950, andcurrentPopulation = 0. - Iterate from
i = 0to100(representing years 1950 to 2050). - Add
populationChanges[i]tocurrentPopulation. - If
currentPopulation > maxPopulation, updatemaxPopulation = currentPopulationandresultYear = 1950 + i. - Return
resultYear.
Walkthrough
The constraints specify that years are within the range [1950, 2050]. We can create an array, let's call it populationChanges, of size 101 (or slightly larger to be safe) to represent this range. The index i of this array will correspond to the year 1950 + i.
We first iterate through the logs array. For each person [birth, death]:
- We increment the value at the index corresponding to their birth year (
birth - 1950). - We decrement the value at the index corresponding to their death year (
death - 1950).
This populationChanges array now stores the net change in population for each year.
Next, we iterate through the populationChanges array from the beginning, maintaining a currentPopulation running sum.
For each year (index i), we add populationChanges[i] to currentPopulation. This gives us the total population for the year 1950 + i.
We compare this currentPopulation with our maxPopulation seen so far. If it's greater, we update maxPopulation and the resultYear.
This method processes all birth and death events in two separate passes, which is much faster than the nested loop structure of the brute-force approach.
class Solution { public int maximumPopulation(int[][] logs) { // The years range from 1950 to 2050. We need an array to cover this range. // The size will be 2051 - 1950 = 101. int[] populationChanges = new int[101]; int minYear = 1950; // Record the change in population for each birth and death year. for (int[] log : logs) { int birthYear = log[0]; int deathYear = log[1]; populationChanges[birthYear - minYear]++; populationChanges[deathYear - minYear]--; } int maxPopulation = 0; int currentPopulation = 0; int resultYear = 0; // Iterate through the years to find the year with max population. for (int i = 0; i < populationChanges.length; i++) { currentPopulation += populationChanges[i]; if (currentPopulation > maxPopulation) { maxPopulation = currentPopulation; resultYear = minYear + i; } } return resultYear; }}Complexity
Time
O(N + Y), where N is the number of logs and Y is the range of years. We make one pass through the logs (O(N)) to populate the difference array and one pass through the year range (O(Y)) to find the maximum population.
Space
O(Y), where Y is the range of years. We need an auxiliary array of size Y (101 in this case) to store the population changes for each year.
Trade-offs
Pros
Significantly more time-efficient than the brute-force approach.
Scales well with a larger number of logs or a wider year range.
Cons
Requires extra space proportional to the range of years.
Solutions
Solution
class Solution {public int maximumPopulation(int[][] logs) { int[] d = new int[101]; final int offset = 1950; for (var log : logs) { int a = log[0] - offset; int b = log[1] - offset; ++d[a]; --d[b]; } int s = 0, mx = 0; int j = 0; for (int i = 0; i < d.length; ++i) { s += d[i]; if (mx < s) { mx = s; j = i; } } return j + offset; }}/** * @param {number[][]} logs * @return {number} */ var maximumPopulation = function (logs) { const d = new Array(101).fill(0); const offset = 1950; for (let [a, b] of logs) { a -= offset; b -= offset; d[a]++; d[b]--; } let j = 0; for (let i = 0, s = 0, mx = 0; i < 101; ++i) { s += d[i]; if (mx < s) { mx = s; j = i; } } return j + offset; };class Solution {public: int maximumPopulation(vector<vector<int>> &logs) { int d[101]{}; const int offset = 1950; for (auto &log : logs) { int a = log[0] - offset; int b = log[1] - offset; ++d[a]; --d[b]; } int s = 0, mx = 0; int j = 0; for (int i = 0; i < 101; ++i) { s += d[i]; if (mx < s) { mx = s; j = i; } } return j + offset; }};class Solution: def maximumPopulation(self, logs: List[List[int]]) -> int: d = [0] * 101 offset = 1950 for a, b in logs: a, b = a - offset, b - offset d[a] += 1 d[b] -= 1 s = mx = j = 0 for i, x in enumerate(d): s += x if mx < s: mx, j = s, i return j + offsetVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.