Longest Common Increasing Subsequence Dynamic Programming - c++

I'm working on finding a solution to the longest common increasing sub sequence problem. Here's a link if you're not familiar with it. LCIS
The problem can basically be reduced to two different problems. 'Longest common subsequence' and 'Longest increasing subsequence'. Here's the recursive solution to Longest common subsequence:
LCS(S,n,T,m)
{
if (n==0 || m==0) return 0;
if (S[n] == T[m]) result = 1 + LCS(S,n-1,T,m-1); // no harm in matching up
else result = max( LCS(S,n-1,T,m), LCS(S,n,T,m-1) );
return result;
}
Based on that and the general recursive formula found here I've been trying to implement the algorithm so I can use dynamic programming.
int lcis(int S[4], int n, int T[4], int m, int prev)
{
int result;
if (n == 0 || m == 0)
return 1;
if (S[n] == T[m] && S[n] > S[prev]){
result = myMax(1 + lcis(S, n-1, T, m-1, n), lcis(S, n-1, T, m, prev),
lcis(S, n, T, m-1, prev)) ;
}
else
result = max(lcis(S,n-1,T,m, prev), lcis(S,n,T,m-1, prev));
return result;
}
Obviously this does not give the correct solution. Any help would be appreciated.
For example, if I give it the two sequences {1, 2, 4, 5} and {12, 1, 2, 4} I get an output of 2. The correct output here would be 3, for the sub sequence {1,2,4}
EDIT:
Here is some revised code, after suggestions from below. Still not 100% correct. But closer. Note I am now using vectors, but this shouldn't change anything.
int lcis(vector<int> S, int n, vector<int> T, int m, int size)
{
int result;
if (n < 0 || m < 0)
return 0;
if (S[n] == T[m] && (n == size - 1 || S[n] < S[n + 1] )){
result = myMax(1 + lcis(S, n - 1, T, m - 1, size), lcis(S, n - 1, T, m, size),
lcis(S, n, T, m - 1, size));
}
else
result = max(lcis(S, n-1, T, m, size), lcis(S, n, T, m-1, size));
return result;
}

Remember that you are going backward through the array. So this test
S[n] > S[prev]
Should be the other way around:
S[n] < S[prev]
I am not sure why you need prev at all, as it should always be n+1, so maybe use
if (S[n] == T[m] && n < 3 && S[n] < S[n+1])
If you need to make it work for any size, then either pass the size in, or just a flag to say don't check n+1
Edit:
My mistake - you want to be going through the first if case when n == 3 (or size), as you are at the start of a (potentially) increasing subsequence.
The if test should be
if (S[n] == T[m] && (n == 3 || S[n] < S[n+1]))
Note that this if test:
if (n == 0 || m == 0)
return 1;
is ignoring the first element of either sequence (and assuming it is at the end of an increasing subsequence). What is needed is to stop the recursion when you have gone before the start of either sequence. You also know that when you have gone before the start of the sequence, you can't possibly be in a subsequence, so you can return 0 for the length of the subsequence. So the test should be
if (n < 0 || m < 0)
return 0;

Related

How to get the correct array dimensions to store all results for my DP memoization for N choose K problem?

I'm learning data-structures and algorithms, I can solve it recursively and I understand I have to add to a memo table to save repetitions, I'm having trouble doing it, some input would be very helpful. If you can also implement the set/ map solution, that would be great too, but I'm primarily looking for array solution for future reference. I think it might be because while passing the array, it's not passed by reference, because c++ doesn't do that, would a vector be a better choice? I tried, but wasn't able to make it work also. And array solution in Java which does pass arrays by reference is also not working, so I'm doing something wrong.
Code:
long long int combinMemo(int n, int k, int memo[]) {
if (k == 0) return 1;
if (n == k) return 1;
if(n < k || (n <= 0)) return 0;
if(memo[k] == 0) {
return memo[k] = (combinMemo(n - 1, k - 1, memo)) + combinMemo(n - 1, k, memo); //+ combinMemo(n - 1, k, memo));
} else {
return memo[k];
}
}
long long int combinMemoWrap(int n, int k) {
int memo[k + 1];
for(int i = 0; i < k + 1; i++) {
memo[i] = 0;
}
return combinMemo(n, k, memo);
}

Integer is set to -858990820 in program using a recursive algorithm - I kind of get it why, not sure though

My program should build a number (in the k parameter) which is obtained with each of the even digits in the a[] array. n is the number of elements of the array.
void F (int n, int a[], int &k) {
if (n == 0)
{
if (a[0] % 2 == 0)
{
k = a[0];
}
else
{
k = -1;
}
}
else
{
F(n - 1, a, k);
if (a[n] % 2 == 0)
{
k = k * 10 + a[n];
}
}
}
BTW I'm not that good at recursion. It might not be an okay algorithm. I'm trying to get better.
The problem is as follows: if I cout k, it shows me -858990820.
If I use a cout k in the else condition to see what's happening, the result is fine UNTIL some point it suddenly turns into that negative number.
[
I think that number appears because of the array. It goes out of bounds at some point but I don't get when.
Calling F(n-1, a, k) at the beginning of the else condition should have resolved this. (because the array stops at n-1 and if I call that in the else condition as the first thing in there it should not ever reach n).
Can you explain to me what's happening and help me fix it?
////edit:
I forgot to mention: if there is no even number, k equals -1.
You have a problem here:
else
{
F(n - 1, a, k);
if (a[n] % 2 == 0)
{
k = k * 10 + a[n];
}
}
If your initial call to this function is:
int a[10];
F(100, a, &k);
Then accessing a[n] is going to access a[10], which is beyond the allocated bounds of the array. Remember that in C, array indexes are 0 through n; in this case, 9 is the index of the last item.

Perfect Square in Leetcode

I am having trouble understanding one of a Leetcode Problem.
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.
For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
Solution:
int numSquares(int n) {
static vector<int> dp {0};
while (dp.size() <= n) {
int m = dp.size(), squares = INT_MAX;
for (int i=1; i*i<=m; ++i)
squares = min(squares, dp[m-i*i] + 1);
dp.push_back(squares);
}
return dp[n];
}
I really dont understand what is going on with min(squares,dp[m-i*i]+1). Can you please explain?
thx.
I had a hard time with this too. Let's take the example number n=13.
First thing to observe is that: 1^2 =1, 2^2=4, 3^2=9, 4^2=16
So 13 can't be composed of anything greater than
3^2. Generically speaking, n can only be composed of numbers 1 to sqrt(n)
So we are left with some combination of the square of the following numbers: 1, 2, or 3.
Next thing we want to do is come up with the recursive formula. This took me a long time to understand. But we basically want to dwindle down to work with a smaller n (that's the whole point of recursion). We do that by subtracting our candidate perfect squares from n. For example:
If we try 3, then dp(13)=dp(13-3^2)+1=dp(4)+1.
The +1 is incrementing the count by 1 and is from the the fact that we already took off a perfect square from 13, which was the 3^2. Each +1 is a perfect square that we took off.
If we try 2, then dp(13)=13-2^2=dp(9)+1
If we try 1, then dp(13)=13-1^2=dp(12)+1
So we are left with comparing which is the smallest out of dp(4), dp(9), and dp(12). Hence the min.
The solution, which you have mentioned, is the bottom-up version of the algorithm. In order to understand the algorithm better, I would advice to look at the top-down version of the solution.
Let's look closer at the recurrence relation for the calculation of the minimal amount of the perfect squares, contained inside the number N. For given N and any arbitrary number x (which is the candidate for being considered as the member of the shortest sequence of numbers, whose perfect squares sums-up to N):
f(N, x) = 0 , if N = 0 ;
f(N, x) = min( f(N, x + 1), f(N - x^2, 1) ) , if N >= x^2 ;
f(N, x) = +infinity , otherwise ;
solution(N) = f(N, 1)
Now, having in mind the considered recurrence, we can construct the top-down solution (I will implement it in Java):
int solve(int n) {
return solve(n, 1);
}
int solve(int n, int curr) {
if (n == 0) {
return 0;
}
if ((curr * curr) > n) {
return POSITIVE_INFINITY;
}
// if curr belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
int inclusive = solve(n - (curr * curr), 1) + 1;
// otherwise:
int exclusive = solve(n, curr + 1);
return Math.min(exclusive, inclusive);
}
The runtime complexity of the given solution is exponential.
However, we can notice that there are only [1..n] possible values of n and [1..sqrt(n)] values of curr. Which, implies, that there are only n * sqrt(n) combinations of different values of arguments of the function solve. Hence, we can create the memoization table and reduce the complexity of the top-down solution:
int solve(int n) {
// initialization of the memoization table
int[][] memoized = new int[n + 1][(int) (Math.sqrt(n) + 1)];
for (int[] row : memoized) {
Arrays.fill(row, NOT_INITIALIZED);
}
return solve(n, 1, memoized);
}
int solve(int n, int curr, int[][] memoized) {
if (n == 0) {
return 0;
}
if ((curr * curr) > n) {
return POSITIVE_INFINITY;
}
if (memoized[n][curr] != NOT_INITIALIZED) {
// the sub-problem has been already solved
return memoized[n][curr];
}
int exclusive = solve(n, curr + 1, memoized);
int inclusive = solve(n - (curr * curr), 1, memoized) + 1;
memoized[n][curr] = Math.min(exclusive, inclusive);
return memoized[n][curr];
}
Given solution has the runtime complexity O(N * sqrt(N)).
However, it is possible to reduce the runtime complexity to O(N).
As far as the recurrence relation for f(N, x) depends only on f(N, x + 1) and f(N - x^2, 1) - it means, that the relation can be equivalently transformed to the loop form:
f(0) = 0
f(N) = min( f(N - x^2) + 1 ) , across the all x, such that x^2 <= N
In this case we have to memoize the f(N) only for N different values of its argument.
Hence, below presented the O(N) top-down solution:
int solve_top_down_2(int n) {
int[] memoized = new int[n + 1];
Arrays.fill(memoized, NOT_INITIALIZED);
return solve_top_down_2(n, memoized);
}
int solve_top_down_2(int n, int[] memoized) {
if (n == 0) {
return 0;
}
if (memoized[n] != NOT_INITIALIZED) {
return memoized[n];
}
// if 1 belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
int result = solve_top_down_2(n - (1 * 1)) + 1;
for (int curr = 2; (curr * curr) <= n; curr++) {
// check, whether some other number belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
result = Math.min(result, solve_top_down_2(n - (curr * curr)) + 1);
}
memoized[n] = result;
return result;
}
Finally, the presented top-down solution can be easily transformed to the bottom-up solution:
int solve_bottom_up(int n) {
int[] memoized = new int[n + 1];
for (int i = 1; i <= n; i++) {
memoized[i] = memoized[i - (1 * 1)] + 1;
for (int curr = 2; (curr * curr) <= i; curr++) {
memoized[i] = Math.min(memoized[i], memoized[i - (curr * curr)] + 1);
}
}
return memoized[n];
}
The clarification to your confusion lies in the question itself. The structure dp holds the least number of squares that sum up to the index position of dp.
E.g., squares would return 3 when n=9, but least possible is 1, which is what dp[m- i*i] + 1 would return.

Meximum Subarray Sum using Divide-And-Conquer

Working on an implementation of finding the Greatest Contiguous Sum of a sequence using the Divide and Conquer method as seen here.
My return value is often incorrect.
For example:
{5, 3} returns 5 instead of 8.
{-5, 3} returns 0 instead of 3.
{ 6, -5, 7 } returns 7 instead of 8.
Other notes:
decrementing or incrementing AT the first or last iterators throws an exception, saying that I either can't increment, decrement, or dereference at that point. There's a bug somewhere in GCSMid, I think, but I haven't been able to solve it.
this implementation uses random-access iterators, signified as RAIter
//function max- finds greatest number given 3 size_ts
size_t max(size_t a, size_t b, size_t c)
{
if (a >= b && a >= c)
{
return a;
}
else if (b >= a && b >= c)
{
return b;
}
else
{
return c;
}
}
//function gcsMid
//main algorithm to find subsequence if it spans across the center line
template<typename RAIter>
size_t gcsMid(RAIter first, RAIter center, RAIter last)
{
size_t sum = 0;
size_t leftSum = 0;
size_t rightSum = 0;
//to the left of center
for (RAIter i = center; i > first; i--)
{
sum += *i;
if(sum > leftSum)
{
leftSum = sum;
}
}
//to right of center
sum = 0;
for (RAIter j = (center + 1); j < last; j++)
{
sum += *j;
if (sum > rightSum)
{
rightSum = sum;
}
}
//return the sums from mid
return leftSum + rightSum;
}
//main function to call
template<typename RAIter>
int gcs(RAIter first, RAIter last)
{
size_t size = distance(first, last);
//base case is when the subarray only has 1 element. when first == last
if (first == last || size == 1)
{
if (size < 1)
{
return 0;
}
if (*first < 0)
{
return 0;
}
return *first;
}
//middle point
RAIter center = first + (size/2);
//return max of leftsum, rightsum, and midsum
return max(gcs(first, center),
gcs(center + 1, last),
gcsMid(first, center, last));
}
You have two problems with your code:
A. This loop:
for (RAIter i = center; i > first; i--)
does not include first in the loop. The reference algorithm does. You can't just use >= as the reference algorithm does as it doesn't work for iterators. Either add an extra bit of code to check first at the end, or change your loop so it somehow includes first (maybe a do while loop would suit better).
B. These definitions:
size_t sum = 0;
size_t leftSum = 0;
size_t rightSum = 0;
should not be size_t as size_t is unsigned. This means that when the sum goes negative, checks like if(sum > leftSum) no longer work, as the negative value (which underflows) is bigger than the positive value.
Change them to int.
The best way to find these kinds of errors is to run the code through a debugger. You can then step through each line of your code and see what the variable values are. This makes it easy to spot things like negative numbers becoming large positive numbers as above.

Substring comparision with one mismatch

The following is code for comparing a String A and String B with atmost one mismatch
i.e.,
ABC is same as ABX or AXC or XBC but, not same as AXZ
I did check several cases but, the website says it provides wrong answer. Could someone help to figure out where does this code fail?
Also, I'd be glad if someone could provide a better algorithm for the same problem.
TY
int compare(string a, int pos, string b) {
int count = 0;
int length = b.length()-1;
int mid = b.length() /2;
if(pos+length >= a.length())
return 0;
for(int i=0,j=pos;i<=mid;i++,j++) {
if(i == mid) {
if(a[j] != b[i])
count ++;
}
else {
if(a[j] != b[i])
count ++;
if(a[pos+length - i] != b[length -i])
count ++;
}
if(count >= 2) return 0;
}
return 1;
}
One problem is that if b.length() is even, then you compare a[pos + b.length() / 2] to b[b.length() / 2] twice: once when i == mid - 1, and once when i == mid. So something like compare("abcd", 0, "abbd") returns 0, because it counts the 'c'-vs.-'b' discrepancy as two separate mismatches.
I recommend that you simply strip out all logic related to mid. It serves no purpose other than massively complicating your code. If you iterate straight from 0 to b.length() - 1, you'll be much better off.