1. 程式人生 > >九章演算法高階班筆記7.Follow Up Question

九章演算法高階班筆記7.Follow Up Question

Overview: cs3k.com 

  1. Subarray sum 3 follow up
  2. Continuous Subarray Sum 2 follow up
  3. Wiggle Sort 2 follow up
  4. Partition 3 follow up
  5. Iterator 3 follow up

Subarray Sum

cs3k.com 

Given an integer array, find a subarray where the sum of numbers is zero. Your code should return the index of the first number and the index of the last number.

Notice

There is at least one subarray that it’s sum equals to zero.

Have you met this question in a real interview? Yes
Example
Given [-3, 1, 2, -3, 4], return [0, 2] or [1, 3].

public class Solution {
    /** * @param nums: A list of integers * @return: A list of integers includes the index of the first number * and the index of the last number */ public ArrayList<Integer> subarraySum(int[] nums) { // write your code here int len = nums.length; ArrayList<Integer> ans = new ArrayList<Integer>(); HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); map.put(0, -1); int sum = 0; for (int i = 0; i < len; i++) { sum += nums[i]; if (map.containsKey(sum)) { ans.add(map.get(sum) + 1); ans.add(i); return ans; } map.put(sum, i); } return ans; } } 

Submatrix Sum

cs3k.com 

Given an integer matrix, find a submatrix where the sum of numbers is zero. Your code should return the coordinate of the left-up and right-down number.

Example
Given matrix

  [1 , 5 , 7]
  [3 , 7 ,-8]
  [4 ,-8 , 9]

return [(1,1), (2,2)]

可以for迴圈暴力做

for lx = 0 ~ n
    for ly = 0 ~ n
        for rx = lx ~ n
            for ry = ly ~ n

時間複雜度是O(n^4)

接著我們可以想列舉行, 對於

  [1 , 5 , 7]
  [3 , 7 ,-8]
  [4 ,-8 , 9]

的第0行和第1行來說,我們算出每列的sum:

   [1 , 5 ,  7]
      [3 , 7 , -8]
  sum [4 , 12, -1]

然後我們就把每個列變成了一個列的和的值;
所以尋找二維的子矩陣就變成了尋找一維的子陣列問題。

public class Solution {
    /** * @param matrix an integer matrix * @return the coordinate of the left-up and right-down number */ public int[][] submatrixSum(int[][] matrix) { int[][] result = new int[2][2]; int M = matrix.length; if (M == 0) return result; int N = matrix[0].length; if (N == 0) return result; // pre-compute: sum[i][j] = sum of submatrix [(0, 0), (i, j)] int[][] sum = new int[M+1][N+1]; for (int j=0; j<=N; ++j) sum[0][j] = 0; for (int i=1; i<=M; ++i) sum[i][0] = 0; for (int i=0; i<M; ++i) { for (int j=0; j<N; ++j) sum[i+1][j+1] = matrix[i][j] + sum[i+1][j] + sum[i][j+1] - sum[i][j]; } for (int l=0; l<M; ++l) { for (int h=l+1; h<=M; ++h) { Map<Integer, Integer> map = new HashMap<Integer, Integer>(); for (int j=0; j<=N; ++j) { int diff = sum[h][j] - sum[l][j]; if (map.containsKey(diff)) { int k = map.get(diff); result[0][0] = l; result[0][1] = k; result[1][0] = h-1; result[1][1] = j-1; return result; } else { map.put(diff, j); } } } } return result; } } 

Subarray Sum II

cs3k.com 

Given an integer array, find a subarray where the sum of numbers is in a given interval. Your code should return the number of possible answers. (The element in the array should be positive)
Example
Given [1,2,3,4] and interval = [1,3], return 4. The possible answers are:

[0, 0]
[0, 1]
[1, 1]
[2, 2]

對於陣列,我們需要計算一個presum陣列:

       [1,  2,  3,  4]
pre   [0,  1,  3,  6, 10]

如果一個子陣列在1和3之間,就相當於我們有了等式:

1 <= pre[j+1] - pre[i] <= 3

然後我們可以進行兩步:

1. for j = 0 ~ n
2. 找對應範圍內[pre[j+1]-3, pre[j+1]-1]曾經遍歷的個數

我們可以二分法優化, 找>=pre[j+1]-3的最小元素和小於等於pre[j+1]-1的最小元素,時間變成(n*logn)。

public class Solution {
    /** * @param A an integer array * @param start an integer * @param end an integer * @return the number of possible answer */ int find(int[] A, int len, int value) { if (A[len-1] < value ) return len; int l = 0, r = len-1, ans = 0; while (l <= r) { int mid = (l + r) / 2; if (value <= A[mid]) { ans = mid; r = mid - 1; } else l = mid + 1; } return ans; } public int subarraySumII(int[] A, int start, int end) { // Write your code here int len = A.length; for (int i = 1; i <len; ++i) A[i] += A[i-1]; int cnt = 0; for (int i = 0; i <len; ++i) { if (A[i] >= start && A[i] <= end) cnt ++; int l = A[i] - end; int r = A[i] - start; cnt += find(A, len, r+1) - find(A, len, l); } return cnt; } } 

Continuous Subarray Sum

cs3k.com 

Given an integer array, find a continuous subarray where the sum of numbers is the biggest. Your code should return the index of the first number and the index of the last number. (If their are duplicate answer, return anyone)

Example
Give [-3, 1, 3, -3, 4], return [1,4].

public class Solution {
    /** * @param A an integer array * @return A list of integers includes the index of the first number and the index of the last number */ public ArrayList<Integer> continuousSubarraySum(int[] A) { // Write your code here ArrayList<Integer> result = new ArrayList<Integer>(); result.add(0); result.add(0); int len = A.length; int start = 0, end = 0; int sum = 0; int ans = -0x7fffffff; for (int i = 0; i < len; ++i) { if (sum < 0) { sum = A[i]; start = end = i; } else { sum += A[i]; end = i; } if (sum >= ans) { ans = sum; result.set(0, start); result.set(1, end); } } return result; } } 

Maximum Subarray

cs3k.com 

Given an array of integers, find a contiguous subarray which has the largest sum.

Notice

The subarray should contain at least one number.

Example
Given the array [−2,2,−3,4,−1,2,1,−5,3], the contiguous subarray [4,−1,2,1] has the largest sum = 6.

就是f[i]以i作為結尾的子陣列的和最大是多少, 對於每個i都有兩種情況,取和不取。

public class Solution {
    public int maxSubArray(int[] A) { if (A == null || A.length == 0){ return 0; } int max = Integer.MIN_VALUE, sum = 0; for (int i = 0; i < A.length; i++) { sum += A[i]; max = Math.max(max, sum); sum = Math.max(sum, 0); } return max; } } // Version 2: Prefix Sum public class Solution { public int maxSubArray(int[] A) { if (A == null || A.length == 0){ return 0; } int max = Integer.MIN_VALUE, sum = 0, minSum = 0; for (int i = 0; i < A.length; i++) { sum += A[i]; max = Math.max(max, sum - minSum); minSum = Math.min(minSum, sum); } return max; } } public class Solution { /** * @param nums: a list of integers * @return: A integer indicate the sum of minimum subarray */ public int maxSubArray(int[] nums) { // write your code if(nums.length == 0){ return 0; } int n = nums.length; int[] global = new int[2]; int[] local = new int[2]; global[0] = nums[0]; local[0] = nums[0]; for(int i = 1; i < n; i ++) { local[i % 2] = Math.max(nums[i], local[(i - 1) % 2] + nums[i]); global[i % 2] = Math.max(local[i % 2], global[(i - 1) % 2]); } return global[(n-1) % 2]; } } 

Continuous Subarray Sum II

cs3k.com 

Given an circular integer array (the next element of the last element is the first element), find a continuous subarray in it, where the sum of numbers is the biggest. Your code should return the index of the first number and the index of the last number.

If duplicate answers exist, return any of them.

Example
Give [3, 1, -100, -3, 4], return [4,1].

迴圈子陣列的處理方式為三種:

  1. 分裂
  2. 倍增
  3. 取反

這道題分裂貌似不太好分,倍增可以做, 假如栗子是:

[-3,  1,  3,  -3,  4]

我們把這個陣列後面再接一個自己:

[-3,  1,  3,  -3,  4, -3,  1,  3,  -3,  4]

然後約束長度為n, 找答案,可以做,但是時間複雜度比較高, 是O(n^2).

還有一個做法就是取反,我們不是求最大的連續子陣列麼?
有兩種情況:

 |————————---|  max  |———————————|
             start     end

 |     max   |-------|    max    |
              end     start

第一種情況很容易, 第二種情況呢, 因為整個陣列的和是固定的,我們要求兩邊陣列的最大值, 就求中間區間的最小值就好了。

public class Solution {
    /** * @param A an integer array * @return A list of integers includes the index of the first number and the index of the last number */ public List<Integer> continuousSubarraySumII(int[] A) { // Write your code here List<Integer> result = new ArrayList<Integer>(); result.add(0); result.add(0); int total = 0; int len = A.length; int start = 0, end = 0; int local = 0; int global = -0x7fffffff; for (int i = 0; i < len; ++i) { total += A[i]; if (local < 0) { local = A[i]; start = end = i; } else { local += A[i]; end = i; } if (local >= global) { global = local; result.set(0, start); result.set(1, end); } } local = 0; start = 0; end = -1; for (int i = 0; i < len; ++i) { if (local > 0) { local = A[i]; start = end = i; } else { local += A[i]; end = i; } if (start == 0 && end == len-1) continue; if (total - local >= global) { global = total - local; result.set(0, (end + 1) % len); result.set(1, (start - 1 + len) % len); } } return result; } } 

Kth Largest Element

cs3k.com 

Find K-th largest element in an array.

Notice

You can swap elements in the array

Example
In array [9,3,2,4,8], the 3rd largest element is 4.

In array [1,2,3,4,5], the 1st largest element is 5, 2nd largest element is 4, 3rd largest element is 3 and etc.

  1. PriorityQueue
  • 時間複雜度O(nlogk)
  • 更適合Topk
  1. QuickSelect
  • 時間複雜度O(n)
  • 更適合第k大

partition問題模板
enter image description here

quick sort模板

import java.util.Random;

public class Solution { /* * @param A: an integer array * @return: */ public Random rand; public void sortIntegers2(int[] A) { rand = new Random(); // write your code here quickSort(A, 0, A.length - 1); } public void quickSort(int[] A, int start, int end) { if (start >= end) { return; } int index = rand.nextInt(end - start + 1) + start; int pivot = A[index]; int left = start; int right = end; while (left <= right) { while (left <= right && A[left] < pivot) { left ++; } while (left <= right && A[right] > pivot) { right --; } if (left <= right) { int temp = A[left]; A[left] = A[right]; A[right] = temp; left ++; right --; } } // A[start... right] quickSort(A, start, right); // A[left ... end] quickSort(A, left, end); } }

merge sort:

public class Solution {
    /** * @param A an integer array * @return void */ public void sortIntegers2(int[] A) { // use a shared temp array, the extra memory is O(n) at least int[] temp = new int[A.length]; mergeSort(A, 0, A.length - 1, temp); } private void mergeSort(int[] A, int start, int end, int[] temp) { if (start >= end) { return; } int left = start, right = end; int mid = (start + end) / 2; mergeSort(A, start, mid, temp); mergeSort(A, mid+1