DEV Community

Cover image for Algorithms: Common Years Problem
Mohammed Shaikh
Mohammed Shaikh

Posted on

Algorithms: Common Years Problem

I wanted to write about an interesting question I faced in a technical interview:

Given an array of arrays containing birth years and death year of people find out the most common years amongst them.

 [[1901,1950],[1930,1960],[1973,2022]]
Enter fullscreen mode Exit fullscreen mode

The steps I use to solve any algorithm problem:

  1. Find out how I would do it manually.
  2. Write them down as steps.
  3. Translate into code.

1. Find out how I would do it manually.

The manual way would be to go through each set and remember the range.for ex, the first set is from 1901 to 1950. At the back of our mind, we can remember those years as occurring once, then we go on to the next set. We remember the next set so we can already see the overlap. The first two have been alive together from 1930 to 1950. Then, we move on to the third and last set and we can see that it does not overlap with the other two.

Few things to note. Firstly, we need to connect occurrences to years. Secondly, the years with the most occurrences are the maximum occurences.

2. Write them down as steps.

To solve this problem, we need to connect each year with the amount of occurences. Afterwards, we need to find the max occurence and find out all the years that have that.

I decided to use hash to connect{1901 => 1}.

3. Translate into code.

This is code version of the steps:

def findCommonYear(arr)
    years = {}
    arr.each do |year_set|
        start_year = year_set[0]
        end_year = year_set[1]
        while start_year <= end_year do
            puts start_year
            if years[start_year]
                years[start_year] += 1
            else
                years[start_year] = 1
            end
            start_year += 1
        end
    end
    if years.values.max != 1 
        max_common_count = years.values.max
    else
        return 0
    end
    max_common_years = []
    years.each do |key,value|
        if value == max_common_count
            max_common_years << key
        end
    end
    return max_common_years
end

puts findCommonYear([[1910, 1950], [1900, 1951], [1945, 2000]])
Enter fullscreen mode Exit fullscreen mode

Top comments (4)

Collapse
 
namhle profile image
Nam Hoang Le

Hi Mohammed Shaikh, I want to contribute to your post to make it clearer and reach more reader.
Firstly, about problem description, there is no reason to return 0 if no two arrays overlap each other, just return all possible years. But, maybe we can return nil if array input is empty.

Next, let me rewrite your solution with some Ruby features I know:

def find_common_year(arr)
    return nil if arr.empty?
    counter = Hash.new(0)
    arr.each do |start_year, end_year|
        while start_year <= end_year do
            counter[start_year] += 1
            start_year += 1
        end
    end
    max_count = counter.values.max
    counter.keys.select { |year| counter[year] == max_count }
end

Finally, if we modify problem statement to find only one year among all possible years then there is another solution which has O(n) complexity with n is length of array input.

Please tell me if I'm wrong somewhere.

Collapse
 
mqshaikh8 profile image
Mohammed Shaikh

Hi Nam H. Le,
I wanted to return 0 because there are no years overlapping. That was the original question. As for the modification of the problem statement, I am interested. What would be the problem statement. Let me know what you think 😃

Collapse
 
namhle profile image
Nam Hoang Le

First of all, to avoid ambiguation, we assume that if a person born (or die), he will born in the first (last) day of that year.
My solution is to create two 2-tuple for each person: (start_year, 1) and (end_year, -1).
And this one has O(nlogn) complexity. I'm wrong in previous coment.

def find2 arr
  ans, max_count, curr_count = nil, 0, 0
  arr
  .flat_map {|start_year, end_year| [[start_year, 1], [end_year, -1]]}
  .sort {|(s1, e1), (s2, e2)| s1 != s2 ? s1 <=> s2 : e2 <=> e1}
  .each {|year, delta|
    curr_count += delta
    ans, max_count = year, curr_count if curr_count > max_count
  }
  ans
end

find2([[1,5], [5, 9], [2,7]]) #  => 5

# [1      5]
#        [5       9]
#   [2        7]


#           count
# [1, 1]  => 1 
# [2, 1]  => 2
# [5, 1]  => 3 : max
# [5,-1]  => 2
# [7, -1] => 1
# [9,-1]  => 0
Thread Thread
 
mqshaikh8 profile image
Mohammed Shaikh

Thanks Nam H. Le. That is an interesting variation of the problem