Google Interview Question
Software Engineer / DevelopersCountry: United States
Well then the question is re-defining what "sub-array" means. I do not think any interviewer would want to do that.
yeah seems the correct way to solve this provided interviewer asked only for subarray.
Given array of pairs is from 0...N-1.
Pair has first and second elements, where first indicates the order and second indicates element value, which needs to be added for sum.
int max_ending_here, max_ending_so_far = 0;
int begin, end = 0;
int begin_temp = begin;
for(int i = 1; i< pairsArray.length; i++)
{
if(pairsArray[i-1].first < pairsArray[i].first)
{
if(max_ending_here < 0)
{
max_ending_here = pairsArray[i].second;
begin_temp = i;
}
else
{
max_ending_here += pairsArray[i].second;
}
if(max_ending_here >= max_ending_so_far)
{
max_ending_so_far = max_ending_here;
begin = begin_temp;
end = i;
}
}
else
{
max_ending_here = 0;
begin_temp = i;
}
}
This was good question. I guess if the interviewer was to test the thinking , then he must have asked for sub-Array. But if it has been to test whether you can apply different algorithm techniques, then he might have asked for sub-sequence.
Kadane algorithm
def max_sum(seq):
max_sum_= 0
sum_ = 0
for i in seq:
if sum_ + i < 0:
sum_ = 0
else:
sum_ += i
max_sum_ = max(sum_, max_sum_)
print "Max sum is {0}".format(max_sum_)
Modified for this problem:
def max_sum_sorted(seq_pairs):
max_sum_= 0
sum_ = 0
# Initialize to the maximum negative integer
prev_first = -sys.maxint
for pair in seq_pairs:
# first element has to be sorted
first, second = pair
if first < prev_first:
sum_ = 0
if sum_ + second < 0:
sum_ = 0
else:
sum_ += second
max_sum_ = max(sum_, max_sum_)
prev_first = first
print "Max sum is {0}".format(max_sum_)
This algorithm will give the consecutive sub-array with the two properties. But in a general case where the sub-array needs not to be consecutive, the algorithm will not give the optimal solution.
This problem is a weighted version of the longest increasing subsequence problem. I give a O(n^2) algorithm below:
double max_sum(List pairs){
pairs = pairs.leftappend(<Integer.MinValue, 0>);
int n = pairs.length;
double[][] L = new double[n][n];
for(int i = 0; i<n; i++){
if(pairs[i].a >= pairs[n-1].a){
L[i][n-1] = Integer.MinValue;
} else {
L[i][n-1] = pairs[n-1].b;
}
}
for(int j = n-2; j>= 0;j--){
for(int i = 0; i<n; i++){
L[i][j] = L[i][j+1];
if(pairs[i].a < pairs[j].a){
if(L[i][j] < L[j][j+1] + pairs[j].b){
L[i][j] = L[j][j+1] + pairs[j].b;
}
}
}
}
return L[0][1];
}
If the subarray is contingous then you can go for Kadan's algorithm suggested by mindless monk. If you need to consider subsequence then dynamic programming approach, as the optimal substructure property is met: you may process the task from left to right, as if A is a solution of size N, and A is optimal it has to be also a part of a solution of B, of size N + 1.
So you should build a helper array M, where
for each i < N
for each j < i
if a[i] > a[j] && b[i] + M[j] > M[i] then
M[i] = b[i] + M[j]
And then for the maximum value of M reconstruct the solution.
O(n) Complexity
public static void max_subsequence(Item[] array){
String paths[] = new String[array.length];
int sum[] = new int[array.length];
int max = Integer.MIN_VALUE;
for(int i = 0; i < array.length; i++){
sum[i] = array[i].b;
paths[i] = "<" + array[i].a + "," + array[i].b +"> ,";
if(sum[i] > max){
max = sum[i];
}
}
for(int i = 1; i < array.length; i++){
if( array[i-1].a <= array[i].a && (sum[i-1]+ sum[i])> sum[i]){
paths[i] = paths[i-1] + paths[i];
sum[i] = sum[i-1] + sum[i];
if(max < sum[i]){
max = sum[i];
}
}
}
for(int i = 0; i < paths.length; i++){
if(max == sum[i]){
System.out.println("["+i+"]"+ " MAX: " + paths[i] + " = " + sum[i]);
}else{
System.out.println("["+i+"]"+paths[i] + " = " + sum[i]);
}
}
}
This clearly cannot work. For one, your maximum subsequence is going to be at most one item long.
I am sorry. I just test it out my code and YES! I HAD a very BAD Bug:
I wrote: sum[i] = array[i-1].b + array[i].b;
when I should use the sum[] values ( which is actually the most importan part of my code:
sum[i] = sum[i-1] + sum[i];
Sorry about that. I've fixed it.
Please send me the bill or the bet I've lost lol
This is a variation of the Kadane's Algorithm
public static void max_subsequence(int sequence[]){
int MAX = Integer.MIN_VALUE;
String paths[] = new String[sequence.length];
int sum[] = new int[sequence.length];
for(int i = 0; i <sequence.length; i++){
paths[i] = sequence[i] + ",";
sum[i] = sequence[i];
if(sum[i]>MAX){
MAX = sum[i];
}
}
for(int i = 1; i < sequence.length; i++){
if((sum[i-1] + sum[i]) > sum[i]){
paths[i] = paths[i-1] + paths[i];
sum[i] = sum[i-1]+sum[i];
if(MAX < sum[i]){
MAX = sum[i];
}
}
}
for(int i = 0; i < sum.length; i++){
if(MAX == sum[i]){
System.out.println("MAX: "+paths[i] + " = " + sum[i]);
}else{
System.out.println(paths[i] + " = " + sum[i]);
}
}
}
INPUT:
max_subsequence(new Item[]{
new Item(1,-2),
new Item(2,1),
new Item(3,-3),
new Item(4,4),
new Item(5,-1),
new Item(6,2),
new Item(7,1),
new Item(8,-5),
new Item(9,4)
});
OUTPUT:
[0]<1,-2> , = -2
[1]<2,1> , = 1
[2]<2,1> ,<3,-3> , = -2
[3]<4,4> , = 4
[4]<4,4> ,<5,-1> , = 3
[5]<4,4> ,<5,-1> ,<6,2> , = 5
[6] MAX: <4,4> ,<5,-1> ,<6,2> ,<7,1> , = 6
[7]<4,4> ,<5,-1> ,<6,2> ,<7,1> ,<8,-5> , = 1
[8]<4,4> ,<5,-1> ,<6,2> ,<7,1> ,<8,-5> ,<9,4> , = 5
INPUT:
max_subsequence(new int[] {-2,1,-3,4,-1,2,1,-5,4});
OUTPUT
[0]-2, = -2
[1]1, = 1
[2]1,-3, = -2
[3]4, = 4
[4]4,-1, = 3
[5]4,-1,2, = 5
[6] MAX: 4,-1,2,1, = 6
[7]4,-1,2,1,-5, = 1
[8]4,-1,2,1,-5,4, = 5
First sort the array based on the first element and save them in an other array call c.
Then we can reduce the problem to find the LCS ( longest Common Subsequence ) problem. Let bi, be the weight whether we choose ai or not, instead of length weight is important here. Using dynamic programming the running time is O(N^2)
Why would you think that the Kadane's Algorithm is the solution? Read the original question again slowly: "the 1st element in the pairs are in increasing order and the sum of 2nd element of the pairs in the sub-array is maximum possible" The 2nd element of the pairs is the "maximum possible"... Given the input pairs:
max_subsequence(new Item[]{
new Item(1,-2),
new Item(2,1),
new Item(3,-3),
new Item(4,4),
new Item(5,-1),
new Item(6,2),
new Item(7,1),
new Item(8,-5),
new Item(9,4)
});
integer 6 is not the max possible as the algorithm is determining, 12 is the max possible integer of the 2nd element. First it's assumed that the pairs are sorted based on their first element. Second, remove all pairs where the 2nd element is negative. You end up with this list of pairs:
Item(2,1),
Item(4,4),
Item(6,2),
Item(7,1),
Item(9,4)
The first elements are in increasing order, and the sum of the second elements are the maximum positive integer. If there happen to be additional criteria that there cannot be gaps in the first elements order then that should be noted in the question, but the question just says "increasing order". Are they not increasing order?
double getMax(vector< pair<double, double> > v) {
assert(v.size() > 0);
int bleft=0, bright=0;
int tmp_left = 0;
double bv=v[0].second;
double cv = bv;
for (int i = 1; i < v.size(); i++) {
if (cv < 0 || v[i].first < v[i-1].first) {
cv = v[i].second;
tmp_left = i;
} else {
cv += v[i].second;
}
if (bv < cv) {
bleft = tmp_left;
bright = i;
bv = cv;
}
}
return bv;
}
Simple in Java
public class GetRequiredRangeInPairArray {
private static class IntPair {
int first_;
int second_;
IntPair (int f, int s){
first_ = f; second_ = s;
}
int first() { return first_; }
int second() { return second_; }
@Override
public String toString() {
return "["+first()+"," +second()+"]";
}
}
static class Range extends IntPair {
Range(int s, int e){ super(s,e); }
int start() { return (int) super.first(); }
int end () { return (int) super.second(); }
}
// the range includes start but not the end
public static Range getRequiredSubArray(IntPair [] arr){
int n = arr.length;
if(n < 1) return new Range(0,1);
if(n == 1) return new Range(0,1);
int maxSum = Integer.MIN_VALUE;
int maxStart = 0;
int maxEnd = 0;
int start = 0;
int sum = 0;
int prevFirst = Integer.MIN_VALUE;
for(int i = 0; i < n ; i++){
IntPair r = arr[i];
if(sum <=0 || prevFirst >= r.first()){
start = i;
sum = 0;
}
sum += r.second();
if(sum > maxSum){
maxSum = sum;
maxStart = start;
maxEnd = i;
}
prevFirst = r.first();
}
return new Range(maxStart, maxEnd+1);
}
public static void main(String[] args) {
IntPair [] arr1 = {
new IntPair(2,Integer.MIN_VALUE),
new IntPair(1,10),
new IntPair(3,-5),
new IntPair(5,-7),
new IntPair(1,10),
new IntPair(3,-5),
new IntPair(5,7),
new IntPair(5,7),
};
System.out.println(getRequiredSubArray(arr1));
}
}
Modified Kadane's algorithm
public class KadaneForPair {
private class Pair {
public int a;
public int b;
public Pair(int a, int b) {
this.a = a;
this.b = b;
}
}
public Pair[] findMaxSubArray(Pair[] input) {
int start = 0;
int maxSum = input[0].b;
int bestSum = input[0].b;
int bestStart = 0;
int bestEnd = 0;
for (int i = 1; i < input.length; i++) {
/*
* we reposition start index only when the continuity of first a
* breaks.
*/
if (input[i].a < input[i - 1].a) {
start = i;
maxSum = input[i].b;
} else {
maxSum += input[i].b;
}
if (maxSum > bestSum) {
bestSum = maxSum;
bestStart = start;
bestEnd = i;
}
}
System.out.println("bestStart: " + bestStart + " bestEnd: " + bestEnd);
Pair[] out = new Pair[bestEnd - bestStart + 1];
System.arraycopy(input, bestStart, out, 0, bestEnd - bestStart + 1);
return out;
}
public static void main(String args[]) {
KadaneForPair test = new KadaneForPair();
Pair[] input = new Pair[5];
input[0] = test.new Pair(10, 2);
input[1] = test.new Pair(2, 10);
input[2] = test.new Pair(3, 2);
input[3] = test.new Pair(5, 87);
input[4] = test.new Pair(-1, 10);
Pair[] out = test.findMaxSubArray(input);
System.out.println("input:");
display(input);
System.out.println("output: ");
display(out);
}
private static void display(Pair[] out) {
for(int i =0;i<out.length;i++){
System.out.print("(" + out[i].a+ ", " + out[i].b + ") ");
}
System.out.println();
}
}
can you please explain?
this is the output i got
bestStart: 0 bestEnd: 0
input:
(-1, -1) (-1, -1) (-1, -1)
output:
(-1, -1)
your input has all negative elements. if you sum up any two of them you get a lower value than either of them. so, your output array must have a single element i.e. the element that has the highest 2nd element in the pair.
Sorry, I was wrong. But how about this input :
(1, 2) (2, -100) (3, 3) (4, 4) (5,5)
Your output will be : 2.
But the best should be : 3 + 4 + 5. right?
Note that 'start' in your code will always be 0.
thanks for pointing it out. my assumption that we don't need a repositioning of start as long as there is ascending order was wrong. if the sum goes negative, we need to reposition the start.
here is the edited code:
public class KadaneForPair {
private class Pair {
public int a;
public int b;
public Pair(int a, int b) {
this.a = a;
this.b = b;
}
}
public Pair[] findMaxSubArray(Pair[] input) {
int start = 0;
int maxSum = input[0].b;
int bestSum = input[0].b;
int bestStart = 0;
int bestEnd = 0;
for (int i = 1; i < input.length; i++) {
/*
* we reposition start index when the sum goes negative or if the
* ascending quality breaks
*/
if (input[i].a < input[i - 1].a || input[i].b + maxSum < 0) {
// change this to <= if you want the longest possible subarray
if (input[i].b + maxSum < 0) {
start = i + 1;
maxSum = 0;
i++;
} else {
start = i;
maxSum = input[i].b;
}
} else {
maxSum += input[i].b;
}
if (maxSum > bestSum) {
bestSum = maxSum;
bestStart = start;
bestEnd = i;
}
}
System.out.println("bestStart: " + bestStart + " bestEnd: " + bestEnd);
Pair[] out = new Pair[bestEnd - bestStart + 1];
System.arraycopy(input, bestStart, out, 0, bestEnd - bestStart + 1);
return out;
}
public static void main(String args[]) {
KadaneForPair test = new KadaneForPair();
Pair[] input = new Pair[5];
input[0] = test.new Pair(1, 2);
input[1] = test.new Pair(2, -100);
input[2] = test.new Pair(3, 3);
input[3] = test.new Pair(4, 4);
input[4] = test.new Pair(5, 5);
Pair[] out = test.findMaxSubArray(input);
System.out.println("input:");
display(input);
System.out.println("output: ");
display(out);
Pair[] input2 = new Pair[3];
input2[0] = test.new Pair(-1, -3);
input2[1] = test.new Pair(-1, -2);
input2[2] = test.new Pair(-1, -1);
out = test.findMaxSubArray(input2);
System.out.println("input:");
display(input2);
System.out.println("output: ");
display(out);
}
private static void display(Pair[] out) {
for (int i = 0; i < out.length; i++) {
System.out.print("(" + out[i].a + ", " + out[i].b + ") ");
}
System.out.println();
}
}
Modified Kadane's algo will be O(N)
- mindless monk November 15, 2013