class TextEditor {
public:
TextEditor() {
}
void addText(string text) {
for(auto &a : text) lt.push(a);
}
int deleteText(int k) {
int res = 0;
while (lt.size() && k > 0) {
lt.pop();
++res;
--k;
}
// cout << "delet" << endl;
return res;
}
string cursorLeft(int k) {
while(lt.size() && k > 0) {
auto t = lt.top();
lt.pop();
rt.push(t);
--k;
}
return f(lt, 10);
}
string cursorRight(int k) {
while(rt.size() && k > 0) {
auto t = rt.top();
rt.pop();
lt.push(t);
--k;
}
return f(lt, 10);
}
private:
stack<int> lt, rt;
string f(stack<int> &sk, int k) {
string res;
while(sk.size() && k > 0) {
res.push_back(sk.top());
sk.pop();
--k;
}
reverse(res.begin(), res.end());
for(auto &a : res) sk.push(a);
return res;
}
};
/**
* Your TextEditor object will be instantiated and called as such:
* TextEditor* obj = new TextEditor();
* obj->addText(text);
* int param_2 = obj->deleteText(k);
* string param_3 = obj->cursorLeft(k);
* string param_4 = obj->cursorRight(k);
*/This blog is mainly about algorithm analysis. The coding questions are mainly from Leetcode and Lintcode. Please leave your message if you have any comments or suggestions. Thanks!
Sunday, June 5, 2022
[Leetcode] 2296. Design a Text Editor
Saturday, June 4, 2022
[Leetcode] 2293. Min Max Game
class Solution {
public:
int minMaxGame(vector<int>& nums) {
return f(nums, 0, nums.size(), 0);
}
private:
int f(vector<int>&ns, int left, int right, int flag) {
if(left+1 == right) return ns[left];
int mid = left + (right - left)/2;
int x = f(ns, left, mid, 0), y = f(ns, mid, right, 1);
return flag ? max(x, y) : min(x, y);
}
};Tuesday, December 28, 2021
[Leetcode] 813. Largest Sum of Averages
813. Largest Sum of Averages
You are given an integer array nums and an integer k. You can partition the array into at most k non-empty adjacent subarrays. The score of a partition is the sum of the averages of each subarray.
Note that the partition must use every integer in nums, and that the score is not necessarily an integer.
Return the maximum score you can achieve of all the possible partitions. Answers within 10-6 of the actual answer will be accepted.
Constraints:
1 <= nums.length <= 100
1 <= nums[i] <= 10^4
1 <= k <= nums.length
Analysis:
This question asks for the an maximum value, so we usually can consider dp first.
As it is known, the key for dp is to find the transition formula. Or find the key parameters than describe an "intermediate state" completely.
The intermediate state here represents a similar question but with a smaller size.
For this question, we can try to define the state as dp[i][k], where i is the index of the elements and k is the number of subarrays.
The meaning of dp[i][k] is the maximum of average sum ending with the ith element with at most k subarrays.
Then the next step is to derive the formula to calculate the value of dp[i][k] using the previous dp with smaller values of i and k.
dp[i][k] = max(dp[x][k-1] + sum(num[x+1] to nums[i])/(i-x)), where x from 0 to i-1.
With the meaning of dp[x][k-1], the above formula is not hard to understand:
The right-hand side (rhs) enumerates all the possible ways to calculate dp[i][k], so we just need to pick up the maximum of it.
In the implementation, the boundary conditions are tricky. The thumb rule is to make sure the dp[i][k] is valid. For example, dp[i>0][0] is not valid, since there is no such case that we have non-zero elements in 0 subarray.
See the code below:
class Solution {
public:
double largestSumOfAverages(vector<int>& nums, int k) {
// dp[i][j]: the max, ending at i, up to j subarray;
// dp[i][j] = max(dp[d][j-1] + sum(nums[d+1], ..., nums[i])/(i-d))
// where d from j-1 to i-1.
double res = 0;
int n = nums.size();
vector<double> sums(n+1, 0);
for(int i=0; i<n; ++i) sums[i+1] = sums[i] + nums[i];
vector<vector<double>> dp(n+1, vector<double>(k+1, 0));
for(int i=1; i<=n; ++i) {
for(int j=min(i, k); j>=1; --j) {
for(int d=max(j-1, 1); d<=i; ++d) {
double v = (j==1&&d>1) ? 0 : (dp[d-1][j-1] + (sums[i]-sums[d-1])/(i-d+1));
dp[i][j] = max(dp[i][j], v);
}
}
}
return dp[n][k];
}
};If do not like the boundary conditions of the above dp solution, we can try dfs + memoization.
We can start from the beginning of the array, and stop to make a subarray at any possible places.
See the code below:
class Solution {
public:
double largestSumOfAverages(vector<int>& nums, int k) {
int n = nums.size();
vector<vector<double>> memo(n, vector<double>(k, -1));
return dfs(nums, 0, k-1, memo);
}
private:
double dfs(vector<int>& ns, int id, int k, vector<vector<double>>& memo) {
// invalid ending since we cannot have more than k subarrays
if(k<0 && id<ns.size()) return -2;
if(id==ns.size()) return 0;
if(memo[id][k] != -1) return memo[id][k];
double t = 0, sum = 0;
for(int i=id; i<ns.size(); ++i) {
sum += ns[i];
double v = dfs(ns, i+1, k-1, memo);
if(v>-2) t = max(t, sum/(i-id+1) + v);
}
return memo[id][k] = t;
}
};
Sunday, December 26, 2021
[Leetcode] 2104. Sum of Subarray Ranges
2104. Sum of Subarray Ranges
You are given an integer array nums. The range of a subarray of nums is the difference between the largest and smallest element in the subarray.
Return the sum of all subarray ranges of nums.
A subarray is a contiguous non-empty sequence of elements within an array.
Constraints:
1 <= nums.length <= 1000
-10^9 <= nums[i] <= 10^9
Follow-up: Could you find a solution with O(n) time complexity?
Analysis:
First of all, we can use a two-layer for loop to solve this problem, since the maximum length is 10^3, so O(N^2) is acceptable for the online OJ.
For any array with N elements, there are N*(N+1)/2 sub-arrays. So we just need to get the min and max of each sub-array, and sum the diffs together.
See the code below:
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
long long res = 0, n = nums.size();
for(int i=0; i<n; ++i) {
int mx = nums[i], mi = mx;
for(int j=i+1; j<n; ++j) {
mx = max(nums[j], mx);
mi = min(nums[j], mi);
res += (long)mx - (long)mi;
}
}
return res;
}
};As asked in the follow up, can we do better?
(Please be noted: the following logic is quite non-intuitive, and requires at least 10 min to read.)
The answer is yes. For example, with a stack, the time complexity can be decreased to O(N).
Think about one classical question about stack: In an integer array with size of N, for each element, what is the first element larger than it?
One observation is that: if we maintain a monotonically increasing stack, then we can derive many useful information. For example, we can derive the answers to the above question for every elements in a time complexity of O(N), or just in one scan for every element.
At the same time, we can get the number of the elements larger than every element on its right side continuously!
For example, say we have one array [6, 9, 3, 5, 10, 1, 4, 7], and we will use a stack to scan through the array from left to right.
One trick here is to use the index instead of value (recording index is obvious better than value with an array, since once we know the index, we know the value as well; but not the reverse)
At step 1, we have [0];
2, [0, 1]
At step 3, the index is 2 and the value is 3, and 3 < arr[1] == 9 (which is the top of the stack), we need to pop out the top element in the stack, so we get the number of elements larger than arr[1] continuously is (2 - 1 - 1) = 1. So res[1] = 0;
We will continue the comparison between the new top of the stack and arr[2]. Now the top is 0. and arr[0] == 6 > arr[2] == 3, so we need to pop it as well. So res[0] = 2 - 0 - 1= 1.
The stack becomes empty, so we just put 2 into it.
So far, we have obtained res[0] = 1 and res[1] = 0. Are they correct?
It is straightforward that the answer is yes. For arr[0], there is one which is arr[1]; for arr[1], there is none.
Let continue the scan.
At step 4, index = 3, we have [2, 3];
5, 4, [2, 3, 4];
At step 6, 5, and we need to pop out elements again, since arr[5] < top of the stack
In this way, we can get all answers for every elements in a single scan!
The take-home message here is:
With a stack, we can get the number of the elements larger than every element on its right side continuously in one single scan!
Similarly, if we change the scanning direction, we can get the number of the elements larger than every element on its left side continuously in one scan as well.
After having these two values, we can calculate the number of sub-arrays with the current element as the minimum.
If the larger elements on the right side continuously is fr[i] and on the left side continuously is fl[i], then there are (fr[i] + 1) * (fl[i] + 1) sub-arrays with arr[i] as the minimum.
One corner case is when the array have elements with the same values. For example, the array is [5, 5, 5]. In this case, we can use a tiny trick: on the right side, we can calculate the number of elements no-smaller than the current element continuously; on the left side, we just calculate the number of elements strictly larger than the current element continuously.
For the [5, 5, 5] array, the fr array is [2, 1, 0], the fl array is [0, 0, 0].
So the number of the subarray with arr[0] as the minimum is: (2+1)*(0+1) = 3;
So the number of the subarray with arr[1] as the minimum is: (1+1)*(0+1) = 2;
So the number of the subarray with arr[2] as the minimum is: (0+1)*(0+1) = 1;
Similarly, we can count the number of the subarray with arr[i] as the maximum in O(N) as well (with a monotonically decreasing stack).
Once we figure out the frequency of the maximum elements and minimum elements, we can calculate the difference of all of them. (The order does not matter. Or we do not need to figure out the maximum and minimum of each subarray).
See the code below:
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
long long res = 0;
int n = nums.size();
stack<int> sk1;
vector<int> dp1(n, 0), dp2(n, 0), dp3(n, 0), dp4(n, 0);
for(int i=0; i<n; ++i) {
while(sk1.size() && nums[sk1.top()] > nums[i]) {
int id = sk1.top();
sk1.pop();
dp1[id] = i - id;
}
sk1.push(i);
}
while(sk1.size()) {
int id = sk1.top();
sk1.pop();
dp1[id] = n - id;
}
for(int i=n-1; i>=0; --i) {
while(sk1.size() && nums[sk1.top()] >= nums[i]) {
int id = sk1.top();
sk1.pop();
dp2[id] = id - i;
}
sk1.push(i);
}
while(sk1.size()) {
int id = sk1.top();
sk1.pop();
dp2[id] = id + 1;
}
for(int i=0; i<n; ++i) {
while(sk1.size() && nums[sk1.top()] < nums[i]) {
int id = sk1.top();
sk1.pop();
dp3[id] = i - id;
}
sk1.push(i);
}
while(sk1.size()) {
int id = sk1.top();
sk1.pop();
dp3[id] = n - id;
}
for(int i=n-1; i>=0; --i) {
while(sk1.size() && nums[sk1.top()] <= nums[i]) {
int id = sk1.top();
sk1.pop();
dp4[id] = id - i;
}
sk1.push(i);
}
while(sk1.size()) {
int id = sk1.top();
sk1.pop();
dp4[id] = id + 1;
}
for(int i=0; i<n; ++i) {
// cout<<dp1[i]<<" "<<dp2[i]<<" "<<dp3[i]<<" "<<dp4[i]<<endl;
res += (long)nums[i] * ((dp3[i]) * (dp4[i]) - (dp1[i]) * (dp2[i]));
}
return res;
}
};We can make the code much more concise.
With a monotonically non-decreasing stack, when we pop out one element, we can calculate the number of (strictly) larger elements on the left side continuously as well. To get this, we just need to compare the index popped out with the current top of the stack, or left boundary if stack if empty. (Why?)
See the code below:
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
long long res = 0, n = nums.size();
stack<int> sk;
for(int i=0; i<=n; ++i) {
while(sk.size() && (i==n || nums[sk.top()] > nums[i])) {
int id = sk.top();
sk.pop();
int fr = i - id;
int fl = sk.empty() ? id + 1 : id - sk.top();
res -= (long long)nums[id]*fr*fl;
}
if(i<n) sk.push(i);
}
for(int i=0; i<=n; ++i) {
while(sk.size() && (i==n || nums[sk.top()] < nums[i])) {
int id = sk.top();
sk.pop();
int fr = i - id;
int fl = sk.empty() ? id + 1 : id - sk.top();
res += (long long)nums[id]*fr*fl;
}
if(i<n) sk.push(i);
}
return res;
}
};Sunday, August 22, 2021
[Leetcode] 1980. Find Unique Binary String
1980. Find Unique Binary String
Given an array of strings nums containing n unique binary strings each of length n, return a binary string of length n that does not appear in nums. If there are multiple answers, you may return any of them.
Constraints:
n == nums.length
1 <= n <= 16
nums[i].length == n
nums[i] is either '0' or '1'.
Analysis:
In order to reduce the time complexity, we need to,
1. store the existing strings in a unordered_set, which makes the checking in O(1);
2. save the visited string, to avoid infinite loop;
Then we can start with the first string, and try to flip each char, until we can find a brand new string.
See the code below:
class Solution {
public:
string findDifferentBinaryString(vector<string>& nums) {
int n = nums.size();
unordered_set<string> st;
for(auto &a : nums) st.insert(a);
unordered_set<string> vis;
string res = nums[0];
while(st.count(res) > 0) {
for(int i=0; i<n; ++i) {
res[i] = res[i] ^ 1;
if(vis.count(res)) continue;
vis.insert(res);
if(st.count(res)) break;
return res;
}
}
return res;
}
};[Leetcode] 1981. Minimize the Difference Between Target and Chosen Elements
1981. Minimize the Difference Between Target and Chosen Elements
You are given an m x n integer matrix mat and an integer target.
Choose one integer from each row in the matrix such that the absolute difference between target and the sum of the chosen elements is minimized.
Return the minimum absolute difference.
The absolute difference between two numbers a and b is the absolute value of a - b.
Constraints:
m == mat.length
n == mat[i].length
1 <= m, n <= 70
1 <= mat[i][j] <= 70
1 <= target <= 800
Analysis:
Let look at the brute-force way: there are n^m combinations in total. If n == m == 70, this number could be as large as 70^70, which is too overwhelming...
We need to figure out some way with reduced complexity.
Bitset would be a good choice to this question. The key idea is to use the index of the bits representing the sums.
For example, if a bitset bt[80] = 1, meaning the bit at the index of 80 is 1, then there is a sum equal to 80.
Bitset has an important operation: bit shift.
When we need to add a number to many others sums, then bit shift would greatly reduce the time complexity: since one bit shift operation would shift all the bits in a bitset by only one operation! More details can be found here.
In this question, initially we can have a bitset to record all the elements in the first row: basically set the corresponding bits as 1.
Then move on to the next row.
For each number in the second row, we need to add it to all the possible sums stored in the bitset from the previous row. Bit shift can perfectly handle this. After performing this bit shift operation to each number in the row, we need to store all the possible sums into a new bitset, which is needed for the next row. An or (|) operation is good enough for this.
We just repeat this step row by row, to the last row.
After finishing all of this, all the possible sums are stored in the last bitset. We just need to check all the possible sums, to see which one gives the minimum abs(sum - target).
See the code below:
class Solution {
public:
int minimizeTheDifference(vector<vector<int>>& mat, int target) {
int m = mat.size(), n = mat.front().size(), cs = 40000, res = cs;
bitset<40000> bt;
for(int i=0; i<n; ++i) bt[mat[0][i]] = 1;
for(int i=1; i<m; ++i) {
bitset<40000> pre = bt, nxt;
for(int j=0; j<n; ++j) {
nxt |= pre << mat[i][j];
}
bt = nxt;
}
for(int i=0; i<cs; ++i) {
if(bt[i]) res = min(res, abs(i-target));
}
return res;
}
};This question can also be solved by dfs + memo.
memo[r][sum] means: the minimum abs(possible sums - target) starting with row number r and the starting sum value as sum.
The optimization lines and trim lines are needed, otherwise, it cannot pass the OJ.
See the code below:
class Solution {
public:
int minimizeTheDifference(vector<vector<int>>& mat, int target) {
int m = mat.size(), n = mat.front().size();
for(auto &a : mat) {
sort(a.begin(), a.end());
}
sort(mat.begin(), mat.end(), greater());
memset(memo, -1, sizeof(memo));
return dfs(mat, 0, 0, target);
}
private:
int memo[71][4901];
int dfs(vector<vector<int>>& ms, int r, int sum, int& target) {
if(r == ms.size()) {
return abs(sum - target);
}
if(memo[r][sum] != -1) return memo[r][sum];
int res = INT_MAX;
for(int i=0; i<ms[r].size(); ++i) {
if(sum + ms[r][i] > target && abs(sum + ms[r][i] - target >= res)) break;
res = min(res, dfs(ms, r+1, sum + ms[r][i], target));
}
return memo[r][sum] = res;
}
};
Sunday, September 13, 2020
Leetcode 312: Burst Balloons
https://leetcode.com/problems/burst-balloons/description/
class Solution {
public:
int maxCoins(vector<int>& nums) {
// insert 1 in the begin and end of nums
// i, j in the range of [1, n]
// dp[i][j] = max(nums[i-1]*nums[k]*nums[j+1] + dp[i][k-1] + dp[k+1][j])
int n = nums.size();
if(n==0) return 0;
nums.insert(nums.begin(), 1);
nums.push_back(1);
vector<vector<int>> dp(n+2, vector<int>(n+2, 0));
for(int i=1; i<n+1; ++i) dp[i][i] = nums[i-1]*nums[i]*nums[i+1];
for(int i=n; i>0; --i) {
for(int j=i+1; j<n+1; ++j) {
for(int k=i; k<=j; ++k) {
dp[i][j] = max(dp[i][j], nums[i-1]*nums[k]*nums[j+1] + dp[i][k-1] + dp[k+1][j]);
}
}
}
return dp[1][n];
}
};Leetcode 1584: Min Cost to Connect All Points
https://leetcode.com/problems/min-cost-to-connect-all-points/description/
class Solution {
public:
int minCostConnectPoints(vector<vector<int>>& points) {
int n = points.size(), res = 0;
vector<int> used(n, 0), mxs(n, INT_MAX);
mxs[0] = 0;
for(int i=0; i<n; ++i) {
// find the next node with the shortest distance
int id = 0, mm = INT_MAX;
for(int j=0; j<n; ++j) {
if(!used[j] && mxs[j] < mm) {
id = j;
mm = mxs[j];
}
}
used[id] = 1;
res += mm;
// update mxs (since a new element at id is added in, so just need to update the shortest dis to it)
for(int j=0; j<n; ++j) {
if(used[j]) continue;// if connected already, continue
int dis = abs(points[id][0] - points[j][0]) + abs(points[id][1] - points[j][1]);
if(dis < mxs[j]) mxs[j] = dis;
}
}
return res;
}
};class Solution {
public:
typedef pair<int, int> pi;
int minCostConnectPoints(vector<vector<int>>& points) {
int n = points.size(), res = 0;
priority_queue<pi, vector<pi>, greater<pi>> pq;
set<int> st;
st.insert(0);
for(int i=1; i<n; ++i) {
int dis = abs(points[0][0] - points[i][0]) + abs(points[0][1] - points[i][1]);
pq.push({dis, i});
}
while(st.size() < n) {
while(st.count(pq.top().second)) pq.pop();
if(pq.empty()) break;
auto t = pq.top();
int d = t.first, id = t.second;
res += d;
// cout<<res<<" "<<d<<endl;
st.insert(id);
for(int i=0; i<n; ++i) {
if(st.count(i)) continue;
int dis = abs(points[id][0] - points[i][0]) + abs(points[id][1] - points[i][1]);
pq.push({dis, i});
}
}
return res;
}
};Leetcode 1448: Count Good Nodes in Binary Tree
https://leetcode.com/problems/count-good-nodes-in-binary-tree/description/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int goodNodes(TreeNode* root) {
return !root ? 0 : dfs(root, root->val);
}
private:
int dfs(TreeNode* r, int val) {
return !r ? 0 : (r->val >= val ? 1 : 0) + dfs(r->left, max(r->val, val)) + dfs(r->right, max(r->val,val));
}
};Saturday, September 12, 2020
Leetcode 1559: Detect Cycles in 2D Grid
https://leetcode.com/problems/detect-cycles-in-2d-grid/description/
class Solution {
struct UF {
vector<int> ps, cts;
int num, mx;
UF(int n): ps(n, 0), cts(n, 1), num(n), mx(0) {
iota(ps.begin(), ps.end(), 0);
if(n>0) mx = 1;
}
int find(int x) {
if(ps[x] == x) return x;
return ps[x] = find(ps[x]);
}
void unite (int x, int y) {
int a = find(x), b = find(y);
if(a != b) {
ps[b] = a;
cts[a] += cts[b];
mx = max(mx, cts[a]);
--num;
}
}
};
public:
bool containsCycle(vector<vector<char>>& grid) {
if(!grid.size() || !grid.front().size()) return false;
int m = grid.size(), n = grid.front().size();
vector<int> dirs = {-1, 0, 1, 0, -1};
vector<vector<int>> ids(m, vector<int>(n, 0));
queue<pair<int, int>> q;
for(int i=0; i<m; ++i) {
for(int j=0; j<n; ++j) {
for(int k=0; k+1<dirs.size(); ++k) {
int a = i + dirs[k], b = j + dirs[k+1];
if(a<0 || a>=m || b<0 || b>=n || grid[a][b] != grid[i][j]) continue;
++ids[i][j];
}
if(ids[i][j] == 1) q.push({i, j});
}
}
while(q.size()) {
auto t = q.front();
q.pop();
int x = t.first, y = t.second;
--ids[x][y];
for(int k=0; k+1<dirs.size(); ++k) {
int a = x + dirs[k], b = y + dirs[k+1];
if(a<0 || a>=m || b<0 || b>=n) continue;
if(grid[a][b] == grid[x][y] && ids[a][b] > 0) --ids[a][b];
}
for(int k=0; k+1<dirs.size(); ++k) {
int a = x + dirs[k], b = y + dirs[k+1];
if(a<0 || a>=m || b<0 || b>=n || grid[a][b] != grid[x][y] || ids[a][b] != 1) continue;
q.push({a, b});
}
}
UF uf(m*n);
for(int i=0; i<m; ++i) {
for(int j=0; j<n; ++j) {
if(ids[i][j] < 2) continue;
int a = i-1, b = j-1;
// upper
if(a>=0 && grid[a][j] == grid[i][j] && ids[a][j] > 1) uf.unite(a*n+j, i*n+j);
// left
if(b>=0 && grid[i][b] == grid[i][j] && ids[i][b] > 1) uf.unite(i*n+b, i*n+j);
}
}
return uf.mx > 3;
}
};Leetcode 1585: Check If String Is Transformable With Substring Sort Operations
https://leetcode.com/problems/check-if-string-is-transformable-with-substring-sort-operations/description/
When the results from both directions are true, return true.
class Solution {
public:
bool isTransformable(string s, string t) {
string s1 = s, t1 = t;
// check ids of elements from largest to smallest;
for(char c='9'; c>='0'; --c) {
vector<int> ids1, ids2;
for(int i=0; i<s1.size(); ++i) {
if(s1[i] == c) ids1.push_back(i);
if(t1[i] == c) ids2.push_back(i);
}
if((int)ids1.size() != (int)ids2.size()) return false;
for(int i=0; i<ids1.size(); ++i) {
if(ids1[i] > ids2[i]) return false;
}
string s2 = "", t2 = "";
for(auto &a : s1) {
if(a < c) s2.push_back(a);
}
for(auto &a : t1) {
if(a < c) t2.push_back(a);
}
s1 = s2;
t1 = t2;
}
// check ids of elements from smallest to the largest;
s1 = s, t1 = t;
for(char c='0'; c<='9'; ++c) {
vector<int> ids1, ids2;
for(int i=0; i<s1.size(); ++i) {
if(s1[i] == c) ids1.push_back(i);
if(t1[i] == c) ids2.push_back(i);
}
if((int)ids1.size() != (int)ids2.size()) return false;
for(int i=0; i<ids1.size(); ++i) {
if(ids1[i] < ids2[i]) return false;
}
string s2 = "", t2 = "";
for(auto &a : s1) {
if(a > c) s2.push_back(a);
}
for(auto &a : t1) {
if(a > c) t2.push_back(a);
}
s1 = s2;
t1 = t2;
}
return true;
}
};Leetcode 650: 2 Keys Keyboard
https://leetcode.com/problems/2-keys-keyboard/description/
class Solution {
public:
int minSteps(int n) {
vector<int> dp(n+1, 0);
for(int i=2; i<=n; ++i) {
dp[i] = n;
for(int j=1; j*2<=i; ++j) {
if(i%j==0) dp[i] = min(dp[i], dp[j] + i/j);
}
}
return dp[n];
}
};Leetcode 651: 4 Keys Keyboard
Imagine you have a special keyboard with the following keys:
Key 1: (A): Print one 'A' on screen.
Key 2: (Ctrl-A): Select the whole screen.
Key 3: (Ctrl-C): Copy selection to buffer.
Key 4: (Ctrl-V): Print buffer on screen appending it after what has already been printed.
Now, you can only press the keyboard for N times (with the above four keys), find out the maximum numbers of 'A' you can print on screen.
Example 1:
Input: N = 3 Output: 3 Explanation: We can at most get 3 A's on screen by pressing following key sequence: A, A, A
Example 2:
Input: N = 7 Output: 9 Explanation: We can at most get 9 A's on screen by pressing following key sequence: A, A, A, Ctrl A, Ctrl C, Ctrl V, Ctrl V
Note:
- 1 <= N <= 50
- Answers will be in the range of 32-bit signed integer.
class Solution {
public:
/**
* @param N: an integer
* @return: return an integer
*/
int maxA(int N) {
// write your code here
vector<int> dp(N+1, 0);
dp[1] = 1;
dp[2] = 2;
for(int i=3; i<=N; ++i) {
for(int j=0; j<i; ++j) {
dp[i] = max(dp[i], dp[j] + i - j);
if(j+3<i) dp[i] = max(dp[i], dp[j]*(i-j-1));
}
}
return dp[N];
}
};Tuesday, September 8, 2020
Leetcode 1400: Construct K Palindrome Strings
https://leetcode.com/problems/construct-k-palindrome-strings/description/
class Solution {
public:
bool canConstruct(string s, int k) {
int n = s.size(), res = 0;
if(n<k) return false;
if(n==k) return true;
vector<int> ct(26, 0);
for(auto &a : s) ++ct[a-'a'];
for(auto &a : ct) {
if(a & 1) ++res;
}
return res <= k;
}
};Leetcode 1558: Minimum Numbers of Function Calls to Make Target Array
https://leetcode.com/problems/minimum-numbers-of-function-calls-to-make-target-array/description/
class Solution {
public:
int minOperations(vector<int>& nums) {
int res = 0;
bool largerThan0 = true, allEven = true;
while(largerThan0) {
largerThan0 = false;
allEven = true;
for(auto &a : nums) {
if(a>0) largerThan0 = true;
if(a&1) {
--a;
++res;
allEven = false;
}
}
if(largerThan0 && allEven) {
for(auto &a : nums) a /= 2;
++res;
largerThan0 = true;
}
}
return res;
}
};Leetcode 358: Rearrange String K Distance Apart
https://leetcode.com/problems/find-latest-group-of-size-m/description/
class Solution {
public:
string rearrangeString(string str, int k) {
if (k == 0) return str;
string res;
int len = (int)str.size(), mx = 0, rep = 0;
unordered_map<char, int> m;
priority_queue<pair<int, char>> q;
for (auto a : str) ++m[a];
for (auto it = m.begin(); it != m.end(); ++it) {
q.push({it->second, it->first});
// find the maximum counting, and the numer of letters having this
if (it->first > mx) {
mx = it->first;
rep = 1;
} else if (it->first == mx) {
++rep;
}
}
// if need more letters than itself, then cannot construct an valid one
if((m-1)*k + rep > len) return "";
while (!q.empty()) {
vector<pair<int, int>> v;
int cnt = min(k, len);
for (int i = 0; i < cnt; ++i) {
if (q.empty()) return "";
auto t = q.top(); q.pop();
res.push_back(t.second);
if (--t.first > 0) v.push_back(t);
--len;
}
for (auto a : v) q.push(a);
}
return res;
}
};Leetcode 1542: Find Longest Awesome Substring
https://leetcode.com/problems/find-longest-awesome-substring/description/
class Solution {
public:
int longestAwesome(string s) {
int n = s.size(), res = 0, mask = 0;
vector<int> dp(1<<10, -2);
dp[0] = -1;
for(int i=0; i<n; ++i) {
mask ^= 1<<(s[i] - '0');
if(dp[mask] != -2) res = max(res, i - dp[mask]);
else dp[mask] = i;// memorize the first position
for(int j=0; j<10; ++j) {// check one letter with odd count
int t = mask ^ (1<<j);
if(dp[t] != -2) res = max(res, i - dp[t]);
}
}
return res;
}
};Monday, September 7, 2020
Leetcode 730: Count Different Palindromic Subsequences
https://leetcode.com/problems/count-different-palindromic-subsequences/description/
class Solution {
public:
int countPalindromicSubsequences(string S) {
int n = S.size(), mod = 1e9+7;
// vector<vector<vector<long>>> dp(n, vector<vector<long>>(n, vector<long>(4, 0)));
for(int i=0; i<n; ++i) dp[i][i][S[i]-'a'] = 1;
for(int i=n-2; i>=0; --i) {
for(int j=i+1; j<n; ++j) {
for(int k=0; k<4; ++k) {
if(S[i] != S[j] || S[i] != (k + 'a')) {
dp[i][j][k] = (dp[i][j][k] + dp[i+1][j][k] + dp[i][j-1][k] - dp[i+1][j-1][k] + mod)%mod;
}
else {
dp[i][j][k] = (dp[i][j][k] + 2)%mod;
for(int t=0; t<4; ++t) {
dp[i][j][k] = (dp[i][j][k] + dp[i+1][j-1][t])%mod;
}
}
}
}
}
long res = 0;
for(int i=0; i<4; ++i) {
res = (res + dp[0][n-1][i])%mod;
}
return res;
}
private:
int dp[1000][1000][4];
};class Solution {
public:
int countPalindromicSubsequences(string S) {
int n = S.size(), mod = 1e9+7;
vector<vector<long>> dp(n+1, vector<long>(n, 0));
for(int i=0; i<n; ++i) dp[i][i] = 1;
for(int i=n-2; i>=0; --i) {
for(int j=i+1; j<n; ++j) {
if(S[i] != S[j]) dp[i][j] = (dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1] + mod)%mod;
else {
int left = i + 1, right = j-1;
while(left<n && S[left] != S[i]) ++left;
while(right>=0 && S[right] != S[i]) --right;
if(left>right) dp[i][j] = (dp[i+1][j-1]*2 + 2)%mod;
else if(left == right) dp[i][j] = (dp[i+1][j-1]*2 + 1)%mod;
else dp[i][j] = (dp[i+1][j-1]*2 - dp[left+1][right-1] + mod)%mod;
}
}
}
return dp[0][n-1];
}
};Leetcode 1419: Minimum Number of Frogs Croaking
https://leetcode.com/problems/minimum-number-of-frogs-croaking/description/
class Solution {
public:
int minNumberOfFrogs(string croakOfFrogs) {
int n = croakOfFrogs.size(), res = 0, rm = 0;
unordered_map<char, int> mp;
for(auto &c : croakOfFrogs) {
if(c=='c') {
if(rm>0) --rm;
else ++res;
++mp['c'];
} else if(c == 'r') {
if(!check(mp, 'c', 'r')) return -1;
} else if(c == 'o') {
if(!check(mp, 'r', 'o')) return -1;
} else if(c == 'a') {
if(!check(mp, 'o', 'a')) return -1;
} else if(c == 'k') {
if(!mp.count('a') || mp['a'] == 0) return -1;
--mp['a'];
++rm;
} else {
return -1;
}
}
for(auto &a : mp) {
if(a.second > 0) return -1;
}
return res;
}
private:
bool check(unordered_map<char, int>& mp, char a, char b) {
if(!mp.count(a) || mp[a] == 0) return false;
--mp[a];
++mp[b];
return true;
}
};Sunday, September 6, 2020
Leetcode 1371: Find the Longest Substring Containing Vowels in Even Counts
https://leetcode.com/problems/find-the-longest-substring-containing-vowels-in-even-counts/description/
class Solution {
public:
int findTheLongestSubstring(string s) {
int res = 0, n = s.size(), mask = 0;
vector<int> dp(1<<5, s.size());// only 5 letters, so 5 bits
dp[0] = -1;// special case for boundary condition
for(int i=0; i<n; ++i) {
char a = s[i];
if(a=='a') mask ^= 1<<0;
else if(a=='e') mask ^= 1<<1;
else if(a=='i') mask ^= 1<<2;
else if(a=='o') mask ^= 1<<3;
else if(a=='u') mask ^= 1<<4;
res = max(res, i - dp[mask]);
dp[mask] = min(i, dp[mask]);// record the first position
}
return res;
}
};