Dynamic Programming Questions: 5. Longest Palindromic Substring
Dynamic Programming Questions: 5. Longest Palindromic Substring
Dynamic Programming Questions: 5. Longest Palindromic Substring
Download PDF
Example 1:
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
Example 2:
Input: "cbbd"
Output: "bb"
Solution
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size(), start, max_len = 0;
if (n == 0) return "";
vector<vector<bool>> dp(n, vector<bool>(n, false));
for (int i = 0; i < n; ++i) dp[i][i] = true;
for (int i = 0; i < n - 1; ++i) dp[i][i + 1] = s[i] == s[i + 1];
for (int i = n - 3; i >= 0; --i) {
for (int j = i + 2; j < n; ++j) {
dp[i][j] = dp[i + 1][j - 1] && s[i] == s[j];
}
}
for (int i = 0; i < n; ++i) {
for (int j = i; j < n; ++j) {
if (dp[i][j] && j - i + 1 > max_len) {
max_len = j - i + 1;
start = i;
}
}
}
return s.substr(start, max_len);
}
};
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size(), start = 0, max_len = n > 0 ? 1 : 0;
for(int i = 0; i < n; ++i) {
for (int l = i - 1, r = i; l >= 0 && r < n && s[l] == s[r]; --l, ++r) {
if (r - l + 1 > max_len) {
max_len = r - l + 1;
start = l;
}
}
for (int l = i - 1, r = i + 1; l >= 0 && r < n && s[l] == s[r]; --l, ++r)
{
if (r - l + 1 > max_len) {
max_len = r - l + 1;
start = l;
}
}
}
return max_len == 0 ? "" : s.substr(start, max_len);
}
};
Given an integer array nums, find the contiguous subarray (containing at least
one number) which has the largest sum and return its sum.
Example:
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
Follow up:
If you have figured out the O(n) solution, try coding another solution using the
divide and conquer approach, which is more subtle.
Solution
The robot can only move either down or right at any point in time. The robot is
trying to reach the bottom-right corner of the grid (marked 'Finish' in the
diagram below).
Example 1:
Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right
corner:
1. Right -> Right -> Down
2. Right -> Down -> Right
3. Down -> Right -> Right
Example 2:
Input: m = 7, n = 3
Output: 28
Solution
01/29/2020:
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<long long>> dp(m + 1, vector<long long>(n + 1, 0));
dp[0][1] = 1;
for (int i = 1; i < m + 1; ++i) {
for (int j = 1; j < n + 1; ++j) {
dp[i][j] = dp[i][j - 1] + dp[i - 1][j];
}
}
return dp[m][n];
}
};
The robot can only move either down or right at any point in time. The robot is
trying to reach the bottom-right corner of the grid (marked 'Finish' in the
diagram below).
Now consider if some obstacles are added to the grids. How many unique paths
would there be?
Example 1:
Input:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
Output: 2
Explanation:
There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right
Solution
01/27/2020:
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size(), n = obstacleGrid[0].size();
if (m == 0 || n == 0) return 1;
vector<vector<long>> dp(m, vector<long>(n, 0));
dp[0][0] = obstacleGrid[0][0] == 1 ? 0 : 1;
// dp[i][j] the total number of unique moves
// dp[i][j] = dp[i - 1][j] * (grid[i - 1][j] != 1) + dp[i][j - 1] * (grid[i]
[j - 1] != 1)
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (obstacleGrid[i][j] == 1) {
dp[i][j] = 0;
continue;
}
if (i - 1 >= 0) dp[i][j] += dp[i - 1][j] * (obstacleGrid[i - 1][j] != 1
? 1 : 0);
if (j - 1 >= 0) dp[i][j] += dp[i][j - 1] * (obstacleGrid[i][j - 1] != 1
? 1 : 0);
}
}
return (m - 1 >= 0 && n - 1 >= 0) ? dp[m - 1][n - 1] : 0;
}
};
Given a m x n grid filled with non-negative numbers, find a path from top left
to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
Example:
Input:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes the sum.
Solution
01/27/2020:
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
if (m == 0 || n == 0) return 0;
const int INF = 1e9 + 5;
vector<vector<int>> dp(m, vector<int>(n, INF));
dp[0][0] = grid[0][0];
// dp[i][j]: the minimum sum from grid[0][0] to grid[i][j]
// dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (i - 1 >= 0) dp[i][j] = min(grid[i][j] + dp[i - 1][j], dp[i][j]);
if (j - 1 >= 0) dp[i][j] = min(grid[i][j] + dp[i][j - 1], dp[i][j]);
}
}
return dp[m - 1][n - 1];
}
};
You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you
climb to the top?
Note: Given n will be a positive integer.
Example 1:
Input: 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
Example 2:
Input: 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step
Solution
class Solution {
public:
int climbStairs(int n) {
int s1 = 1, s2 = 2;
for (int i = 2; i < n; ++i) {
s1 = s1 + s2;
swap(s1, s2);
}
return n >= 2 ? s2 : s1;
}
};
Given two words word1 and word2, find the minimum number of operations required
to convert word1 to word2.
Insert a character
Delete a character
Replace a character
Example 1:
Solution
01/27/2020:
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
if (m == 0) return n;
if (n == 0) return m;
const int INF = 1e9 + 5;
vector<vector<int>> dp(m + 1, vector(n + 1, INF));
dp[0][0] = 0;
// dp[i][j]: the edit distance between word1[0..i] and word2[0..j]
// dp[i][j] = dp[i - 1][j - 1] if word1[i] == word2[j]: no operations
needed
// dp[i][j] = min( if word1[i] != word2[j]
// dp[i - 1][j - 1] + 1, replace word1[i] by word2[j]
// dp[i - 1][j] + 1, delete character word1[i]
// dp[i][j - 1] + 1 delete character word2[j]
// )
for (int i = 1; i <= m; ++i) dp[i][0] = dp[i - 1][0] + 1;
for (int j = 1; j <= n; ++j) dp[0][j] = dp[0][j - 1] + 1;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (word1[i - 1] == word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = min(dp[i - 1][j], min(dp[i][j - 1], dp[i - 1][j - 1])) + 1;
}
}
}
return dp[m][n];
}
};
Say you have an array for which the ith element is the price of a given stock on
day i.
If you were only permitted to complete at most one transaction (i.e., buy one
and sell one share of the stock), design an algorithm to find the maximum
profit.
Note that you cannot sell a stock before you buy one.
Example 1:
Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-
1 = 5.
Not 7-1 = 6, as selling price needs to be larger than buying price.
Example 2:
Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.
Solution
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
if (n <= 1) return 0;
vector<int> diff(n - 1, 0);
for (int i = 0; i < n - 1; ++i) {
diff[i] = prices[i + 1] - prices[i];
}
int max_sum = max(0, diff[0]);
for (int i = 1; i < n - 1; ++i) {
if (diff[i - 1] > 0) diff[i] += diff[i - 1];
max_sum = max(diff[i], max_sum);
}
return max_sum;
}
};
You are a professional robber planning to rob houses along a street. Each house
has a certain amount of money stashed, the only constraint stopping you from
robbing each of them is that adjacent houses have security system connected and
it will automatically contact the police if two adjacent houses were broken into
on the same night.
Example 1:
Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
Example 2:
Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5
(money = 1).
Total amount you can rob = 2 + 9 + 1 = 12.
Solution
There are a row of n houses, each house can be painted with one of the three
colors: red, blue or green. The cost of painting each house with a certain color
is different. You have to paint all the houses such that no two adjacent houses
have the same color.
Note:
All costs are positive integers.
Example:
Input: [[17,2,17],[16,16,5],[14,3,19]]
Output: 10
Explanation: Paint house 0 into blue, paint house 1 into green, paint house 2
into blue.
Minimum cost: 2 + 5 + 3 = 10.
Solution
05/26/2020:
class Solution {
public:
int minCost(vector<vector<int>>& costs) {
if (costs.empty()) return 0;
int n = costs.size();
for (int i = 1; i < n; ++i) {
costs[i][0] += min(costs[i - 1][1], costs[i - 1][2]);
costs[i][1] += min(costs[i - 1][0], costs[i - 1][2]);
costs[i][2] += min(costs[i - 1][0], costs[i - 1][1]);
}
return *min_element(costs.back().begin(), costs.back().end());
}
};
class Solution {
public:
int minCost(vector<vector<int>>& costs) {
for (int i = 1; i < costs.size(); ++i) {
for (int j = 0; j < costs[0].size(); ++j) {
int cur_min = INT_MAX;
for (int k = 0; k < costs[0].size(); ++k)
if (k != j)
cur_min = min(cur_min, costs[i - 1][k]);
costs[i][j] += cur_min;
}
}
return costs.size() > 0 ? *min_element(costs.back().begin(),
costs.back().end()) : 0;
}
};
There is a fence with n posts, each post can be painted with one of the k
colors.
You have to paint all the posts such that no more than two adjacent fence posts
have the same color.
Return the total number of ways you can paint the fence.
Note:
n and k are non-negative integers.
Example:
Input: n = 3, k = 2
Output: 6
Explanation: Take c1 as color 1, c2 as color 2. All possible ways are:
Solution
class Solution {
public:
int numWays(int n, int k) {
if (n == 0 || k == 0) return 0;
vector<vector<int>> dp(n, vector<int>(2, 0));
dp[0][0] = k;
for (int i = 1; i < n; ++i) {
dp[i][0] = (dp[i - 1][0] + dp[i - 1][1]) * (k - 1);
dp[i][1] = dp[i - 1][0];
}
return dp.back()[0] + dp.back()[1];
}
};
class Solution {
public:
int numWays(int n, int k) {
if (n == 0 || k == 0) return 0;
vector<int> dp(2, 0);
dp[0] = k;
for (int i = 1; i < n; ++i) {
int tmp = dp[0];
dp[0] = (dp[0] + dp[1]) * (k - 1);
dp[1] = tmp;
}
return dp[0] + dp[1];
}
};
Given an integer array nums, find the sum of the elements between indices i and
j (i ≤ j), inclusive.
Example:
sumRange(0, 2) -> 1
sumRange(2, 5) -> -1
sumRange(0, 5) -> -3
Note:
Solution
class NumArray {
public:
vector<int> nums;
NumArray(vector<int>& nums) {
for (int i = 1; i < nums.size(); ++i) nums[i] += nums[i - 1];
this->nums = nums;
}
/**
* Your NumArray object will be instantiated and called as such:
* NumArray* obj = new NumArray(nums);
* int param_1 = obj->sumRange(i,j);
*/
Given a non negative integer number num. For every numbers i in the range 0 ≤ i
≤ num calculate the number of 1's in their binary representation and return them
as an array.
Example 1:
Input: 2
Output: [0,1,1]
Example 2:
Input: 5
Output: [0,1,1,2,1,2]
Follow up:
Solution
class Solution {
public:
vector<int> countBits(int num) {
vector<int> dp(num + 1, 0);
for (int i = 1, m = 1; i <= num; ++i) {
if (i == m << 1) m <<= 1;
dp[i] = dp[i % m] + 1;
}
return dp;
}
};
392. Is Subsequence
Description
You may assume that there is only lower case English letters in both s and t. t
is potentially a very long (length ~= 500,000) string, and s is a short string
(<=100).
Example 1:
s = "abc", t = "ahbgdc"
Return true.
Example 2:
s = "axc", t = "ahbgdc"
Return false.
Follow up:
If there are lots of incoming S, say S1, S2, ... , Sk where k >= 1B, and you
want to check one by one to see if T has its subsequence. In this scenario, how
would you change your code?
Credits:
Special thanks to @pbrother for adding this problem and creating all test cases.
Solution
class Solution {
public:
bool isSubsequence(string s, string t) {
if (s.size() >= t.size()) return s == t;
return s.back() == t.back() ? isSubsequence(s.substr(0, s.size() - 1),
t.substr(0, t.size() - 1)) :
isSubsequence(s, t.substr(0, t.size() - 1));
}
};
01/14/2020 (Dynamic Programming (bottom-up), Two pointers):
class Solution {
public:
bool isSubsequence(string s, string t) {
int ps = 0, pt = 0;
for (; ps < s.size() && pt < t.size(); ++pt)
if (s[ps] == t[pt]) ++ps;
return ps == s.size();
}
};
Given a string, your task is to count how many palindromic substrings in this
string.
The substrings with different start indexes or end indexes are counted as
different substrings even they consist of same characters.
Example 1:
Input: "abc"
Output: 3
Explanation: Three palindromic strings: "a", "b", "c".
Example 2:
Input: "aaa"
Output: 6
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".
Note:
Solution
Initially on a notepad only one character 'A' is present. You can perform two
operations on this notepad for each step:
Copy All: You can copy all the characters present on the notepad (partial copy
is not allowed).
Paste: You can paste the characters which are copied last time.
Given a number n. You have to get exactly n 'A' on the notepad by performing the
minimum number of steps permitted. Output the minimum number of steps to get n
'A'.
Example 1:
Input: 3
Output: 3
Explanation:
Intitally, we have one character 'A'.
In step 1, we use Copy All operation.
In step 2, we use Paste operation to get 'AA'.
In step 3, we use Paste operation to get 'AAA'.
Note:
06/09/2020:
class Solution {
public:
int minSteps(int n) {
// dp[i]: the minimum steps to obtain i A's
// dp[i] = min_j(dp[j] + 1 + (i - j) / j) = min_j(dp[j] + 1 + i / j - 1) =
min_j(dp[j] + i / j)
vector<int> dp(n + 1, INT_MAX);
dp[1] = 0;
for (int i = 2; i <= n; ++i)
for (int j = 1; j < i; ++j)
if (i % j == 0)
dp[i] = min(dp[i], dp[j] + i / j);
return dp[n];
}
};
Alex and Lee play a game with piles of stones. There are an even number of
piles arranged in a row, and each pile has a positive integer number of stones
piles[i].
The objective of the game is to end with the most stones. The total number of
stones is odd, so there are no ties.
Alex and Lee take turns, with Alex starting first. Each turn, a player takes
the entire pile of stones from either the beginning or the end of the row. This
continues until there are no more piles left, at which point the person with the
most stones wins.
Assuming Alex and Lee play optimally, return True if and only if Alex wins the
game.
Example 1:
Input: [5,3,4,5]
Output: true
Explanation:
Alex starts first, and can only take the first 5 or the last 5.
Say he takes the first 5, so that the row becomes [3, 4, 5].
If Lee takes 3, then the board is [4, 5], and Alex takes 5 to win with 10
points.
If Lee takes the last 5, then the board is [3, 4], and Alex takes 4 to win with
9 points.
This demonstrated that taking the first 5 was a winning move for Alex, so we
return true.
Note:
Solution
01/15/2020 (Mathematics):
class Solution {
public:
bool stoneGame(vector<int>& piles) {
return true;
}
};
class Solution {
public:
bool stoneGame(vector<int>& piles) {
// dp[i][j]: the largest number of stones Alex can pick
int n = piles.size();
vector<vector<int>> dp(n, vector<int>(n, 0));
for (int i = 0; i < n; ++i) dp[i][i] = piles[i];
for (int i = 0; i < n - 1; ++i) {
for (int j = i + 1; j < n; ++j) {
dp[i][j] = max(piles[i] + dp[i + 1][j], piles[j] + dp[i][j - 1]);
}
}
return dp[0][n - 1] > max(dp[1][n - 1], dp[0][n - 2]);
}
};
931. Minimum Falling Path Sum
Description
Given a square array of integers A, we want the minimum sum of a falling path
through A.
A falling path starts at any element in the first row, and chooses one element
from each row. The next row's choice must be in a column that is different from
the previous row's column by at most one.
Example 1:
Input: [[1,2,3],[4,5,6],[7,8,9]]
Output: 12
Explanation:
The possible falling paths are:
[1,4,7], [1,4,8], [1,5,7], [1,5,8], [1,5,9]
[2,4,7], [2,4,8], [2,5,7], [2,5,8], [2,5,9], [2,6,8], [2,6,9]
[3,5,7], [3,5,8], [3,5,9], [3,6,8], [3,6,9]
The falling path with the smallest sum is [1,4,7], so the answer is 12.
Note:
Solution
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& A) {
int n = A[0].size(), K = 1;
if (n == 0) return 0;
// dp[i][j]: the current smallest sum from row 0 to row i at column j.
vector<vector<int>> dp(n, vector<int>(n, 0));
for (int i = 0; i < n; ++i) dp[0][i] = A[0][i];
for (int i = 1; i < n; ++i) {
for (int j = 0; j < n; ++j) {
int cur_min = INT_MAX;
for (int k = -K; k <= K; ++k) {
int l = j + k;
if(l >= 0 && l < n) {
cur_min = min(cur_min, dp[i - 1][l] + A[i][j]);
}
}
dp[i][j] = cur_min;
}
}
return *min_element(dp.back().begin(), dp.back().end());
}
};
We write the integers of A and B (in the order they are given) on two separate
horizontal lines.
Now, we may draw connecting lines: a straight line connecting two numbers A[i]
and B[j] such that:
A[i] == B[j];
The line we draw does not intersect any other connecting (non-horizontal) line.
Note that a connecting lines cannot intersect even at the endpoints: each number
can only belong to one connecting line.
Return the maximum number of connecting lines we can draw in this way.
Example 1:
Note:
Solution
05/25/2020:
class Solution {
public:
int maxUncrossedLines(vector<int>& A, vector<int>& B) {
if (A.empty() && B.empty()) return 0;
// dp[i][j]: the maximum number of lines can be drawn of A[0..i] and B[0..j]
// same as longest common subsequence
int m = A.size(), n = B.size();
vector<vector<int>> dp(m, vector<int>(n, 0));
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
dp[i][j] = A[i] == B[j];
if (i > 0 && j > 0) dp[i][j] = dp[i][j] + dp[i - 1][j - 1];
if (i > 0) dp[i][j] = max(dp[i][j], dp[i - 1][j]);
if (j > 0) dp[i][j] = max(dp[i][j], dp[i][j - 1]);
}
}
return dp.back().back();
}
};
Given a m * n matrix of ones and zeros, return how many square submatrices have
all ones.
Example 1:
Input: matrix =
[
[0,1,1,1],
[1,1,1,1],
[0,1,1,1]
]
Output: 15
Explanation:
There are 10 squares of side 1.
There are 4 squares of side 2.
There is 1 square of side 3.
Total number of squares = 10 + 4 + 1 = 15.
Example 2:
Input: matrix =
[
[1,0,1],
[1,1,0],
[1,1,0]
]
Output: 7
Explanation:
There are 6 squares of side 1.
There is 1 square of side 2.
Total number of squares = 6 + 1 = 7.
Constraints:
Solution
class Solution {
public:
int countSquares(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size(), ret = 0;;
vector<vector<int>> dp(m, vector<int>(n, 0));
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (i == 0 || j == 0)
dp[i][j] = matrix[i][j];
else
dp[i][j] = matrix[i][j] == 0 ? 0 : min(min(dp[i - 1][j - 1], dp[i - 1]
[j]), dp[i][j - 1]) + 1;
ret += dp[i][j];
}
}
return ret;
}
};
Given a m * n matrix mat and an integer K, return a matrix answer where each
answer[i][j] is the sum of all elements mat[r][c] for i - K <= r <= i + K, j - K
<= c <= j + K, and (r, c) is a valid position in the matrix.
Example 1:
Constraints:
m == mat.length
n == mat[i].length
1 <= m, n, K <= 100
1 <= mat[i][j] <= 100
Solution
01/14/2020 (Definition):
class Solution {
public:
vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int K) {
int m = mat.size(), n = mat[0].size();
vector<vector<int>> ret(m, vector<int>(n, 0));
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = -K; k <= K; ++k) {
for (int l = -K; l <= K; ++l) {
if (i + k >= 0 && i + k < m && j + l >= 0 && j + l < n) {
ret[i][j] += mat[i + k][j + l];
}
}
}
}
}
return ret;
}
};
class Solution {
public:
vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int K) {
int m = mat.size(), n = mat[0].size();
vector<vector<int>> dp(m, vector<int>(n, 0));
vector<vector<int>> ret(m, vector<int>(n, 0));
dp[0][0] = mat[0][0];
for (int i = 1; i < m; ++i) dp[i][0] += dp[i - 1][0] + mat[i][0];
for (int j = 1; j < n; ++j) dp[0][j] += dp[0][j - 1] + mat[0][j];
for (int i = 1; i < m; ++i)
for (int j = 1; j < n; ++j)
dp[i][j] = mat[i][j] + dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
int r1 = max(i - K, 0);
int c1 = max(j - K, 0);
int r2 = min(i + K, m - 1);
int c2 = min(j + K, n - 1);
ret[i][j] = dp[r2][c2];
if (r1 > 0) ret[i][j] -= dp[r1 - 1][c2];
if (c1 > 0) ret[i][j] -= dp[r2][c1 - 1];
if (r1 > 0 && c1 > 0) ret[i][j] += dp[r1 - 1][c1 - 1];
}
}
return ret;
}
};
There is a one-dimensional garden on the x-axis. The garden starts at the point
0 and ends at the point n. (i.e The length of the garden is n).
Return the minimum number of taps that should be open to water the whole garden,
If the garden cannot be watered return -1.
Example 1:
Solution
class Solution {
public:
int minTaps(int n, vector<int>& ranges) {
const int INF = 1e9 + 5;
vector<int> dp(n + 1, INF);
for (int i = 0; i < n + 1; ++i) {
int left = max(i - ranges[i], 0);
int best = i - ranges[i] <= 0 ? 1 : dp[left] + 1;
for (int j = i; j <= min(i + ranges[i], n); ++j) {
dp[j] = min(dp[j], best);
}
}
return dp.back() == INF ? -1 : dp.back();
}
};
You want to schedule a list of jobs in d days. Jobs are dependent (i.e To work
on the i-th job, you have to finish all the jobs j where 0 <= j < i).
You have to finish at least one task every day. The difficulty of a job schedule
is the sum of difficulties of each day of the d days. The difficulty of a day is
the maximum difficulty of a job done in that day.
Return the minimum difficulty of a job schedule. If you cannot find a schedule
for the jobs return -1.
Example 1:
Constraints:
Solution
01/26/2020:
class Solution {
public:
int minDifficulty(vector<int>& jobDifficulty, int d) {
int n = jobDifficulty.size();
if (n < d) return -1;
vector<vector<int>> diff(n, vector<int>(n, 0));
// diff[i][j]: max diff from jobDifficulty[i] to jobDifficulty[j]
for (int i = 0; i < n; ++i) {
diff[i][i] = jobDifficulty[i];
for (int j = i + 1; j < n; ++j) {
diff[i][j] = max(diff[i][j - 1], jobDifficulty[j]);
}
}
const int INF = 1e9 + 5;
// dp[i][j]: min diff of i jobs in j days
// dp[i][j] = min(dp[j - 1][j - 1] + diff[j][i], dp[j][j - 1] + diff[j + 1]
[i], ..., dp[i - 1][j - 1] + diff[i][i])
vector<vector<int>> dp(n, vector<int>(d, INF));
for (int j = 0; j < d; ++j) {
for (int i = 0; i < n; ++i) {
if (j == 0) {
dp[i][j] = diff[j][i];
} else {
for (int k = j - 1; k < i; ++k) {
dp[i][j] = min(dp[i][j], dp[k][j - 1] + diff[k + 1][i]);
}
}
}
}
return dp[n - 1][d - 1];
}
};
Return the maximum dot product between non-empty subsequences of nums1 and nums2
with the same length.
A subsequence of a array is a new array which is formed from the original array
by deleting some (can be none) of the characters without disturbing the relative
positions of the remaining characters. (ie, [2,3,5] is a subsequence of
[1,2,3,4,5] while [1,5,3] is not).
Example 1:
Constraints:
Solution
05/23/2020:
class Solution {
public:
int maxDotProduct(vector<int>& nums1, vector<int>& nums2) {
// dp[i][j]: the maximum dot product of two subsequences
// nums1[0..i], nums2[0..j];
// dp[i][j] = max(max(0, nums1[i] * nums2[j]) + dp[i - 1][j - 1], dp[i - 1]
[j], dp[i][j - 1])
int n1 = nums1.size(), n2 = nums2.size();
vector<vector<int>> dp(n1, vector<int>(n2, INT_MIN));
dp[0][0] = nums1[0] * nums2[0];
for (int i = 1; i < n1; ++i) dp[i][0] = max(nums1[i] * nums2[0], dp[i - 1]
[0]);
for (int j = 1; j < n2; ++j) dp[0][j] = max(nums1[0] * nums2[j], dp[0][j -
1]);
for (int i = 1; i < n1; ++i) {
for (int j = 1; j < n2; ++j) {
dp[i][j] = max(nums1[i] * nums2[j], 0) + dp[i - 1][j - 1];
dp[i][j] = max(dp[i][j], dp[i - 1][j]);
dp[i][j] = max(dp[i][j], dp[i][j - 1]);
dp[i][j] = max(dp[i][j], nums1[i] * nums2[j]);
}
}
return dp[n1 - 1][n2 - 1];
}
};
class Solution {
public:
int maxDotProduct(vector<int>& nums1, vector<int>& nums2) {
int n1 = nums1.size(), n2 = nums2.size();
vector<vector<int>> dp(n1, vector<int>(n2));
for (int i = 0; i < n1; ++i) {
for (int j = 0; j < n2; ++j) {
dp[i][j] = nums1[i] * nums2[j];
if (i > 0 && j > 0) dp[i][j] = max(dp[i][j], max(nums1[i] * nums2[j], 0)
+ dp[i - 1][j - 1]);
if (i > 0) dp[i][j] = max(dp[i][j], dp[i - 1][j]);
if (j > 0) dp[i][j] = max(dp[i][j], dp[i][j - 1]);
}
}
return dp[n1 - 1][n2 - 1];
}
};
1473. Paint House III
Description
There is a row of m houses in a small city, each house must be painted with one
of the n colors (labeled from 1 to n), some houses that has been painted last
summer should not be painted again.
A neighborhood is a maximal group of continuous houses that are painted with the
same color. (For example: houses = [1,2,2,3,3,2,1,1] contains 5 neighborhoods
[{1}, {2,2}, {3,3}, {2}, {1,1}]).
houses[i]: is the color of the house i, 0 if the house is not painted yet.
cost[i][j]: is the cost of paint the house i with the color j+1.
Return the minimum cost of painting all the remaining houses in such a way that
there are exactly target neighborhoods, if not possible return -1.
Example 1:
Constraints:
m == houses.length == cost.length
n == cost[i].length
1 <= m <= 100
1 <= n <= 20
1 <= target <= m
0 <= houses[i] <= n
1 <= cost[i][j] <= 10^4
Solution
06/06/2020:
int dp[101][101][20];
class Solution {
public:
int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int
target) {
fill_n(dp[0][0], 101 * 101 * 20, INT_MAX);
fill_n(dp[0][0], 20, 0);
for (int i = 1; i <= m; ++i) {
int hi = houses[i - 1] - 1;
for (int k = 1; k <= target; ++k) {
for (int j = 0; j < n; ++j) {
if (hi != -1) {
dp[k][i][hi] = hi == j ? min(dp[k][i][hi], dp[k][i - 1][hi]) :
min(dp[k][i][hi], dp[k - 1][i - 1][j]);
} else {
if (dp[k][i - 1][j] != INT_MAX)
dp[k][i][j] = min(dp[k][i][j], dp[k][i - 1][j] + cost[i - 1][j]);
for (int l = 0; l < n; ++l)
if (l != j && dp[k - 1][i - 1][l] != INT_MAX)
dp[k][i][j] = min(dp[k][i][j], dp[k - 1][i - 1][l] + cost[i - 1]
[j]);
}
}
}
}
int ret = *min_element(dp[target][m], dp[target][m] + n);
return ret == INT_MAX ? -1 : ret;
}
};
int dp[101][20][101];
class Solution {
public:
int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int
target) {
for (int k = 0; k <= target; ++k)
for (int i = 0; i <= m; ++i)
for (int j = 0; j < n; ++j)
dp[i][j][k] = INT_MAX;
for (int j = 0; j < n; ++j) dp[0][j][0] = 0; // no houses, with target 0
for (int i = 1; i <= m; ++i) {
int house_i = houses[i - 1] - 1;
if (house_i != -1) {
for (int k = 1; k <= target; ++k) {
dp[i][house_i][k] = min(dp[i][house_i][k], dp[i - 1][house_i][k]);
for (int j = 0; j < n; ++j) {
if (j == house_i) continue;
dp[i][house_i][k] = min(dp[i][house_i][k], dp[i - 1][j][k - 1]);
}
}
} else {
for (int k = 1; k <= target; ++k) {
for (int j = 0; j < n; ++j) {
if (dp[i - 1][j][k] != INT_MAX) dp[i][j][k] = min(dp[i][j][k], dp[i
- 1][j][k] + cost[i - 1][j]);
for (int l = 0; l < n; ++l) {
if (l == j || dp[i - 1][l][k - 1] == INT_MAX) continue;
dp[i][j][k] = min(dp[i][j][k], dp[i - 1][l][k - 1] + cost[i - 1]
[j]);
}
}
}
}
}
int ret = INT_MAX;
for (int j = 0; j < n; ++j)
ret = min(ret, dp[m][j][target]);
return ret == INT_MAX ? -1 : ret;
}
};
Return the minimum total distance between each house and its nearest mailbox.
Example 1:
Constraints:
n == houses.length
1 <= n <= 100
1 <= houses[i] <= 10^4
1 <= k <= n
Array houses contain unique integers.
Solution
06/13/2020:
int dp[105][105];
class Solution {
public:
int minDistance(vector<int>& houses, int k) {
memset(dp, -1, sizeof(dp));
sort(houses.begin(), houses.end());
return solve(houses, houses.size(), k);
}
};