PuzzlersWorld.com

  • Hacker Puzzle
  • Interview Puzzles
  • Number Puzzles
  • Maths Puzzles

Find the Min solution: Facebook hacker Cup 2013 Qual Round

(No Ratings Yet)

January 29, 2013 by puzzler 4 Comments

From 2011 facebook is organizing a Facebook hacker cup every year around feb, visit Facebook hacker cup homepage for more details

This question is the third question(Carried 45 marks out of 100) for the qualification round 2013 hacker cup.

Problem Statement

After sending smileys, John decided to play with arrays. Did you know that hackers enjoy playing with arrays? John has a zero-based index array, m, which contains n non-negative integers. However, only the first k values of the array are known to him, and he wants to figure out the rest.

John knows the following: for each index i, where k <= i < n, m[i] is the minimum non-negative integer which is *not* contained in the previous *k* values of m.


For example, if k = 3, n = 4 and the known values of m are [2, 3, 0], he can figure out that m[3] = 1.

John is very busy making the world more open and connected, as such, he doesn’t have time to figure out the rest of the array. It is your task to help him.

Given the first k values of m, calculate the nth value of this array. (i.e. m[n – 1]).

Because the values of n and k can be very large, we use a pseudo-random number generator to calculate the first k values of m. Given non-negative integers a, b, c and positive integer r, the known values of m can be calculated as follows:

  • m[0] = a
  • m[i] = (b * m[i – 1] + c) % r, 0 < i < k

Input

The first line contains an integer T (T <= 20), the number of test cases.
This is followed by T test cases, consisting of 2 lines each.
The first line of each test case contains 2 space separated integers, n, k (1 <= k <= 105, k < n <= 109).
The second line of each test case contains 4 space separated integers a, b, c, r (0 <= a, b, c <= 109, 1 <= r <= 109).

Output

For each test case, output a single line containing the case number and the nth element of m.

Example Input

5
97 39
34 37 656 97
186 75
68 16 539 186
137 49
48 17 461 137
98 59
6 30 524 98
46 18
7 11 9 46

Example Output

Case #1: 8
Case #2: 38
Case #3: 41
Case #4: 40
Case #5: 12

Solution 1

It looked like this question was to test the complexity, as if you do it in normal ways, without applying a little thought(how can we make it faster) You wont be able to solve it in 6 mins.

Main key is to realize that next k+1 numbers will be from 0 to k and then they repeat, how? will explain in detail later. so to get the nth number you simple get k + (n-k)%(k+1) number.

Also you cant take whole n numbers(109) in memory so just have to take k numbers(105) in memory and keep on deleting oldest number after adding the new number.

Explanation


First we will take a queue to keep k numbers(for current window), now as a new number comes into the window we will pop the first element in the queue and add the new element at the end of the queue, thus at any point of time this queue will have k previous numbers to determine the new number. Also we will keep one hashmap to store numbers in the queue and their occurrences, we will maintain this number of occurences while adding or deleting a number from the queue. Lastly we will keep a range of continuous subsequence of smallest numbers(start and end of the subsequence) and maintain this subsequence as and when a new number is added/deleted from the queue.

Lets take an example input list: 5, 3, 7, 5, 1, 2
Here k = 6 and continuous subsequence of smallest numbers is 1, 2, 3 thus start will be 1 and end will be 3

Now to get the next number=> minimum non-negative integer not in the queue, we can get is based on the range, if range.start is > 0 then the minimum non-negative integer possible is 0.
Thus now the queue will become 3, 7, 5, 1, 2, 0 => range should also change=> we can say our range is now 0 to 3(based on the removed and added number, think a bit)

Now again to get the next number=> from the range, as now range.start=0, so the new number should be (range.end +1), i.e. 4
Thus now the queue will become 7, 5, 1, 2, 0, 4 => range should also change=> we can say our new range is 0 to 2 (based on the removed and added number)

Now again to get the next number=> from the range, as now range.start=0, so the new number should be (range.end +1), i.e. 3
Thus now the queue will become 5, 1, 2, 0, 4, 3 => range should also change=> we can say our new range(based on the removed and added number) is 0 to 3 + (might be there is 4, we will use hashmap here to check, see funtion getNewEndFromMap)

This solution is close to O(k) in time and executes all the 20 cases in 0.7 seconds.

	class Range {
		int start;
		int end;

		public Range(int value, int index) {
			this.start = value;
			this.end = index;
		}
	}

	// initialize the element array
	private LinkedList<Integer> getElementArray(int k, int a, int b,
			int c, int r) {
		LinkedList<Integer> elemArr = new LinkedList<Integer>();
		int currNumber = a;
		for (int i = 0; i < k; i++) {
			elemArr.addLast(currNumber);
			currNumber = getNextValue(currNumber, a, b, c, r);
		}
		return elemArr;
	}

	private int getNextValue(int currVal, int a, int b, int c, int r) {
		return (int) ((((long) b) * currVal + c) % r);
	}

	// To get the Nth number based on the condition
	public int getNthNumber(int n, int k, int a, int b, int c, int r) {
		b = b % r;
		c = c % r;
		LinkedList<Integer> queue = getElementArray(k, a, b, c, r);
		HashMap<Integer, Integer> numberAndCounts = new HashMap<Integer, Integer>();
		for (Integer num : queue) {
			Integer val = numberAndCounts.get(num);
			if (val == null) {
				val = 1;
			} else {
				val++;
			}
			numberAndCounts.put(num, val);
		}

		int ans = 0;

		Range range = getRangeOfSubsquence(queue);

		int maxRange = k + (n - k) % (k + 1);

		for (int i = k; i < maxRange; i++) {

			int nextValue = 0;
			if (range.start == 0) {
				nextValue = range.end + 1;
			}
			ans = nextValue;
			insertAndRemoveOlder(queue, numberAndCounts, range,
					nextValue);
		}
		return ans;
	}

	private void insertAndRemoveOlder(LinkedList<Integer> queue,
			HashMap<Integer, Integer> map, Range range, int nextValue) {
		Integer removedValue = queue.remove();
		int countOfRemoved = map.get(removedValue);
		boolean isRemovedFromMap = false;
		if (countOfRemoved > 1) {
			countOfRemoved--;
			map.put(removedValue, countOfRemoved);
		} else {
			map.remove(removedValue);
			isRemovedFromMap = true;
		}

		queue.addLast(nextValue);
		Integer countOfNewAdded = map.get(nextValue);
		if (countOfNewAdded == null) {
			countOfNewAdded = 1;
		} else {
			countOfNewAdded++;
		}
		map.put(nextValue, countOfNewAdded);

		if ((removedValue <= range.end && removedValue >= range.start)
				&& isRemovedFromMap) {
			if (range.start == removedValue) {
				if (range.end == range.start) {
					// Your code will come here maximum once in its life time
					Range newRange = getRangeOfSubsquence(queue);
					range.start = newRange.start;
					range.end = newRange.end;
				} else {
					range.start = range.start + 1;
				}
			} else {
				range.end = removedValue - 1;
			}
		}

		if (nextValue < range.start) {
			if (nextValue == range.start - 1) {
				range.start = nextValue;
			} else {
				range.start = nextValue;
				range.end = nextValue;
			}
		} else if (nextValue > range.end) {
			range.end = getNewEndFromMap(map, range.end);
		}

	}

	//After adding new element in the range @ the end it will check if the range can be increased more for ex 
	// current range is 4, 7 and new element added is 8 then it checks if 9(after theat 10, 11 etc) exists in the map
	private int getNewEndFromMap(HashMap<Integer, Integer> map,
			int nextvalue) {
		int ret = nextvalue;
		for (int i = nextvalue;; i++) {
			if (map.get(i) == null) {
				ret = i - 1;
				break;
			}
		}
		return ret;
	}

	// This returns the subsequence range containing smallest numbers
	// So for input list 4 5 19 7 6 20 21, it should consider subsequence 4, 5, 6, 7 and start will be 4 end will be 7
	private Range getRangeOfSubsquence(
			LinkedList<Integer> queue) {

		ArrayList<Integer> array = new ArrayList<Integer>();
		array.addAll(queue);
		Collections.sort(array);

		int start = array.get(0);
		int end = array.get(0);
		for (int i = 0; i < array.size(); i++) {
			if (array.get(i) > end + 1) {
				break;
			}
			end = array.get(i);
		}
		return new Range(start, end);
	}

Solution 2

We are just constructing the first k elements of array m, by using the formula m[i] = (b * m[i – 1] + c) % r

While constructing the elements, we are also keeping track of the last position at which any number m[i] appeared, where 0 <= m[i] < (k+1); The array called is posArray and it’s index are the numbers we are keeping track of.

As explained in the solution 1, the m[j] = m[n-1]  where j = k + (n-k)%(k+1); OR you can say, after first k elements we need to construct next ((n-k)%(k+1))th element, lets call it index.

Now, as we start constructing the next elements, we will take the first element with last position as ZERO, and reduce the position count for other indexes.

This solution is O(k*k) and runs all the test cases in around 2 minutes.

public class FindTheMin {
	/**
	 * 
	 * @param x = n k
	 * @param y = a b c r
	 * @return
	 */
	private static int getTheMin(String x, String y) {
	        // m[i] = (b * m[i - 1] + c) % r 
		String[] inputLine1 = x.split(" ");
		String[] inputLine2 = y.split(" ");

		int n = Integer.parseInt(inputLine1[0]);
		int k = Integer.parseInt(inputLine1[1]);

		int a = Integer.parseInt(inputLine2[0]);
		int b = Integer.parseInt(inputLine2[1]);
		int c = Integer.parseInt(inputLine2[2]);
		int r = Integer.parseInt(inputLine2[3]);

		//System.out.println(n + ", " + k);
		//System.out.println(a + ", " + b + ", " + c + ", " + r);

                // We need to find the ((n-k)%(k+1))th element after first k elements
		// as (k+1) numbers will repeat in same order
               

		int index = ((n-k)%(k+1)) ;
                // Initializing the array, of length k+1, with initial values as 0
		// which will contain the (pos+1)
		// where pos is the last position at which number appeared in first k elements.
		 

		int[] posArray = new int[k+1];

		long[] m = new long[k]; 
		m[0] = a;

		if (a < k+1)
			posArray[a] = 1;

		// constructing the first k elements
		for (int i=1; i<k; i++)
		{
			m[i] = (b * m[i - 1] + c) % r;
			// array construction can be avoided by storing m[i-1] in a field
			if (m[i] < k+1)
			{
				posArray[(int)m[i]] = i + 1; 
			}
		}

		for (int j = 0; j < index; j++)
		{
			boolean setZero = false;
			for (int i = 0; i < k+1; i++)
			{
				if (posArray[i] == 0){
					if (j == (index-1))
					{
						return i;
					}
					if (!setZero){
						posArray[i] = k+1; // setting large value for first 0
						setZero = true;
					}					
				}
				else{
					posArray[i] = posArray[i] - 1;
				}
			}
			setZero = false;
		}

		return 0;
	}
}
  • Share on Whatsapp
  • Share on Facebook
  • Share on Twitter
Facebook Comments
Next Puzzle
Card Game solution: Facebook hacker cup 2013 Round1

Checkout more Interview Questions Tags: Facebook Hacker Cup, Interview, Java, Solved Puzzles, Very Difficult

Comments

  1. Adam Ryan Duren says

    January 29, 2013 at 7:43 pm

    Can you fix the html entities in the source code?

    Reply
    • puzzlersworld says

      January 30, 2013 at 3:57 am

      Thanks @facebook-1094790043:disqus updated the source code for solution 2

      Reply
  2. Sandeep says

    January 29, 2013 at 7:15 am

    Can you explain the logic in detail

    Reply
    • puzzlersworld says

      January 30, 2013 at 3:57 am

      Sandeep Thanks for the query: updated explanation in the post, here it is for you :- First we will take a queue to keep k numbers(for current window), now as a new number comes into the window we will pop the first element in the queue and add the new element at the end of the queue, thus at any point of time this queue will have k previous numbers to determine the new number. Also we will keep one hashmap to store numbers in the queue and their occurrences, we will maintain this number of occurences while adding or deleting a number from the queue. Lastly we will keep a range of continuous subsequence of smallest numbers(start and end of the subsequence) and maintain this subsequence as and when a new number is added/deleted from the queue.
      Lets take an example input list: 5, 3, 7, 5, 1, 2
      Here k = 6 and continuous subsequence of smallest numbers is 1, 2, 3 thus start will be 1 and end will be 3

      Now to get the next number=> minimum non-negative integer not in the queue, we can get is based on the range, if range.start is > 0 then the minimum non-negative integer possible is 0.
      Thus now the queue will become 3, 7, 5, 1, 2, 0 => range should also change=> we can say our range is now 0 to 3(based on the removed and added number, think a bit)

      Now again to get the next number=> from the range, as now range.start=0, so the new number should be (range.end +1), i.e. 4
      Thus now the queue will become 7, 5, 1, 2, 0, 4 => range should also change=> we can say our new range is 0 to 2 (based on the removed and added number)

      Now again to get the next number=> from the range, as now range.start=0, so the new number should be (range.end +1), i.e. 3
      Thus now the queue will become 5, 1, 2, 0, 4, 3 => range should also change=> we can say our new range(based on the removed and added number) is 0 to 3 + (might be there is 4, we will use hashmap here to check, see funtion getNewEndFromMap)

      Reply

Leave a Comment Cancel reply

Submit your Puzzle

You may also like

  • Find a pythagorean triplet from an array
  • Osmos Solution: Google codejam 2013 Round 1B
  • Swap two integer variables
  • DS with insert, delete and getRandomElement in O(1)
  • Find middle element of linked list
  • Lawnmower Solution: Google codejam 2013 Qual Round
  • Objective Questions set C/C++ – Part 3
  • Bullseye Solution: Google codejam 2013 Round 1A
  • Balanced Smileys solution: Facebook hacker Cup 2013 Qual Round
  • 3 SUM problem

Categories

  • Aive hi Puzzles
  • Akbar and Birbal
  • Alphabetical Puzzles
  • Bollywood Puzzles
  • Google Code jam
  • Hindi Riddles
  • Interview Puzzles
  • Interview Questions
  • Logical Puzzles
  • Malayalam Puzzles
  • Maths Puzzles
  • Miscellaneous
  • Number Puzzles
  • Picture Puzzles
  • Riddles
  • Tamil Puzzles
  • Technical

Social

  • View puzzlersworld’s profile on Twitter
privacy policy

Copyright © 2025 · eleven40 Pro Theme on Genesis Framework · WordPress · Log in

  • Hacker Puzzle
  • Logo Puzzles
  • Optical Illusions
  • WhatsApp Puzzles
  • Picture Puzzles
  • Riddles
    ▼
    • Hindi Riddles
  • Bollywood Puzzles
  • Alphabetical Puzzles
  • Aive hi Puzzles
  • Interview Puzzles
  • Logical Puzzles
  • Interview Questions
    ▲
    • Data Structures
    • Binary Tree
    • Algorithms
    • Recursion Questions
    • Amazon Interview Questions
    • Snapdeal Interview Questions
    • Google Code jam
  • Technical
  • Akbar and Birbal
  • Number Puzzles
  • Maths Puzzles
  • Miscellaneous