Woodstock Blog

a tech blog for general algorithmic interview questions

[Question] 0-1 Knapsack Problem

Question

link

Given weights and values of n items, put these items in a knapsack of capacity W to get the maximum total value.

In other words, given two integer arrays val[0..n-1] and wt[0..n-1] which represent values and weights. Also given an integer W which represents knapsack capacity, find out the maximum possible value.

You cannot break an item, either pick it or don’t pick it (0-1 property).

Analysis

This is a very similar question to [Question] Coin Change Problem, because directly using recursion to solve will result in a lot of re-calculations. It’s a DP question.

Solution

First of all, define a 2D array, Knapsack(n,W) denotes getting ‘n'th item, with weight 'W’. When n == 0 or W = 0, dp value is 0.

int[][] Knapsack = new int[n + 1][W + 1];

Using ‘n’ to denote the items to put into Knapsack. ‘v’ is the value and ‘w’ is the total weight.

Now if item ‘n’ is able to fit in:

Knapsack(n,W) = max(vn + Knapsack(n-1, W-wn), Knapsack(n-1, W))

If not able to fit in:

Knapsack(n,W) = Knapsack(n-1, W)

Refer to page 11 to 12 of this pdf.

Follow up

Look at the code, we checked dp[i-1][j]. Now the question is:

Do we need to check dp[i][j-1] ? (In case that total weight is not fully used up)

The answer is NO. We don’t. Look at example: weights = {1, 2} and values = {3, 5}, and knapsack weight = 4. DP array would be:

[
 [0, 0, 0, 0, 0],
 [0, 3, 3, 3, 3],
 [0, 3, 5, 8, 8]
]

See that? The way that we keep DP array size int[items + 1][totalWeight + 1], the DP value is always 0 at 1st column and row.

So, in the example when i == 1, total value is ALWAYS 3.

Code

public int maxValNoDup(int totalWeight, int[] value, int[] weight) {
    int items = value.length;
    Arrays.sort(value);
    Arrays.sort(weight);

    int[][] dp = new int[items + 1][totalWeight + 1];
    for (int i = 1; i <= items; i++) {
        for (int j = 1; j <= totalWeight; j++) {
            // we'll try to take i'th item, to fit in weight j
            if (j < weight[i - 1]) {
                // not able to put in
                dp[i][j] = dp[i - 1][j];
            } else {
                // we are able to take i'th item into knapsack
                dp[i][j] = Math.max(dp[i - 1][j], value[i - 1]
                        + dp[i - 1][j - weight[i - 1]]);
            }
        }
    }
    return dp[items][totalWeight];
}

[Question] Make a Fair Coin From a Biased Coin

Question

link

You are given a function foo() that represents a biased coin. When foo() is called, it returns 0 with 60% probability, and 1 with 40% probability. Write a new function that returns 0 and 1 with 50% probability each. Your function should use only foo(), no other library method.

Analysis

(0, 1): The probability to get 0 followed by 1 from two calls of foo() = 0.6 * 0.4 = 0.24

(1, 0): The probability to get 1 followed by 0 from two calls of foo() = 0.4 * 0.6 = 0.24

Solution

Toss twice. If get (0, 0) or (1, 1), discard. Otherwise, return 0 or 1 for the 2 different cases.

Code

int my_fun() {
    int val1 = foo();
    int val2 = foo();
    if (val1 == 0 && val2 == 1)
        return 0;   // Will reach here with 0.24 probability
    if (val1 == 1 && val2 == 0)
        return 1;   // Will reach here with 0.24 probability
    return my_fun();
}

[Question] Coin Change Problem

Question

link

Given a value N, if we want to make change for N cents, and we have infinite supply of each of S = { S1, S2, .. , Sm} valued coins, how many ways can we make the change? The order of coins doesn’t matter.

For example, for N = 4 and S = {1,2,3}, there are four solutions: {1,1,1,1},{1,1,2},{2,2},{1,3}. So output should be 4. For N = 10 and S = {2, 5, 3, 6}, there are five solutions: {2,2,2,2,2}, {2,2,3,3}, {2,2,6}, {2,3,5} and {5,5}. So the output should be 5.

Analysis

I did this question before, it’s not a DFS search question, because question only asks the total number of ways.

So what method do we use? Remember the 4 types of DP?

  1. Input cannot sort

  2. Find minimum/maximum result

  3. Check the feasibility

  4. Count all possible solutions

So, this is a DP question!

Solution

The solutions in in two parts:

  1. Solutions that do not contain mth coin (or Sm).
  2. Solutions that contain at least one Sm.

Using m to denote the types of coin used, and n denote the total value, the equation is:

count( S, m, n ) = count( S, m - 1, n ) + count( S, m, n-S[m-1] )

Solution one is using recursion. It’s not good because of a lot of repeated calculation. But the code is extremely easy to write:

int count( int S[], int m, int n ) {
    // If n is 0 then there is 1 solution (do not include any coin)
    if (n == 0)
        return 1;
    // If n is less than 0 then no solution exists
    if (n < 0)
        return 0;
    // If there are no coins and n is greater than 0, then no solution exist
    if (m <=0 && n >= 1)
        return 0;
    // count is sum of solutions (i) including S[m-1] (ii) excluding S[m-1]
    return count( S, m - 1, n ) + count( S, m, n-S[m-1] );
}

Solution two is DP, it’s a little hard to write actually. Do it carefully.

Code

C++ code not written by me:

int count( int S[], int m, int n ) {
    int i, j, x, y;

    // We need n+1 rows as the table is consturcted in bottom up manner using 
    // the base case 0 value case (n = 0)
    int table[n+1][m];

    // Fill the enteries for 0 value case (n = 0)
    for (i=0; i<m; i++)
        table[0][i] = 1;

    // Fill rest of the table enteries in bottom up manner  
    for (i = 1; i < n+1; i++)
    {
        for (j = 0; j < m; j++)
        {
            // Count of solutions including S[j]
            x = (i-S[j] >= 0)? table[i - S[j]][j]: 0;

            // Count of solutions excluding S[j]
            y = (j >= 1)? table[i][j-1]: 0;

            // total count
            table[i][j] = x + y;
        }
    }
    return table[n][m-1];
}

[Question] Single Number IV

Question

link

You are given an array of n+2 elements. All elements of the array are in range 1 to n. And all elements occur once except two numbers which occur twice. Find the two repeating numbers.

Solution

Solution 1: User count array. O(n) time and O(n) space. Not efficient enough.

Solution 2: Calculate sum of x,y and product of x,y. O(n) time and O(1) space, but there’s risk of overflow.

Solution 3: XOR. Add number 1 to N to the array, and this becomes Single Number III. O(n) time and O(1) space.

There is also a solution 4: Use array elements as index. This is the same method as used in [LeetCode 41] First Missing Positive.

Code

C++ Code from GFG

void printRepeating(int arr[], int size)
{
  int xor = arr[0]; /* Will hold xor of all elements */
  int set_bit_no;  /* Will have only single set bit of xor */
  int i;
  int n = size - 2;
  int x = 0, y = 0;

  /* Get the xor of all elements in arr[] and {1, 2 .. n} */
  for(i = 1; i < size; i++)
    xor ^= arr[i];
  for(i = 1; i <= n; i++)
    xor ^= i;

  /* Get the rightmost set bit in set_bit_no */
  set_bit_no = xor & ~(xor-1);

  /* Now divide elements in two sets by comparing rightmost set
   bit of xor with bit at same position in each element. */
  for(i = 0; i < size; i++)
  {
    if(arr[i] & set_bit_no)
      x = x ^ arr[i]; /*XOR of first set in arr[] */
    else
      y = y ^ arr[i]; /*XOR of second set in arr[] */
  }
  for(i = 1; i <= n; i++)
  {
    if(i & set_bit_no)
      x = x ^ i; /*XOR of first set in arr[] and {1, 2, ...n }*/
    else
      y = y ^ i; /*XOR of second set in arr[] and {1, 2, ...n } */
  }

  printf("\n The two repeating elements are %d & %d ", x, y);
}     


int main()
{
  int arr[] = {4, 2, 4, 5, 2, 3, 1};
  int arr_size = sizeof(arr)/sizeof(arr[0]);  
  printRepeating(arr, arr_size);
  getchar();
  return 0;
}

[Question] Single Number III

Question

link

In an array, all numbers in the array repeat twice except two numbers, which repeat only once.

Assume all the numbers are placed randomly. Find the 2 numbers.

Analysis

The main idea of the solution is how to remove repeated elements. It’s definitely using XOR.

We need to try solve this problem like we did in ‘Single number 1’ but how? We can divide the array into 2 part, each part containing 1 non-repeating number.

The difficulty and the trick, is how do we divide?

Solution

  1. xor = arr[0]^arr[1]^arr[2]…..arr[n-1]

  2. We can extract the rightmost set bit of any number n by taking ( n & ~(n-1))

  3. We take any set bit of xor and divide the elements of the array in two sets – one set of elements with same bit set and other set with same bit not set.

    By doing so, we will get x in one set and y in another set.

Code

C++ Code from GFG

/* This finction sets the values of *x and *y to nonr-epeating
 elements in an array arr[] of size n*/
void get2NonRepeatingNos(int arr[], int n, int *x, int *y)
{
  int xor = arr[0]; /* Will hold xor of all elements */
  int set_bit_no;  /* Will have only single set bit of xor */
  int i;
  *x = 0;
  *y = 0;

  /* Get the xor of all elements */
  for(i = 1; i < n; i++)
   xor ^= arr[i];

  /* Get the rightmost set bit in set_bit_no */
  set_bit_no = xor & ~(xor-1);

  /* Now divide elements in two sets by comparing rightmost set
   bit of xor with bit at same position in each element. */
  for(i = 0; i < n; i++)
  {
    if(arr[i] & set_bit_no)
     *x = *x ^ arr[i]; /*XOR of first set */
    else
     *y = *y ^ arr[i]; /*XOR of second set*/
  }
}

/* Driver program to test above function */
int main()
{
  int arr[] = {2, 3, 7, 9, 11, 2, 3, 11};
  int *x = (int *)malloc(sizeof(int));
  int *y = (int *)malloc(sizeof(int));
  get2NonRepeatingNos(arr, 8, x, y);
  printf("The non-repeating elements are %d and %d", *x, *y);
  getchar();
}

[LintCode] Partition Array

Question

link

Given an array “nums” of integers and an int “k”, Partition the array (i.e move the elements in “nums”) such that,

  1. All elements < k are moved to the left
  2. All elements >= k are moved to the right

Return the partitioning Index, i.e the first index “i” nums[i] >= k.

Example: If nums=[3,2,2,1] and k=2, a valid answer is 1.

Analysis

The solution is to keep swapping elements. It confuses me for a while, until I realize the swapping mechanism is actually not difficult.

There’s another question on leetcode “Sort Color”, which is similar to this question (just partition twice).

Code

public int partitionArray(ArrayList<Integer> nums, int k) {
    //write your code here
    ArrayList<Integer> ans = new ArrayList<Integer>();
    if (nums == null || nums.size() == 0) {
        return ans;
    }
    int len = nums.size();
    int left = 0;
    int right = len - 1;
    while (left < right) {
        while (left < len && nums.get(left) < k) {
            left++;
        }
        while (right >= 0 && nums.get(right) >= k) {
            right--;
        }
        if (left > right) {
            break;
        } else {
            // swap 2 elements
            int temp = nums.get(left);
            nums.set(left, nums.get(right));
            nums.set(right, temp);
            left++;
            right--;
        }
    }
    // now return the correct value
    if (left == len) {
        return len;
    } else {
        return left;
    }
}

[NineChap 8] High Frequency Questions

Number & Bit questions

  1. Single Number
  2. Single Number II
  3. Single Number III
  4. Single Number IV
  5. Majority Number
  6. Majority Number II
  7. Majority Number III

Subarray questions

Always using the idea of 前缀和.

  1. Best Time to Buy and Sell Stock - 贪心法
  2. Best Time to Buy and Sell Stock II
  3. Best Time to Buy and Sell Stock III
  4. Maximum Subarray
  5. Minimum Subarray
  6. Maximum Subarray II
  7. Subarray with 0 Sum
  8. Subarray with Particular Sum
  9. Subarray with Sum Closest

N Sum questions

  1. Two Sum - difficult
  2. 3 Sum
  3. 3 Sum Closest
  4. 4 Sum - doing a O(n3) solution is good enough.
  5. k sum questions are basically solved with O(nk-1) time. Faster solution is available but too complex.

L 家最爱

  1. Pow(x,n)
  2. Sqrt(x)
  3. Trailing Zeros of Factorial
  4. Check Power of 2

Additional questions

  1. Partition Array
  2. Sort Color

Code

Number questions

Single Number

public int singleNumber(int[] A) {
    int x = 0;
    for (Integer a: A) {
        x = x ^ a;
    }
    return x;
}

Single Number II

Last time, I used an array of size 32 to store count, but it’s actually not necessary.

public int singleNumber(int[] A) {
    int ans = 0;
    for (int i = 0; i < 32; i++) {
        int count = 0;
        for (Integer a: A) {
            count += ((a >> i) & 1);
        }
        ans |= (count % 3) << i;
    }
    return ans;
}

Subarray questions

Best Time to Buy and Sell Stock

public int maxProfit(int[] prices) {
    if (prices == null || prices.length == 0) {
        return 0;
    }
    int min = prices[0];
    int profit = 0;
    for (Integer p: prices) {
        min = Math.min(min, p);
        profit = Math.max(profit, p - min);
    }
    return profit;
}

Best Time to Buy and Sell Stock II

public int maxProfit(int[] prices) {
    if (prices == null || prices.length == 0) {
        return 0;
    }
    int pre = prices[0];
    int profit = 0;
    for (Integer p: prices) {
        if (p > pre) {
            profit += p - pre;
        }
        pre = p;
    }
    return profit;
}

Best Time to Buy and Sell Stock III

It’s important to note the 2nd last line of the code, where we consider the corner case of doing only 1 transaction.

It’s always best to list a simple test case and walk it thru before submitting the code.

public int maxProfit(int[] prices) {
    if (prices == null || prices.length == 0) {
        return 0;
    }
    int len = prices.length;
    int[] dpLeft = new int[len];
    int leftMin = prices[0];
    for (int i = 1; i < len; i++) {
        dpLeft[i] = Math.max(dpLeft[i - 1], prices[i] - leftMin);
        leftMin = Math.min(leftMin, prices[i]);
    }
    int[] dpRight = new int[len];
    int rightMax = prices[len - 1];
    for (int i = len - 2; i >= 0; i--) {
        dpRight[i] = Math.max(dpRight[i + 1], rightMax - prices[i]);
        rightMax = Math.max(rightMax, prices[i]);
    }
    // now iterate the 2 DP array and find out the largest possible profit
    int profit = 0;
    for (int i = 0; i < len - 1; i++) {
        profit = Math.max(profit, dpLeft[i] + dpRight[i + 1]);
    }
    int oneTransaction = Math.max(dpLeft[len - 1], dpRight[0]);
    return Math.max(profit, oneTransaction);
}

Maximum Subarray

public int maxSubArray(int[] A) {
    if (A == null || A.length == 0) {
        return 0;
    }
    int max = Integer.MIN_VALUE;
    int pre = 0;
    // the largest sum ending at previous position in the array
    for (Integer a: A) {
        max = Math.max(max, pre + a);
        pre = Math.max(0, pre + a);
    }
    return max;
}

3Sum questions

Two Sum

This solution is O(nlgn) time.

Alternatively, we can use HashMap to solve this problem with O(n) time.

public int[] twoSum(int[] numbers, int target) {
    // write your code here
    int[] ans = new int[2];
    if (numbers == null || numbers.length == 0) {
        return ans;
    }
    int len = numbers.length;
    Pair[] pairs = new Pair[len];
    for (int i = 0; i < len; i++) {
        pairs[i] = new Pair(numbers[i], i + 1);
    }
    Arrays.sort(pairs);
    int left = 0;
    int right = len - 1;
    while (left < right) {
        if (pairs[left].num + pairs[right].num == target) {
            ans[0] = pairs[left].index;
            ans[1] = pairs[right].index;
            Arrays.sort(ans);
            break;
        } else if (pairs[left].num + pairs[right].num > target) {
            right--;
        } else {
            left++;
        }
    }
    return ans;
}

class Pair implements Comparable<Pair> {
    int num;
    int index;

    public Pair(int a, int b) {
        num = a;
        index = b;
    }

    public int compareTo(Pair another) {
        return this.num - another.num;
    }
}

3 Sum

public ArrayList<ArrayList<Integer>> threeSum(int[] numbers) {
    ArrayList<ArrayList<Integer>> ans = new ArrayList<ArrayList<Integer>>();
    if (numbers == null || numbers.length == 0) {
        return ans;
    }
    Arrays.sort(numbers);
    int len = numbers.length;
    for (int i = 0; i < len; i++) {
        if (i > 0 && numbers[i - 1] == numbers[i]) {
            continue;
        }
        int left = i + 1;
        int right = len - 1;
        // find 2 numbers that sums to - number[i]
        while (left < right) {
            int diff = numbers[left] + numbers[right] + numbers[i];
            if (diff == 0) {
                ArrayList<Integer> triplet = new ArrayList<Integer>();
                triplet.add(numbers[i]);
                triplet.add(numbers[left]);
                triplet.add(numbers[right]);
                ans.add(triplet);
            }
            if (diff <= 0) {
                left++;
                while (left < len && numbers[left - 1] == numbers[left]) {
                    left++;
                }
            }
            if (diff >= 0) {
                right--;
                while (right >= 0 && numbers[right + 1] == numbers[right]) {
                    right--;
                }
            }
        }
    }
    return ans;
}

3 Sum Closest

public int threeSumClosest(int[] numbers, int target) {
    if (numbers == null || numbers.length == 0) {
        return 0;
    }
    Arrays.sort(numbers);
    int sum = 0;
    int diff = Integer.MAX_VALUE;
    int len = numbers.length;
    for (int i = 0; i < len; i++) {
        int left = i + 1;
        int right = len - 1;
        while (left < right) {
            int triple = numbers[left] + numbers[right] + numbers[i];
            if (triple == target) {
                return target;
            } else if (triple < target) {
                left++;
            } else {
                right--;
            }
            if (Math.abs(target - triple) < diff) {
                diff = Math.abs(target - triple);
                sum = triple;
            }
        }
    }
    return sum;
}

4 Sum

public ArrayList<ArrayList<Integer>> fourSum(int[] numbers, int target) {
    ArrayList<ArrayList<Integer>> ans = new ArrayList<ArrayList<Integer>>();
    if (numbers == null || numbers.length == 0) {
        return ans;
    }
    Arrays.sort(numbers);
    int len = numbers.length;
    for (int i = 0; i < len - 3; i++) {
        if (i > 0 && numbers[i - 1] == numbers[i]) {
            continue;
        }
        for (int j = i + 1; j < len - 2; j++) {
            if (j > i + 1 && numbers[j - 1] == numbers[j]) {
                continue;
            }
            int left = j + 1;
            int right = len - 1;
            while (left < right) {
                int diff = numbers[left] + numbers[right] + numbers[i] + numbers[j] - target;
                if (diff == 0) {
                    ArrayList<Integer> triplet = new ArrayList<Integer>();
                    triplet.add(numbers[i]);
                    triplet.add(numbers[j]);
                    triplet.add(numbers[left]);
                    triplet.add(numbers[right]);
                    ans.add(triplet);
                }
                if (diff <= 0) {
                    left++;
                    while (left < len && numbers[left - 1] == numbers[left]) {
                        left++;
                    }
                }
                if (diff >= 0) {
                    right--;
                    while (right >= 0 && numbers[right + 1] == numbers[right]) {
                        right--;
                    }
                }
            }
        }
    }
    return ans;
}

L 家最爱

Pow(x,n)

It’s important to note that in Line 16, wrting ‘while (pow * 2 <= y)’ would not work (because of overflow). It took me a long time to find this bug.

public double pow(double x, int n) {
    if (n < 0) {
        return 1.0 / helper (x, 0 - n);
    } else {
        return helper(x, n);
    }
}

private double helper(double x, int y) {
    if (y == 0) {
        return 1.0;
    }
    int pow = 1;
    double num = x;
    while (pow <= y / 2) {
        num *= num;
        pow <<= 1;
    }
    return num * helper(x, y - pow);
}

Sqrt(x)

Note that in Line 8, we must declare left and right as ‘long’, not ‘int’, otherwise there will be overflow problems. It took me a long time to find this bug.

public int sqrt(int x) {
    if (x < 0) {
        return -1;
    } else if (x < 2) {
        return x;
    }
    long left = 1;
    long right = x;
    while (left + 1 < right) {
        long mid = left + (right - left) / 2;
        if (mid * mid < x) {
            left = mid;
        } else if (mid * mid > x) {
            right = mid;
        } else {
            return (int) mid;
        }
    }
    return (int) left;
}

Additional

Sort Color

public void sortColors(int[] A) {
    if (A == null || A.length == 0) {
        return;
    }
    int len = A.length;
    partition(A, 0, len - 1, 0);
    int p = 0;
    while (p < len && A[p] == 0) {
        p++;
    }
    partition(A, p, len - 1, 1);
}

private void partition(int[] A, int start, int end, int target) {
    // find the target and put it on the left side of the array
    while (start < end) {
        while (start < A.length && A[start] == target) {
            start++;
        }
        while (end >= 0 && A[end] != target) {
            end--;
        }
        if (start > end) {
            break;
        } else {
            int temp = A[start];
            A[start] = A[end];
            A[end] = temp;
        }
    }
}

[NineChap 7] Data Structure

Data Structure

Data structure is a way to manage data. It provides some methods to handle data stream. For example, DB is a DS.

Stack and Queue

  1. Min-stack

  2. Implement a queue by two stacks

  3. Largest Rectangle in histogram

Hash

Hash function

  1. MD5
  2. Magic number 33 (PHP hash function DJBX33A)

Magic Number:

int hashfunc(String key) {
    int sum = 0;
    for (int i = 0; i < key.length(); i++) {
        sum = sum * 33 + (int)(key.charAt(i));
        sum = sum % HASH_TABLE_SIZE;
    }
    return sum
}

Collision

  1. Close hashing (also called Open addressing)

    Resolves conflict by probing, or searching through alternate locations in the array

    Suck scheme may cause the lookup cost to skyrocket. Not good to use.

  2. Open hashing

    Keys stored in linked lists attached to cells of the hash table.

    Practically, hash size set around 10 times the size of data

    Used by Java and most other languages.

Rehashing

  1. Memcached is a general-purpose distributed memory caching system. One of its bottleneck is rehashing, which locks down the entire hash.

  2. Dynamic resizing (normally size * 2) and copy all elements into the new hash.

  3. Extremely slow process, we should try to avoid it by setting a large enough initial size.

Hash questions:

  1. Implement a hashmap

  2. HashMap vs Hashtable vs HashSet

  3. LRU Cache

  4. Longest consecutive sequence

Heap

  1. Child is always larger than parent
  2. Heap is not a sorted structure, but it’s partially ordered
  3. Heap is always balanced

Heap is better than array because average of 3 operations is O(logn), but array is O(n).

Add O(log N)

Remove O(log N)

Min/Max O(1)

Heap implementation:

  1. Low Level: dynamic array, not list

  2. Internal Method: Shiftup, Shiftdown operations

  3. A heap is a complete binary tree (最优二叉树) represented by an array

  4. When removing element from heap, we actually uses HashMap to find that element.

Heaps are usually implemented in an array, and do not require pointers between elements.

Full and almost full binary heaps may be represented in a very space-efficient way using an array alone. The first element will contain the root. The next two elements of the array contain its children. The next four contain the four children of the two child nodes, etc.

Thus the children of the node at position n would be at positions 2n+1 and 2n+2.

So to summarize:

  1. elems[1] - root, also the minimum elem in elems.
  2. elems[i]: left child is elems[i2], right child is elems[i2+1]

Implementation code:

Add:
    Push back to elems; size ++; Siftup;
Remove:
    Replace the elem to be removed with the last elem; 
    size --; 
    Siftup and Siftdown.

Heap questions:

  1. Median in a stream of integers

  2. The Skyline Problem

Interval Tree

Easily find the max/min value in an interval. 2 example questions are:

  1. Find min/max/sum in an interval
  2. 最长的连续1

Code

Largest Rectangle in histogram

public int largestRectangleArea(int[] height) {
    if (height == null || height.length == 0) {
        return 0;
    }
    Stack<Integer> stack = new Stack<Integer>();
    stack.add(0);
    int len = height.length;
    int area = 0;
    for (int i = 1; i <= len; i++) {
        int h = i == len ? 0 : height[i];
        // pop a element and calculate its max area
        // pop until the top element is smaller than h, then push h
        while (!stack.isEmpty() && h < height[stack.peek()]) {
            int pos = stack.pop();
            int width = stack.isEmpty() ? i : i - stack.peek() - 1;
            area = Math.max(area, height[pos] * width);
        }
        stack.push(i);
    }
    return area;
}

LRU Cache

I posted code in the new post.

Longest consecutive sequence

public int longestConsecutive(int[] num) {
    if (num == null || num.length == 0) {
        return 0;
    }
    HashSet<Integer> set = new HashSet<Integer>();
    for (Integer i: num) {
        set.add(i);
    }
    int longest = 0;
    for (Integer i: num) {
        if (!set.contains(i)) {
            continue;
        }
        int left = i - 1;
        while (set.contains(left)) {
            set.remove(left--);
        }
        int right = i + 1;
        while (set.contains(right)) {
            set.remove(right++);
        }
        longest = Math.max(longest, right - left - 1);
        set.remove(i);
    }
    return longest;
}

[LintCode] Minimum Subarray

Question

link

Given an array of integers, find the subarray with smallest sum. Return the sum of the subarray.

Note The subarray should contain at least one integer.

Example For [1, -1, -2, 1], return -3

Analysis

Same as “Max subarray”.

Code

public int minSubArray(ArrayList<Integer> nums) {
    // write your code
    if (nums == null || nums.size() == 0) {
        return 0;
    }
    int min = nums.get(0);
    int pre = Math.min(0, nums.get(0));
    for (int i = 1; i < nums.size(); i++) {
        pre += nums.get(i);
        min = Math.min(min, pre);
        pre = Math.min(0, pre);
    }
    return min;
}

[LintCode] Maximum Subarray II

Question

link

Given an array of integers, find two non-overlapping subarrays which have the largest sum. The number in each subarray should be contiguous. Return the largest sum.

Note The subarray should contain at least one number

Example For given [1, 3, -1, 2, -1, 2], the two subarrays are [1, 3] and [2, -1, -2] or [1, 3, -1, 2] and [2], they both have the largest sum 7.

Analysis

This is not an easy question. I thought I have to use DP 2 times:

  1. first time, calculate max sum ending at each point.
  2. second time, calculate max sum to the left/right of a point (inclusive but not necessarily ending at current point).

After a second thought, the first DP path can be denoted with a single variable. So there comes the solution below.

Code

public int maxTwoSubArrays(ArrayList<Integer> nums) {
    // write your code
    int len = nums.size();
    int[] dp1 = new int[len];
    int[] dp2 = new int[len];
    // dp1[k] denotes the max sum to the left of k (inclusive)
    // dp2[k] denotes the max sum to the right of k (inclusive)
    dp1[0] = nums.get(0);
    int sumSoFar = Math.max(0, nums.get(0));
    for (int i = 1; i < len; i++) {
        sumSoFar += nums.get(i);
        dp1[i] = Math.max(dp1[i - 1], sumSoFar);
        sumSoFar = Math.max(0, sumSoFar);
    }
    dp2[len - 1] = nums.get(len - 1);
    sumSoFar = Math.max(0, nums.get(len - 1));
    for (int i = len - 2; i >= 0; i--) {
        sumSoFar += nums.get(i);
        dp2[i] = Math.max(dp2[i + 1], sumSoFar);
        sumSoFar = Math.max(0, sumSoFar);
    }
    // now for every node, calculate leftMaxSum + rightMaxSum
    int maxSum = Integer.MIN_VALUE;
    for (int i = 0; i < len - 1; i++) {
        maxSum = Math.max(maxSum, dp1[i] + dp2[i + 1]);
    }
    return maxSum;
}