Scramble String
Given a string s1
, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.
Below is one possible representation of s1 = "great"
:
great
/ \
gr eat
/ \ / \
g r e at
/ \
a t
To scramble the string, we may choose any non-leaf node and swap its two children.
For example, if we choose the node "gr"
and swap its two children, it produces a scrambled string "rgeat"
.
rgeat
/ \
rg eat
/ \ / \
r g e at
/ \
a t
We say that "rgeat"
is a scrambled string of "great"
.
Similarly, if we continue to swap the children of nodes "eat"
and "at"
, it produces a scrambled string "rgtae"
.
rgtae
/ \
rg tae
/ \ / \
r g ta e
/ \
t a
We say that "rgtae"
is a scrambled string of "great"
.
Given two strings s1
and s2
of the same length, determine if s2
is a scrambled string of s1
.
class Solution {
public:
/**
* @param s1: A string
* @param s2: Another string
* @return: whether s2 is a scrambled string of s1
*/
bool isScramble(string &s1, string &s2) {
// write your code here
int n1 = s1.size();
int n2 = s2.size();
if (n1 != n2) {
return false;
}
vector<vector<vector<bool>>> dp(n1 + 1, vector<vector<bool>>(n1 + 1, vector<bool>(n1 + 1, false)));
for (int k = 1; k <= n1; k++) {
for (int i = 0; i + k - 1 < n1; i++) {
for (int j = 0; j + k - 1 < n1; j++) {
if (k == 1) {
dp[i][j][k] = (s1[i] == s2[j]);
} else {
for (int x = 1; x < k; x++) {
bool cond1 = dp[i][j][x] && dp[i + x][j + x][k - x];
bool cond2 = dp[i][j + k - x][x] && dp[i + x][j][k - x];
dp[i][j][k] = cond1 || cond2 || dp[i][j][k];
}
}
}
}
}
return dp[0][0][n1];
}
};
吹气球
有n个气球,编号为0
到n-1
,每个气球都有一个分数,存在nums
数组中。每次吹气球i可以得到的分数为 nums[left] * nums[i] * nums[right]
,left和right分别表示i
气球相邻的两个气球。当i气球被吹爆后,其左右两气球即为相邻。要求吹爆所有气球,得到最多的分数。
给出 [4, 1, 5, 10]
返回 270
nums = [4, 1, 5, 10] burst 1, 得分 4 * 1 * 5 = 20
nums = [4, 5, 10] burst 5, 得分 4 * 5 * 10 = 200
nums = [4, 10] burst 4, 得分 1 * 4 * 10 = 40
nums = [10] burst 10, 得分 1 * 10 * 1 = 10
总共的分数为 20 + 200 + 40 + 10 = 270
class Solution {
public:
/**
* @param nums: A list of integer
* @return: An integer, maximum coins
*/
int maxCoins(vector<int> &nums) {
// write your code here
int n = nums.size();
if (n == 0) {
return 0;
}
vector<int> arr(n + 2, 0);
for (int i = 0; i < n; i++) {
arr[i + 1] = nums[i];
}
arr[0] = 1;
arr[n + 1] = 1;
vector<vector<int>> dp(n + 2, vector<int>(n + 2, 0));
for (int k = 1; k <= n; k++) {
for (int i = 1; i + k - 1 <= n; i++) {
int j = i + k - 1;
for (int x = i; x <= j; x++) {
int midvalue = arr[i - 1] * arr[x] * arr[j + 1];
dp[i][j] = max(dp[i][j], dp[i][x - 1] + dp[x + 1][j] + midvalue);
}
}
}
return dp[1][n];
}
};
Maximum Subarray III
Given an array of integers and a number k, find k non-overlapping
subarrays which have the largest sum.
The number in each subarray should be contiguous.
Return the largest sum.
Notice
The subarray should contain at least one number
Given [-1,4,-2,3,-2,3]
, k=2
, return 8
/* 这题属于动态规划里比较难的一题。首先定义状态,f[i][j]表示:在前i个元素中取出j个不重叠的子数组的和的最大值(也就
* 要将前i个元素组成的数组划分成j个部分,每个部分求最大子数组,然后相加)。状态定义好了之后,需要找到状态之间的关
* ,也就是求动态转移方程。可以将f[i][j]拆分成两部分来看,第一部分是f[x][j - 1],x为j - 1~ i
* - 1之间的任意值,表示前x个元素中取j - 1个子数组的和的最大值。第二部分是[x, x + 1, ..., i -
* 1]数组,求这个数组的maximum subarray(可以理解为在数组[0, 1, ..., x - 1, x, ..., i-
* 1]中任意切一刀,分成两部分。index为x - 1的地方就是那一刀切的地方,第一部分是[0, 1, ..., x - 1],第二部分是[x, x +
* 1, ..., i - 1])。由此得到动态转移方程为:f[i][j] = f[x][j - 1] + maxSubarray([x, x + 1, ..., i - 1])。求max
* subarray的方法可以参考maximum subarray那道题。
*/
int maxSubArray2(vector<int> &nums, int k) {
// write your code here
if (nums.size() == 0 || k == 0 || k > nums.size()) {
return 0;
}
int n = nums.size();
vector<vector<int>> dp(n + 1, vector<int>(k + 1, INT_MIN));
// init
for (int i = 0; i <= n; i++) {
dp[i][0] = 0;
}
for (int j = 1; j <= k; j++) {
for (int i = j; i <= n; i++) {
int cur_sum = 0;
int max_sum = INT_MIN;
for (int x = i - 1; x >= j - 1; x--) {
cur_sum = max(cur_sum + nums[x], nums[x]);
max_sum = max(max_sum, cur_sum);
dp[i][j] = max(dp[i][j], dp[x][j - 1] + max_sum);
}
}
}
return dp[n][k];
}