Google Interview Question for Software Engineers


Country: India
Interview Type: Phone Interview




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

We'd have to use dynamic programming to solve this one, since there are 2^(m) combinations of making even the first cut.

My algorithm is listed below in pseudocode:

Rod-cutting problem
Say we have range i...j in consideration.
C(i, j) = cost of cutting a rod between markings i and j
i, j = 0, 1, …, m+1
C(i, j) = MIN/k {C(i,k) + C(k, j) + (j - i)}, k = i+1, …,j-1
So, 
i → 0, 1, …,m+1
j → 0, 1, …,m+1
for each {i,j}
    k → i+1, …,j-1
Time complexity: O(m^3)
Space complexity: O(m^2)
Initialization: C(0, 0) = 0; C(i, i) = 1 for i = 1, …,m+1
Return: C(0, m+1)

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

C(i, j) = MIN/k {C(i,k) + C(k, j) + L(j - i)}, k = i+1, …,j-1

What the above line says is basically, if I cut at position k between i and j, then to minimum cost of this cut, is going to be the minimum cost of further cutting up rods ranging {i, k} and {k, j}. This is as per the optimal substructure rule. In addition, I need to add the cost of making this cut at k, which is L(j - i).

L(j - i) is the length of the rod from marking i to marking j (remember, the markings aren't always uniform! :) )

Also, an edit: j ranges from {i, i+1, ..., m+1}.

- Killedsteel April 13, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Shouldn't C(i, i) = 0 for all i?

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

Can't we optimize here by collapsing the 2D array down to a 1D array minCosts where minCosts[i] = minimum cost of cutting a log of length m*i ?

Basically, what I'm suggesting is that the minimum cost of cutting a certain length of log, say C[i,j] is the same as C[i-1,j-1] since the log segments are the same length.

If we compute the minimum cost just purely on length of the log, I think the n-square computation inside the outer loop can be collapsed down to n, making the total running time O(n-square).

Somehow, I can't convince myself that we need O(n-cube).

- ac_rocker85 May 04, 2015 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

I don't think there is a viable greedy solution here (pick the median cut point each time? the cut point closest to the middle?), so we'll have to use dynamic programming and memoization:

def cut_log(arr):
    """Returns minimum cost of cutting the log."""
    if len(arr) <= 2:
	return 0
    optimal_cut_point = argmin_i(cut_log(arr[:i+1]) + cut_log(arr[i:]))
    return max(arr) - min(arr) + cut_log(arr[:i+1]) + cut_log(arr[i:]))

- Alex C. April 10, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

can you explain your solution?

- aka[1] April 12, 2015 | Flag
Comment hidden because of low score. Click to expand.
1
of 3 vote

Surprisingly there is no need for a program to calculate. This is more like a brain teasing question. The lease cost is n - max(di), which di represents the length of log between neighbor markings. Each time cut off the shorter log on the sides of log and the log with longest length remains in the hard at the end.

Follow this blog, cpluspluslearning-petert.blogspot.co.uk/2015/04/minimize-cost-of-cutting-log-google.html, to see the induction.

- peter tang April 18, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
1
of 1 vote

You are assuming that the markings are evenly spaced, which is not neccessarily true.

- anvesh.subs June 15, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Could you be a bit more specific about how the marking can be done unevenly? Example?

- peter tang June 15, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

I will consider the most optimal case which is the marking are equally spaced.
So let L be the distance between two consecutive marking. N will then be equal to (M+1)*L.
The best way to cut in this case is to cut at the marking M/2, then M/4, etc...until we reach L
This cutting path costs Log(N), since there are M similar paths. The total cost will be M*Log(N).
This solution is better than cutting the markings in sequence starting with the 1st, then 2nd, then 3rd until Mth. Which results in a cost of (M+1)*N/2


However since we don't know if the markings are equally spaced, the best solution is to try to get as close as possible to the optimal one (explained above) by cutting at the marking which is the closest to the middle of the segment.

- zsalloum April 10, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Should'nt it be N*log(M)? You basically have M leaves at the bottom of the tree.

- kabhat April 12, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Is this a trick question? If I cut the log after each first word, the cost is just m (because we are not cutting the last remaining log containing n-m words).

- mithya April 11, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Here's working code for this problem, along with a test case (input expected to be clean):

public class LogCuttingProblem {

    public static void main(String[] args) {
        System.out.println(calculateLogCuttingCost(100, new int[]{23, 34, 35, 68, 71, 88, 93}));
    }
    
    public static int calculateLogCuttingCost(int n, int[] markings) {
        int m = markings.length;
        int[] newMarkings = new int[m+2];
        newMarkings[0] = 0;
        newMarkings[m+1] = n;

        for(int j=1; j<m+1; j++) {
            newMarkings[j] = markings[j-1];
        }
        m = newMarkings.length;

        int[][] cmatrix = new int[m][m];
        cmatrix[0][0] = 0;

        cmatrix[0][1] = newMarkings[1];
        cmatrix[m-2][m-1] = n - newMarkings[m-2];

        for(int i=1; i<m-2; i++) {
            cmatrix[i][i+1] = newMarkings[i+1] - newMarkings[i]; // sub-logs with no markings
        }

        for(int windowSize=1; windowSize<m; windowSize++) {
            for(int i=0; i+windowSize<m; i++) {
                int j = i + windowSize;
                int minCost = Integer.MAX_VALUE;
                for(int k=i+1; k<j; k++) {
                    int currCost = cmatrix[i][k] + cmatrix[k][j] + newMarkings[j] - newMarkings[i];
                    if(currCost < minCost) minCost = currCost;
                }
                if(j != i+1)cmatrix[i][j] = minCost;
            }
        }
        return cmatrix[0][m-1];
    }
}

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

You have a bug: System.out.println(calculateLogCuttingCost(100, new int[]{}));
Cutting a rod with length 100 without markings costs 0.
Here is my proposal:

/**
  The plan
  ======
  M markings => M+2 markings, including the beginning and the end of the log
  dp[i][j] = optimum cost cutting up log between marking i and marking j
  dp[i][j] = if |j-i| < 2 then 0, same marking or no inbetween markings
     dp[i][j] = dp[i][k]+dp[k][j]+logLen(i,j) over all k:i+1..j-1
  O(M**2) different (i,j) pairs:
     maximum O(M) different cuts between i and j:
       1 sum calculation, 1 length calculation  -> time:O(1), space:O(M)
dp time: O((M**2)*M), space: O(M**2)
**/
public class CarerrCup_5188262471663616{
  public static void main(String[]args){
    System.out.println(findMinCost(new int[]{1, 3, 7, 10}, 15));
    System.out.println(findMinCost(new int[]{}, 15));
    System.out.println(findMinCost(new int[]{1}, 15));
    System.out.println(findMinCost(new int[]{23, 34, 35, 68, 71, 88, 93}, 100));
  }
  private static int findMinCost(int[] markings, int len){
    int[] logLen = logLen(markings, len);
    int[][] dp = new int[markings.length+2][markings.length+2];
    for(int betweenMarkCount = 1;
        betweenMarkCount <= markings.length;
        ++betweenMarkCount){
      for(int i = 0;; ++i){
        int j = i+betweenMarkCount+1;
        if (j >= dp.length) break;
        int min = Integer.MAX_VALUE;
        int cost = logLen[j]-logLen[i];
        for(int k = i+1; k <= j-1; ++k){
          min = Math.min(min, dp[i][k]+dp[k][j]+cost);
        }
        dp[i][j] = min;
      }
    }
    return dp[0][dp.length-1];
  }
  private static int[] logLen(int[] markings, int len){
    int[] ret = new int[markings.length+2];
    for(int i = 1; i <= markings.length; ++i){
      ret[i] = markings[i-1];
    }
    ret[ret.length-1] = len;
    return ret;
  }
}

- madno May 01, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

DUP of 13467664

- mytestaccount2 April 13, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

This is my solution using modified binary search to find the closest possible cut that is in the middle of the log:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int find_price(vector<int> &cuts, int from, int to) {
	
	if (from >= to-1) return 0;
	
	int dist=cuts[to]-cuts[from], m=(from+to)/2, cut = -1;
	int target=cuts[from]+dist/2, curdiff = dist, tmpdiff = abs(target - cuts[m]);
	
	while (m>from && m<to && curdiff>tmpdiff) {
		
		curdiff = tmpdiff;
		cut = m;
		// Left or right?
		if (abs(target-cuts[m-1]) < abs(target-cuts[m+1])) {
			tmpdiff = abs(target-cuts[--m]);
		} else {
			tmpdiff = abs(target-cuts[++m]);
		}
	}
	
	if (cut > -1) {
		dist += find_price(cuts, from, cut),
		dist += find_price(cuts, cut, to);
	}
	return dist;
}

int main() {
	
	const int len = 80;
	vector<int> cuts = {30,41,67,5,10,15,20,25};
	
	cuts.push_back(0);
	cuts.push_back(len);
	sort(cuts.begin(), cuts.end());
	
	cout << find_price(cuts, 0, cuts.size()-1);
	
	return 0;
}

- nikolay.dimitrov April 14, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

The complexity is about (n+1)*logn which is ok

- nikolay.dimitrov April 14, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Just cut the log in half and then each successive piece in half until you make all the cuts.

- Bill May 17, 2015 | 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