Thursday, June 6, 2019

leetcode weekly 132 to 136 - dp problems

weekly 132
(dp) 1027. Longest Arithmetic Sequence
Given an array A of integers, return the length of the longest arithmetic subsequence in A.

e.g. [20,1,15,3,10,5,8] = 4, [20,15,10,5] is the longest arithmetic subsequence.

ref: lee215' [Java/C++/Python] DP
https://leetcode.com/problems/longest-arithmetic-sequence/discuss/274611/JavaC%2B%2BPython-DP
// (CY 2nd attempt.) 2016 ms, faster than 51.45% 
// Memory Usage: 365.3 MB, less than 28.94%
int longestArithSeqLength(vector<int>& A) {
  const int n = A.size();
  // dp[i] = <Diff, Length> information start from A[0], and end with A[i]
  //
  // dp[i][diff] = arithmetic sequence length for 'diff',
  //               start from A[0], and end with A[i]
  //
  // Update order:
  // for i = 0..n-1
  //   for j = i+1..n-1
  //     dp[j][diff] = dp[i][diff] + 1
  vector<unordered_map<int, int>> dp(n);
  
  int longest = 0;
  for (int i = 0; i < n; ++i) {
    for (int j = i + 1; j < n; ++j) {
      const int d = A[j] - A[i];
      const int cnt = dp[i][d] + 1;
      dp[j][d] = cnt;
      longest = max(longest, cnt);
    }
  }

  return longest + 1;
}
// From Sampled commit - Without unordered_map
// 2380 ms, faster than 36.17% 
// Memory Usage: 8.7 MB, less than 92.28%
int longestArithSeqLength(vector<int>& A) {
  int count = 2;
  int ans = 2;
  for (int i = 0; i < A.size(); i++) {
    for (int j = i + 1; j < A.size(); j++) {
      int diff = A[j] - A[i];
      int target = A[j] + diff;
      count = 2;
      for (int k = j+1; k < A.size(); k++) {
        if (A[k] == target){
          target += diff;
          count++;
          ans = max(ans, count);
        }
      }
    }
  }
  return ans;
}
// From Sampled commit
// 24 ms, faster than 99.88%
// 26.5 MB, less than 80.83%
int longestArithSeqLength(vector<int>& A) {      
  int n = A.size();
  int pos[10001];
  memset(pos,-1,sizeof(pos));
  int d[n][n];
  memset(d,0,sizeof(d));
  int ret = 0;
  pos[A[0]] = 0;
  for(int i = 1; i < n; ++i) {
    for(int j = i + 1; j < n; ++j) {
      int prev = 2*A[i] - A[j];

      if (prev < 0 || prev > 10000 || pos[prev] == -1)
        continue;

      d[i][j] = d[pos[prev]][i] + 1;

      if (d[i][j] > ret)
        ret = d[i][j];
    }
    pos[A[i]] = i;
  }
  return ret + 2; 
}

weekly 134
(dp)(classical)(lcs) 1035. Uncrossed Lines
Given two integer arrays A and B.
We can draw a connecting line to connect two numbers from A, B if:

  • A[i] == B[j]
  • The line doesn't intersect with other connecting line.
  • Each number can only belong to to one connecting line.


Return the maximum connecting line.
int maxUncrossedLines(vector<int>& A, vector<int>& B) {
  // Longest Common Subsequence.
  const int m = A.size() + 1;
  const int n = B.size() + 1;
  
  vector<vector<int>> dp(m, vector<int>(n));
  for (int r = 1; r < m; ++r)
    for (int c = 1; c < n; ++c)
      if (A[r-1] == B[c-1])
        dp[r][c] = dp[r - 1][c - 1] + 1;
      else
        dp[r][c] = max(dp[r - 1][c], dp[r][c - 1]);
  return dp[m - 1][n - 1];
}

weekly 135
(dp)(good) 1039. Minimum Score Triangulation of Polygon
Given a n-sided convex with vertices A[0], A[1], ... A[n - 1]
  • Triangulate it into n - 2 triangles
  • Each triangle has a score = A[i] * A[j] * A[k], i, j, k is the vertex of triangle.
  • Return the smallest total score
See votrubac's explanation.
https://leetcode.com/problems/minimum-score-triangulation-of-polygon/discuss/286753/C%2B%2B-with-picture
// ref: neal_wu's contest solution
vector<vector<int>> dp;
int n;

int next(int idx) const { return (idx + 1) % n; }

int solve(int begin, int end, const vector<int> &A) {
  if (next(begin) == end)
    return 0;
  
  if (dp[begin][end])
    return dp[begin][end];
  
  int best = INT_MAX;
  for (int i = next(begin); i != end; i = next(i))
    best = min(best, 
               A[begin]*A[i]*A[end] + 
               solve(begin, i, A) + 
               solve(i, end, A));
  
  dp[begin][end] = best;
  return best;
}

int minScoreTriangulation(vector<int>& A) {
  n = A.size();
  dp.resize(n, vector<int>(n));
  int best = INT_MAX;
  for (int i = 0; i < n; ++i)
    for (int j = i + 1; j < n; ++j)
      for (int k = j + 1; k < n; ++k)
        best = min(best, 
                   solve(i, j, A) + 
                   solve(j, k, A) +
                   solve(k, i, A) +
                   A[i] * A[j] * A[k]);
  return best;
}

weekly 136
(dp) 1043. Partition Array for Maximum Sum
Example
Input: A = [1,15,7,9,2,5,10], K = 3
Output: 84
Explanation: A becomes [15,15,15,9,10,10,10]
Return the largest sum of the given array after partitioning.
int maxSumAfterPartitioning(vector<int>& A, int K) {
  // From lee215:
  // dp[i] record the maximum sum we can get considering A[0] ~ A[i]
  //
  // To get dp[i], we will try to change k last numbers separately to
  // the maximum of them, where k = 1 to k = K.
  const int n = A.size();
  int dp[n];
  dp[0] = A[0];
  
  for (int i = 1; i < n; ++i) {
    int maxSum = 0;
    int maxElem = 0;
    for (int j = 0; j < K; ++j) {
      if (i - j < 0)
        continue;

      maxElem = max(maxElem, A[i - j]);
      int curSum = maxElem * (j + 1);
      if (i - j - 1 >= 0)
        curSum += dp[i - j - 1];
        
      maxSum = max(maxSum, curSum);
    }
    dp[i] = maxSum;
  }

  return dp[n - 1];
}
// By neal_wu's contest solution
int maxSumAfterPartitioning(vector<int>& A, int K) {
    int N = A.size();
    vector<int> dp(N + 1, 0);

    for (int i = 1; i <= N; i++) {
        int most = 0;

        for (int j = i - 1; j >= max(i - K, 0); j--) {
            most = max(most, A[j]);
            dp[i] = max(dp[i], dp[j] + (i - j) * most);
        }
    }

    return dp[N];
}

No comments:

Post a Comment