Facebook Interview Question for Software Engineers


Country: Israel
Interview Type: Phone Interview




Comment hidden because of low score. Click to expand.
6
of 6 vote

public Range[] merge(Range[] ranges, Range newRange)
{
  List<Range> output = new LinkedList<>();
  int b = newRange.begin;
  int e = newRange.end;
  for (Range r : ranges)
  {
    if (r.end < b || r.begin > e)
    {
      output.add(r);
    }
    else
    {
      b = Math.min(b, r.begin);
      e = Math.max(e, r.end);
    }
  }
  output.add(new Range(b, e));
  return output.toArray(new Range[output.size()]);
}

- Anonymous February 23, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

It wasn't until I read your answer that I realized the question never stated the output had to be sorted.

- Nick March 14, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Implemented your solution in C++:

#include <vector>
using namespace std;

struct Range
{
	int begin, end;
	Range(int a, int b) : begin(a), end(b) {}
};

vector<Range> mergeRanges(vector<Range> input, Range newRange)
{
	vector<Range> output;
	for (vector<Range>::const_iterator it = input.begin(); it != input.end(); ++it)
	{
		if (newRange.end < it->begin || newRange.begin > it->end)
		{
			output.push_back(*it);
		}
		else
		{
			if (it->begin < newRange.begin)
			{
				newRange.begin = it->begin;
			}
			if (it->end > newRange.end)
			{
				newRange.end = it->end;
			}
		}
	}
	output.push_back(newRange);
	return output;
}

- Nick March 14, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Sort the initial list of Range classes that do not overlap.
Given the newRange class that may or may not overlap...
Do a binary search on the sorted list of Range classes to figure out the overlapping range.
The meat of the solution lies in the criteria to search in the left/right subarrays using both the Range.begin and Range.end keys.

- Murali Mohan February 23, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

function mergeRange(ranges, range) {
 var result = [],
 toBeMerged = [],
 toBeMerged.push(range);

 ranges.forEach(function (r) {
  if (overlap(range, r)) {
    toBeMerged.push(r);
  } else {
    result.push(r);
  }
 });

 result.push(merge(toBeMerged));
 return result;
}

function merge(ranges) {
  // find min, max return a new object
  var min = ranges.reduce(function (a, b) {
    return a.begin < b.begin ? a : b;
  });

  var max = ranges.reduce(function (a, b) {
    return a.end > b.end ? a : b;
  });

  return { begin: min.begin, end: max: end };
}

function overlap(a, b) {
  // a => { begin, end }
  if (a.begin > b.begin) {
    return a.begin < b.end;
  } else {
    return b.begin < a.end;
  }
}

- Jasiri February 25, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

I would propose the following: (i) Find ranges that that overlap with the newRange (ii) merge them together one by one (iii) copy non overlapped ranges to the output and add the new merged interval.

public Range[] mergeRanges(Range[] ranges, Range newRange) {
	int N = ranges.length;
	
	/*** Detect overlaps ***/
	boolean[] isover = isOverlap(ranges, newRange);
	
	/*** Merge overlapped ranges and count the output array size ***/
	int Nout = N+1;
	Range newGuy = newRange;
	
	for (int k=0; k<N; k++) {
		if (isover[k] == false) 		continue;
		Range curr = ranges[k];
		newGuy = merge(newGuy, curr);
		Nout--;
	}

	/*** Generate output ***/
	Range[] out = new Range[Nout];
	
	for (int k =0, j=0; k<N; k++)
		if (isover[k] == false) 		out[j++] = ranges[k];
	
	out[Nout-1] = newGuy; 		// don't forget the new guy
	
	return out;
}

private Range merge(Range a, Range b) {
	int x = new int[] {a.begin, b.begin};
	int y = new Int[] {a.end, b.end};
	int begin 	= Math.min(x);
	int end 	= Math.max(y);
	return new Range(begin, end);
}

private boolean[] isOverlap(Range[] a, Range x) {
	int N = a.length;
	boolean[] out = new boolean[N];

	for (int k=0; k<N; k++) {
		if (a[k].begin < x.begin && a[k].end < x.begin) 		out[k] = false;
		else if (a[k].begin > x.end && a[k].end > x.end) 		out[k] = false;
		else 										out[k] = true;
	}

	return out;
}

- autoboli February 23, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

public static List<Range> MergeRanges(List<Range> ranges, Range overlap)
{
	int start = overlap.start;
	int end = overlap.end;
        List<Range> result = new List<Range>();
	for(int i = 0; i < ranges.Count; i++)
	{

                Ranges r = ranges[i];

		// This also covers the case where r is larger than overlap
		if(r.start < overlap.start && r.end >= overlap.start)
		{
			start = r.start;
		}
		else if(r.start <= overlap.end && r.end > overlap.end)
		{
			end = r.end;
		}
                else  if(r.start < overlap.start && r.end > overlap.end)
                {
                      start = r.start;
                      end = r.end;
                 }
                 else if(r.end < overlap.start || r.start > overlap.end)
                 {
                      result.Add(r);
                 }
	}

        result.Add(new Range(start, end));
	return result;
}

- Nelson Perez February 24, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Oops! wrong answer. I'm to sleepy to think I though it was just returning the merged set.

The problems seems to be simpler just add to a list everything found that supports the conditions and return that back without the need to calculate the big merged overlapped range.

- Nelson Perez February 24, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

function mergeRange(ranges, range) {
 var result = [],
 toBeMerged = [],
 toBeMerged.push(range);

 ranges.forEach(function (r) {
  if (overlap(range, r)) {
    toBeMerged.push(r);
  } else {
    result.push(r);
  }
 });

 result.push(merge(toBeMerged));
 return result;
}

function merge(ranges) {
  // find min, max return a new object
  var min = ranges.reduce(function (a, b) {
    return a.begin < b.begin ? a : b;
  });

  var max = ranges.reduce(function (a, b) {
    return a.end > b.end ? a : b;
  });

  return { begin: min.begin, end: max: end };
}

function overlap(a, b) {
  // a => { begin, end }
  if (a.begin > b.begin) {
    return a.begin < b.end;
  } else {
    return b.begin < a.end;
  }
}

- Jasiri February 25, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

function mergeRange(ranges, range) {
 var result = [],
 toBeMerged = [],
 toBeMerged.push(range);

 ranges.forEach(function (r) {
  if (overlap(range, r)) {
    toBeMerged.push(r);
  } else {
    result.push(r);
  }
 });

 result.push(merge(toBeMerged));
 return result;
}

function merge(ranges) {
  // find min, max return a new object
  var min = ranges.reduce(function (a, b) {
    return a.begin < b.begin ? a : b;
  });

  var max = ranges.reduce(function (a, b) {
    return a.end > b.end ? a : b;
  });

  return { begin: min.begin, end: max: end };
}

function overlap(a, b) {
  // a => { begin, end }
  if (a.begin > b.begin) {
    return a.begin < b.end;
  } else {
    return b.begin < a.end;
  }
}

- Jasiri February 25, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

function mergeRange(ranges, range) {
 var result = [],
 toBeMerged = [],
 toBeMerged.push(range);

 ranges.forEach(function (r) {
  if (overlap(range, r)) {
    toBeMerged.push(r);
  } else {
    result.push(r);
  }
 });

 result.push(merge(toBeMerged));
 return result;
}

function merge(ranges) {
  // find min, max return a new object
  var min = ranges.reduce(function (a, b) {
    return a.begin < b.begin ? a : b;
  });

  var max = ranges.reduce(function (a, b) {
    return a.end > b.end ? a : b;
  });

  return { begin: min.begin, end: max: end };
}

function overlap(a, b) {
  // a => { begin, end }
  if (a.begin > b.begin) {
    return a.begin < b.end;
  } else {
    return b.begin < a.end;
  }
}

- Jasiri February 25, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

function mergeRange(ranges, range) {
 var result = [],
 toBeMerged = [],
 toBeMerged.push(range);

 ranges.forEach(function (r) {
  if (overlap(range, r)) {
    toBeMerged.push(r);
  } else {
    result.push(r);
  }
 });

 result.push(merge(toBeMerged));
 return result;
}

function merge(ranges) {
  // find min, max return a new object
  var min = ranges.reduce(function (a, b) {
    return a.begin < b.begin ? a : b;
  });

  var max = ranges.reduce(function (a, b) {
    return a.end > b.end ? a : b;
  });

  return { begin: min.begin, end: max: end };
}

function overlap(a, b) {
  // a => { begin, end }
  if (a.begin > b.begin) {
    return a.begin < b.end;
  } else {
    return b.begin < a.end;
  }
}

- Jasiri February 25, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

function mergeRange(ranges, range) {
 var result = [],
 toBeMerged = [],
 toBeMerged.push(range);

 ranges.forEach(function (r) {
  if (overlap(range, r)) {
    toBeMerged.push(r);
  } else {
    result.push(r);
  }
 });

 result.push(merge(toBeMerged));
 return result;
}

function merge(ranges) {
  // find min, max return a new object
  var min = ranges.reduce(function (a, b) {
    return a.begin < b.begin ? a : b;
  });

  var max = ranges.reduce(function (a, b) {
    return a.end > b.end ? a : b;
  });

  return { begin: min.begin, end: max: end };
}

function overlap(a, b) {
  // a => { begin, end }
  if (a.begin > b.begin) {
    return a.begin < b.end;
  } else {
    return b.begin < a.end;
  }
}

- Jasiri February 25, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

function mergeRange(ranges, range) {
 var result = [],
 toBeMerged = [],
 toBeMerged.push(range);

 ranges.forEach(function (r) {
  if (overlap(range, r)) {
    toBeMerged.push(r);
  } else {
    result.push(r);
  }
 });

 result.push(merge(toBeMerged));
 return result;
}

function merge(ranges) {
  // find min, max return a new object
  var min = ranges.reduce(function (a, b) {
    return a.begin < b.begin ? a : b;
  });

  var max = ranges.reduce(function (a, b) {
    return a.end > b.end ? a : b;
  });

  return { begin: min.begin, end: max: end };
}

function overlap(a, b) {
  // a => { begin, end }
  if (a.begin > b.begin) {
    return a.begin < b.end;
  } else {
    return b.begin < a.end;
  }
}

- Jasiri February 25, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

function mergeRange(ranges, range) {
 var result = [],
 toBeMerged = [],
 toBeMerged.push(range);

 ranges.forEach(function (r) {
  if (overlap(range, r)) {
    toBeMerged.push(r);
  } else {
    result.push(r);
  }
 });

 result.push(merge(toBeMerged));
 return result;
}

function merge(ranges) {
  // find min, max return a new object
  var min = ranges.reduce(function (a, b) {
    return a.begin < b.begin ? a : b;
  });

  var max = ranges.reduce(function (a, b) {
    return a.end > b.end ? a : b;
  });

  return { begin: min.begin, end: max: end };
}

function overlap(a, b) {
  // a => { begin, end }
  if (a.begin > b.begin) {
    return a.begin < b.end;
  } else {
    return b.begin < a.end;
  }
}

- Jasiri February 25, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

function mergeRange(ranges, range) {
 var result = [],
 toBeMerged = [],
 toBeMerged.push(range);

 ranges.forEach(function (r) {
  if (overlap(range, r)) {
    toBeMerged.push(r);
  } else {
    result.push(r);
  }
 });

 result.push(merge(toBeMerged));
 return result;
}

function merge(ranges) {
  // find min, max return a new object
  var min = ranges.reduce(function (a, b) {
    return a.begin < b.begin ? a : b;
  });

  var max = ranges.reduce(function (a, b) {
    return a.end > b.end ? a : b;
  });

  return { begin: min.begin, end: max: end };
}

function overlap(a, b) {
  // a => { begin, end }
  if (a.begin > b.begin) {
    return a.begin < b.end;
  } else {
    return b.begin < a.end;
  }
}

- Jasiri February 25, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

The idea is, add this new range to the first element of the entire list of ranges, then use a while loop to update this set of ranges until stable - meaning the size of this list of ranges no longer changes.

Keeping the newly constructed range always in the first element, for each iteration, try to merge with the rest of the element and see if there's a successful merge, and update the list or ranges while keeping the merged range in the first element of this list.


in Python,

class Range(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __str__(self,):
        return "[%s, %s]" % (self.start, self.end)
    
def ranges_union(r1, r2):
    #sort range head
    if r1.start > r2.start:
        tmp = r1
        r1 = r2
        r2 = tmp
        
    #disjoint
    if r1.end < r2.start:
        return [r1, r2]
    #subset
    elif r1.end >= r2.end:
        return [r1]
    
    #partial overlap
    elif r1.end < r2.end:
        return [Range(r1.start, r2.end)]
    
def merge_ranges(ranges, new_range):
    output = [new_range] + ranges[:]
    
    #store the new interval on the first element, merged with others
    stable = False
    while not stable:
        stable = True
        for r in output[1:]:
            merge_result = ranges_union(output[0], r)
            if len(merge_result) == 1: #merged
                output.remove(r)
                output[0] = merge_result[0]
                stable = False
                break
    return output
    
def print_ranges(ranges):
    for r in ranges:
        print r


#test        
r1 = Range(1, 3)
r2 = Range(5,7)
r3 = Range(9, 11)
ranges = [r1, r2, r3]
new_range = Range(1, 4)

print_ranges(merge_ranges(ranges, new_range))

- CC February 26, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Take each entry in the rangelist and merge it with the new range...
O(n)

import java.util.*;
public class Ranges {
	public static class Range{
		public int begin;
		public int end;
		public Range(int begin,int end){
			this.begin = begin;
			this.end = end;
		}
		
		public String toString(){
			return " " + this.begin + "-" + this.end;
		}
	}
	 
	public static ArrayList<Range> merge(ArrayList<Range> rangelist, Range range){
		
		Iterator<Range> i = rangelist.iterator();
		while(i.hasNext()){
			Range r = i.next();
			if(canMerge(r,range)){
				merge(r,range);
				i.remove();
			}
		}
		rangelist.add(range);
		return rangelist;
	}

	private static boolean canMerge(Range r, Range range) {
		// TODO Auto-generated method stub
		return ((r.begin >= range.begin && r.begin <= range.end)||
				(r.end >= range.begin && r.end <= range.end)||
				(range.begin >= r.begin && range.begin <= r.end)||
				(range.end >= r.begin && range.end <= r.end));
				
	}

	private static void merge(Range r, Range range) {
		if(range.begin > r.begin)
			range.begin = r.begin;
		if(range.end< r.end)
			range.end = r.end;
	}
	
	public static void main(String arg[]){
		Range r = new Range(1,5);
		Range r2 = new Range(9,13);
		Range r3 = new Range(17,22);
		ArrayList<Range> rangelist= new ArrayList<Range>();
		rangelist.add(r);
		rangelist.add(r2);
		rangelist.add(r3);
		System.out.println(merge(rangelist,new Range(4,10)));
	}
}

- ranger March 01, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

ArrayList<Range> merge(ArrayList<Range> list, Range range) {
	sort(list);
	
	int idx = 0;
	while (idx < list.size() && range.begin > list.get(idx).end) {
		idx++;
	}
	
	if (range.begin > list.get(idx).begin) {
		range.begin = list.get(idx).begin;
	}
	
	int idx1 = idx;
	while (idx1 < list.size() && range.end >= list.get(idx1).begin) {
		idx1++;
	}
	
	
	if (range.end < list.get(idx1 - 1).end) {
		range.end = list.get(idx1 - 1).end;
	}
	
	for (int i = idx; i < idx1; i++) {
		list.set(i,  null);
	}
	list.set(idx, range);
	return list;
}

- jasmine8gu March 23, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

I assumed the inputs are the list of ranges and new range.

I used quicksort to sort the list of existing ranges and new range together by begin value.
After that scan the list and merge the overlapping ranges.
Running time is O(n log n), where n is the number of ranges in the list.

#include <list>
#include <string>
#include <climits>
#include <iostream>

using namespace std;

bool isNum(char c)
{
	return (c >='0' && c<='9');
}

bool isOp(char c)
{
	return (c =='+'|| c== '-'||c=='/'|| c=='*');
}

bool multiOrDiv(char c)
{
	return (c == '*' || c == '/');
}

int compute(int l, int r, char op)
{
	if (op =='+')
		return l+r;
	else if (op == '-')
		return l-r;
	else if (op == '*')
		return l*r;
	else if (op == '/')
		return l/r;
	return INT_MIN;
}

int eval_expr(string input)
{
	list<int> numbers;
	list<char> ops;
	string token;
	int result;

	for (int i = input.length()-1; i >= 0; i--)
	{
		int num;
		if (isNum(input[i]))
		{
			token.insert(0,1, input[i]);
			if (i == 0 && token.length())
			{
				num = atoi(token.c_str());
				numbers.push_back(num);			
			}		
		} else if (isOp(input[i]))
		{
			if (token.length())
			{
				num = atoi(token.c_str());
				numbers.push_back(num);
				token = "";
			}
			if (!multiOrDiv(input[i]))
			{
				char op = ops.back();
				while (multiOrDiv(op) && numbers.size() >1)
				{
					ops.pop_back();
					int l = numbers.back();
					numbers.pop_back();
					int r = numbers.back();
					numbers.pop_back();
					int result = compute(l, r, op);
					numbers.push_back(result);
					op = ops.back();
				}		
			}
			ops.push_back(input[i]);		
		}	
	}

	while (numbers.size() >1 && ops.size() >0)
	{
		char op = ops.back();
		ops.pop_back();
		int l = numbers.back();
		numbers.pop_back();
		int r = numbers.back();
		numbers.pop_back();
		result = compute(l, r, op);
		numbers.push_back(result);	
	}	
	return numbers.back();
}

- hankm2004 July 13, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

I did not know the output does not have to be sorted. If that is the case, the following algorithm will give O(N) running time.

vector<Range> mergerange(vector<Range> &input, Range &newrange)
{
  int start = newrange.begin;
  int end = newrange.end;
  vector<Range> result;

  for (int i= 0; i <input.size(); i++)
  {
    if (start> input[i].end || end < input[i].begin)
    {
      result.push_back(input[i]);
    }
    else {
      start = (start< input[i].begin)? start: input[i].begin;
      end = (end > input[i].end)? end: input[i].end;
    }
  }
  result.push_back(Range(start, end));
  return result;
}

- hankm2004 July 13, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

public static List<Range> MergeRanges(Collection<Range> ranges, Range newRange) {
        BitSet bs = new BitSet();
        bs.set(newRange.Begin, newRange.End+1, true);
        for (Range r : ranges) bs.set(r.Begin, r.End + 1, true);
        List<Range> newRanges = new LinkedList<>();
        for (int begin = bs.nextSetBit(0), end = 0; begin >= 0; begin = bs.nextSetBit(end)) {
            end = bs.nextClearBit(begin);
            newRanges.add(new Range(begin, end - 1));
        }
        return newRanges;
    }

- Lucidio August 07, 2017 | Flag Reply


Add a Comment
Name:

Writing Code? Surround your code with {{{ and }}} to preserve whitespace.

Books

is a comprehensive book on getting a job at a top tech company, while focuses on dev interviews and does this for PMs.

Learn More

Videos

CareerCup's interview videos give you a real-life look at technical interviews. In these unscripted videos, watch how other candidates handle tough questions and how the interviewer thinks about their performance.

Learn More

Resume Review

Most engineers make critical mistakes on their resumes -- we can fix your resume with our custom resume review service. And, we use fellow engineers as our resume reviewers, so you can be sure that we "get" what you're saying.

Learn More

Mock Interviews

Our Mock Interviews will be conducted "in character" just like a real interview, and can focus on whatever topics you want. All our interviewers have worked for Microsoft, Google or Amazon, you know you'll get a true-to-life experience.

Learn More