Longest subsequence of S that is balanced - algorithm

Given question:
A string of parentheses is said to be
balanced if the left- and right-parentheses in the string can be paired off properly. For example, the strings "(())" and "()()" are both balanced, while the string "(()(" is not
balanced.
Given a string S of length n consisting of parentheses, suppose you want to find the longest subsequence of S that is balanced. Using dynamic programming, design an algorithm that finds the longest balanced subsequence of S in O(n^3) time.
My approach:
Suppose given string: S[1 2 ... n]
A valid sub-sequence can end at S[i] iff S[i] == ')' i.e. S[i] is a closing brace and there exists at least one unused opening brace previous to S[i]. which could be implemented in O(N).
#include<iostream>
using namespace std;
int main(){
string s;
cin >> s;
int n = s.length(), o_count = 0, len = 0;
for(int i=0; i<n; ++i){
if(s[i] == '('){
++o_count;
continue;
}
else if(s[i] == ')' && o_count > 0){
++len;
--o_count;
}
}
cout << len << endl;
return 0;
}
I tried a couple of test cases and they seem to be working fine. Am I missing something here? If not, then how can I also design an O(n^3) Dynamic Programming solution for this problem?
This is the definition of subsequence that I'm using.
Thanks!

For O(n^3) DP this should work I think:
dp[i, j] = longest balanced subsequence in [i .. j]
dp[i, i] = 0
dp[i, i + 1] = 2 if [i, i + 1] == "()", 0 otherwise
dp[i, j] = max{dp[i, k] + dp[k + 1, j] : j > i + 1} in general
This can be implemented similar to how optimal matrix chain multiplication is.
Your algorithm also seems correct to me, see for example this problem:
http://xorswap.com/questions/107-implement-a-function-to-balance-parentheses-in-a-string-using-the-minimum-nu
Where the solutions are basically the same as yours.
You are only ignoring the extra brackets, so I don't see why it wouldn't work.

Here's a O(n^2) time and space DP solution in Java:
public int findLongestBalancedSubsequence(String seq, int n) {
int[][] lengths = new int[n][n];
for (int l = 1; l < n; l++) {
for (int i = 0; i < n - l; i++) {
int j = i + l;
// Ends are balanced.
if (seq.charAt(i) == '(' && seq.charAt(j) == ')') {
// lengths[i, j] = max(lengths[i + 1, j - 1] + 2, lengths[i + 1, j] +
// lengths[i, j - 1] - lengths[i + 1, j - 1])
if (lengths[i + 1][j - 1] + 2 > lengths[i + 1][j] +
lengths[i][j - 1] - lengths[i + 1][j - 1])
lengths[i][j] = lengths[i + 1][j - 1] + 2;
else
lengths[i][j] = lengths[i + 1][j] +
lengths[i][j - 1] - lengths[i + 1][j - 1];
// Ends are not balanced.
} else {
// lengths[i, j] = max(lengths[i + 1, j], lengths[i, j - 1])
if (lengths[i + 1][j] > lengths[i][j - 1])
lengths[i][j] = lengths[i + 1][j];
else
lengths[i][j] = lengths[i][j - 1];
}
}
}
return lengths[0][n - 1];
}

Related

Find index j in a simple convex vector

A vector V [0, n − 1] is a simple convex vector if a index j exists such that V [0] = V[1] = V[2] = ··· = V[j] and for each i > j, V[i] < V[i + 1]. Can you write pseudocode to solve this in O(log(n)) time complexity?
That's my solution, but I don't know if it works. I think it should but assuming for each i >= j, V[i] < V[i + 1]. I don't know if I have a wrong definition.
convex(A, l, r) {
m = floor((l + r) / 2);
if (A[m] == A[0] && A[m] != A[m + 1] {
return m;
}
if (A[m] == A[0]) {
return convex(A, m + 1, r);
}
else {
return convex(A, l, m - 1);
}
}

Knuth's Optimal Binary Search tree in O(n^2)

I am trying to implement Knuth's optimal binary search tree which can run in O(n^2) time. I have the code which is running in O(n^3).
float P[N + 1] = {0, .13, .12, .15, .05, .12, .10, .08, .09, .03, .13};
float sum[N + 1] = {0, .13, .25, .40, .45, .57, .67, .75, .84, .87, 1.00};
float M[N + 1][N + 1];
int root[N + 1][N + 1];
int s, i, j;
float temp;
for (s = 0; s <= N; s++){
for (i = 0; i <= N; i++){
M[s][i] = 0;
root[s][i] = 0;
}
}
for (s = 2; s <= N; s++){
for (i = 1; i <= N - s + 1; i++){
M[s][i] = N;
for (j = i; j <= i + s - 1; j++){
temp = M[j - i][i] + M[i + s - j - 1][j + 1]+ sum[i + s - 1] - sum[i - 1] - P[j];
if (M[s][i] > temp){
M[s][i] = temp;
root[s][i] = j;
}
}
}
}
M is the array of costs. P is the probability of each node. I get some ideas from: Dynamic Programming: Why Knuth's improvement to Optimal Binary Search Tree O(n^2)?. In my case, I tried to modify the third loop from for (j = i; j <= i + s - 1; j++) to for (j = root[s+1][i]; j <= root[s][i-1]; j++). But it doesn't work. Could someone give me some clue on this problem?
You're supposed to be computing the costs of the optimal subtrees in non-decreasing order by size, so when you're filling in M[s][i] --- the minimum cost of a subtree of size s whose leftmost key has index i --- you haven't filled in M[s+1][i] or root[s+1][i] yet.
Cheers,
Travis
PS "j <= root[s][i-1]" isn't quite right either.

Optimize: Divide an array into continuous subsequences of length no greater than k such that sum of maximum value of each subsequence is minimum

Optimize O(n^2) algorithm to O(n log n).
Problem Statement
Given array A of n positive integers. Divide the array into continuous subsequences of length no greater than k such that sum of maximum value of each subsequence is minimum. Here's an example.
If n = 8 and k = 5 and elements of the array are 1 4 1 3 4 7 2 2, best solution is 1 | 4 1 3 4 7 | 2 2. The sum would be max{1} + max{4, 1, 3, 4, 7} + max{2, 2} = 1 + 7 + 2 = 10.
O(n^2) solution
Let dp[i] be the minimum sum as in problem statement for subproblem array A[0] ... A[i]. dp[0] = A[0] and, for 0 < i < n (dp[-1] = 0),
// A, n, k, - defined
// dp - all initialized to INF
dp[0] = A[0];
for (auto i = 1; i < n; i++) {
auto max = -INF;
for (auto j = i; j >= 0 && j >= i-k+1; j--) {
if (A[j] > max)
max = A[j];
auto sum = max + (j > 0 ? dp[j-1] : 0);
if (sum < dp[i])
dp[i] = sum;
}
}
// answer: dp[n-1]
O(n log n) ?
The problem author claimed that it was possible to solve this in O(n log n) time, and there are some people who were able to pass the test cases. How can this be optimized?
NOTE: I'm gonna change slightly your dynamic programming relation, so that there is no special case if j = 0. Now dp[j] is the answer for the first j termsA[0], ..., A[j-1] and:
dp[i] = min(dp[j] + max(A[j], ..., A[i-1]), i-k <= j < i)
The answer of the problem is now dp[n].
Notice that if j < i and dp[j] >= dp[i], you won't need dp[j] in the following transitions, because max(A[j], ..., A[l]) >= max(A[i], ..., A[l]) (so it will be always better to cut at i instead of j.
Furthermore let C[j] = max(A[j+1], ..., A[l]) (where l is our current index in the dynamic programming step, ie. i in your C++ program).
Then you can keep in memory some set of indices x1 < ... < xm (the "interesting" indices for the transitions of your dynamic programming relation) such that: dp[x1] < ... < dp[xm] (1). Then automatically C[x1] >= ... >= C[xm] (2).
To store {x1, ..., xm}, we need some data structure that supports the following operations:
Pop back (when we move from i to i+1, we must say that i-k is now unreachable) or front (cf. insertion).
Push front x (when we have computed dp[i], we insert it while preserving (1), by deleting the corresponding elements).
Compute min(dp[xj] + C[xj], 1 <= j <= m).
Thus some queue to store x1, ..., xk together with a set to store all dp[xi] + C[xi] will be enough.
How do we both preserve (1) and update C when we insert an element i?
Before computing dp[i], we update C with A[i-1]. For that we find the smallest element xj in the set x s.t. C[xj] <= A[i-1]. Then (1) and (2) imply dp[j'] + C[j'] >= dp[j] + C[j] for all j' >= j, so we update C[xj] to A[i-1] and we delete x(j+1), ..., xm from the set (*).
When we insert dp[i], we just delete all elements s.t. dp[j] >= dp[i] by popping front.
When we remove i-k, it may be possible that some element destroyed in (*) is now becoming best. So if necessary we update C and insert the last element.
Complexity : O(n log n) (there could be at most 2n insertions in the set).
This code sums up the main ideas:
template<class T> void relaxmax(T& r, T v) { r = max(r, v); }
vector<int> dp(n + 1);
vector<int> C(n + 1, -INF);
vector<int> q(n + 1);
vector<int> ne(n + 1, -INF);
int qback = 0, qfront = 0;
auto cmp = [&](const int& x, const int& y) {
int vx = dp[x] + C[x], vy = dp[y] + C[y];
return vx != vy ? vx < vy : x < y;
};
set<int, decltype(cmp)> s(cmp);
dp[0] = 0;
s.insert(0);
q[qfront++] = 0;
for (int i = 1; i <= n; ++i) {
C[i] = A[i - 1];
auto it_last = lower_bound(q.begin() + qback, q.begin() + qfront, i, [=](const int& x, const int& y) {
return C[x] > C[y];
});
for (auto it = it_last; it != q.begin() + qfront; ++it) {
s.erase(*it);
C[*it] = A[i - 1];
ne[*it] = i;
if (it == it_last) s.insert(*it);
}
dp[i] = dp[*s.begin()] + C[*s.begin()];
while (qback < qfront && dp[q[qfront]] >= dp[i]) {
s.erase(q[qfront]);
qfront--;
}
q[qfront++] = i;
C[i] = -INF;
s.insert(i);
if (q[qback] == i - k) {
s.erase(i - k);
if (qback + 1 != qfront && ne[q[qback]] > q[qback + 1]) {
s.erase(q[qback + 1]);
relaxmax(C[q[qback + 1]], C[i - k]);
s.insert(q[qback + 1]);
}
qback++;
}
}
// answer: dp[n]
This time I stress-tested it against your algorithm: see here.
Please let me know if it's still unclear.

How to determine the longest increasing sub-sequence using dynamic programming with joinable input integers

I read the article about
How to determine the longest increasing sub-sequence using dynamic programming
with this algorithm:
int maxLength = 1, bestEnd = 0;
DP[0] = 1;
prev[0] = -1;
for (int i = 1; i < N; i++)
{
DP[i] = 1;
prev[i] = -1;
for (int j = i - 1; j >= 0; j--)
if (DP[j] + 1 > DP[i] && array[j] < array[i])
{
DP[i] = DP[j] + 1;
prev[i] = j;
}
if (DP[i] > maxLength)
{
bestEnd = i;
maxLength = DP[i];
}
}
but i want to know how to solve this problem with this condition that we can take the arrays with joined integers.
For example: 1,5,3,1,5,6,7,8,1,2,9
we can have this set:1,3,5,6,7,8,12 for solution
that 12 is joint form 1 and 2
so conditions are:
The input array includes 1-9 numbers! and the integers can joined from few other integers.
Original problem
dp[i] = max(DP[j] + 1, a[j] < a[i])
Your problem
Let:
a[x,y] = a[x] + a[x + 1] + ... + a[y] (+ means concatenate)
So:
f[x,y] = max(DP[j] + 1, a[j] < a[x,y], j < x)
dp[i] = max(f[i,j], 0 <= j <= i) = max(
max(DP[j] + 1, a[j] < a[i], j < i) # f(i, i)
max(DP[j] + 1, a[j] < a[i-1, i], j < i - 1) # f(i-1, i)
...
)
If you still have some problems, please don't hesitate to leave a comment here.

Maximum span in two arrays with equal sum

This is programming puzzle. We have two arrays A and B. Both contains 0's and 1's only.
We have to two indices i, j such that
a[i] + a[i+1] + .... a[j] = b[i] + b[i+1] + ... b[j].
Also we have to maximize this difference between i and j. Looking for O(n) solution.
I found O(n^2) solution but not getting O(n).
Best solution is O(n)
First let c[i] = a[i] - b[i], then question become find i, j, which sum(c[i], c[i+1], ..., c[j]) = 0, and max j - i.
Second let d[0] = 0, d[i + 1] = d[i] + c[i], i >= 0, then question become find i, j, which d[j + 1] == d[i], and max j - i.
The value of d is in range [-n, n], so we can use following code to find the answer
answer = 0, answer_i = 0, answer_j = 0
sumHash[2n + 1] set to -1
for (x <- 0 to n) {
if (sumHash[d[x]] == -1) {
sumHash[d[x]] = x
} else {
y = sumHash[d[x]]
// find one answer (y, x), compare to current best
if (x - y > answer) {
answer = x - y
answer_i = y
answer_j = y
}
}
}
Here is an O(n) solution.
I use the fact that sum[i..j] = sum[j] - sum[i - 1].
I keep the leftmost position of each found sum.
int convertToPositiveIndex(int index) {
return index + N;
}
int mostLeft[2 * N + 1];
memset(mostLeft, -1, sizeof(mostLeft));
int bestLen = 0, bestStart = -1, bestEnd = -1;
int sumA = 0, sumB = 0;
for (int i = 0; i < N; i++) {
sumA += A[i];
sumB += B[i];
int diff = sumA - sumB;
int diffIndex = convertToPositiveIndex(diff);
if (mostLeft[diffIndex] != -1) {
//we have found the sequence mostLeft[diffIndex] + 1 ... i
//now just compare it with the best one found so far
int currentLen = i - mostLeft[diffIndex];
if (currentLen > bestLen) {
bestLen = currentLen;
bestStart = mostLeft[diffIndex] + 1;
bestEnd = i;
}
}
if (mostLeft[diffIndex] == -1) {
mostLeft[diffIndex] = i;
}
}
cout << bestStart << " " << bestEnd << " " << bestLen << endl;
P.S. mostLeft array is 2 * N + 1, because of the negatives.
This is a fairly straightforward O(N) solution:
let sa = [s1, s2, s3.. sn] where si = sum(a[0:i]) and similar for sb
then sum(a[i:j]) = sa[j]-sa[i]
and sum(b[i:j]) = sb[j] - sb[i]
Note that because the sums only increase by 1 each time, we know 0 <= sb[N], sa[N] <=N
difference_array = [d1, d2, .. dn] where di = sb[i] - sa[i] <= N
note if di = dj, then sb[i] - sa[i] = sb[j] - sa[j] which means they have the same sum (rearrange to get sum(b[i:j]) and sum(a[i:j]) from above).
Now for each difference we need its max position occurrence and min position occurrence
Now for each difference di, the difference between max - min, is an i-j section of equal sum. Find the maximum max-min value and you're done.
sample code that should work:
a = []
b = []
sa = [0]
sb = [0]
for i in a:
sa.append(sa[-1] + i)
for i in b:
sb.append(sb[-1] + i)
diff = [sai-sbi for sai, sbi in zip(sa, sb)]
min_diff_pos = {}
max_diff_pos = {}
for pos, d in enumerate(diff):
if d in min_diff_pos:
max_diff_pos[d] = pos
else:
min_diff_pos[d] = pos
ans = min(max_diff_pos[d] - min_diff_pos[d] for d in diff)
Basically, my solution goes like this.
Take a variable to take care of the difference since the beginning.
int current = 0;
for index from 0 to length
if a[i] == 0 && b[i] == 1
current--;
else if a[i] == 1 && b[i] == 0
current++;
else
// nothing;
Find the positions where the variable has the same value, which indicates that there are equal 1s and 0s in between.
Pseudo Code:
Here is my primary solution:
int length = min (a.length, b.length);
int start[] = {-1 ... -1}; // from -length to length
start[0] = -1;
int count[] = {0 ... 0}; // from -length to length
int current = 0;
for (int i = 0; i < length; i++) {
if (a[i] == 0 && b[i] == 1)
current--;
else if (a[i] == 1 && b[i] == 0)
current++;
else
; // nothing
if (start[current] == -1) // index can go negative here, take care
start[current] = current;
else
count[current] = i - start[current];
}
return max_in(count[]);

Resources