Longest Common Subsequence taking maximum of all the three possible cases - algorithm

I approached the Longest Common Subsequence as:
LCS(m,n) = max( LCS(m-1,n), LCS(m,n-1), LCS(m-1,n-1) + (String1[m]==String2[n]) );
Whereas the texts show the logic for the problem to be like:
if( String1[m]==String2[n] )
LCS(m,n) = LCS(m-1,n-1) + 1;
else LCS(m,n) = max( LCS(m-1,n), LCS(m,n-1) );
Will my approach produce incorrect results? if yes, then in what kind of a situation? If it is correct, how do you justify the correctness?
Thanks in advance!

My (badly) Java version, it runs correctly?
//'main' method must be in a class 'Rextester'.
//Compiler version 1.8.0_111
import java.util.*;
import java.lang.*;
class Rextester
{
public static void main(String args[])
{
int[] a = {1,1,1,1,2,3,2,3};
int[] b = {1,1,1,1,3,4,3,4};
System.out.println(solve(a, b).toString());
System.out.println(solve2(a, b).toString());
}
private static void printL(int[][]len, int m, int n, int[] a, int[] b)
{
System.out.print(" a→ ");
for (int j = 0; j < m; ++j)
{
System.out.print(a[j]);
System.out.print(" ");
}
System.out.println();
for (int i = 0; i <= n; ++i)
{
if (i > 0) { System.out.print(" "); System.out.print(b[i-1]); System.out.print(" "); }
else { System.out.print("b↓ "); }
for (int j = 0; j <= m; ++j)
{
System.out.print(len[i][j]);
System.out.print(" ");
}
System.out.println();
}
}
private static List<Integer> solve(int[] a, int[] b)
{
int m = a.length;
int n = b.length;
System.out.println("Method 1");
int[][] len = new int[n+1][m+1];
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
len[i+1][j+1] = a[j] == b[i] ? 1 + len[i][j] : Math.max(len[i+1][j], len[i][j+1]);
printL(len, m, n, a, b);
List<Integer> c = new ArrayList<Integer>();
for (int i = n - 1, j = m - 1; len[i+1][j+1] > 0;)
{
if (a[j] == b[i]) { c.add(a[j]); i--; j--; }
else if (len[i+1][j] < len[i][j+1]) i--;
else j--;
}
Collections.reverse(c);
return c;
}
private static List<Integer> solve2(int[] a, int[] b)
{
int m = a.length;
int n = b.length;
System.out.println("Method 2");
int[][] len = new int[n+1][m+1];
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
len[i+1][j+1] = Math.max(Math.max(len[i+1][j], len[i][j+1]), (a[j] == b[i] ? 1 : 0) + len[i][j]);
printL(len, m, n, a, b);
List<Integer> c = new ArrayList<Integer>();
for (int i = n - 1, j = m - 1; len[i+1][j+1] > 0;)
{
if (a[j] == b[i]) { c.add(a[j]); i--; j--; }
else if (len[i+1][j] < len[i][j+1]) i--;
else j--;
}
Collections.reverse(c);
return c;
}
}
output on rextester:
Method 1
a→ 1 1 1 1 2 3 2 3
b↓ 0 0 0 0 0 0 0 0 0
1 0 1 1 1 1 1 1 1 1
1 0 1 2 2 2 2 2 2 2
1 0 1 2 3 3 3 3 3 3
1 0 1 2 3 4 4 4 4 4
3 0 1 2 3 4 4 5 5 5
4 0 1 2 3 4 4 5 5 5
3 0 1 2 3 4 4 5 5 6
4 0 1 2 3 4 4 5 5 6
[1, 1, 1, 1, 3, 3]
Method 2
a→ 1 1 1 1 2 3 2 3
b↓ 0 0 0 0 0 0 0 0 0
1 0 1 1 1 1 1 1 1 1
1 0 1 2 2 2 2 2 2 2
1 0 1 2 3 3 3 3 3 3
1 0 1 2 3 4 4 4 4 4
3 0 1 2 3 4 4 5 5 5
4 0 1 2 3 4 4 5 5 5
3 0 1 2 3 4 4 5 5 6
4 0 1 2 3 4 4 5 5 6
[1, 1, 1, 1, 3, 3]
My sketchy proof:
If you look at any row LCS(m) in the table above, you'll see that they all have increasing values, or they're all monotonically increasing. They cannot be decreasing since LCS(m,n) means longest common subsequence of (sub)string1 of length m and (sub)string2 of length n, if n2 >= n1 then LCS(m,n2) >= LCS(m,n1) because if n2 >= n1, LCS(m,n2) contains LCS(m,n1).
For the column LCS(n) you use the same proof. Now you have LCS(m,n) <= LCS(m,n+1) and LCS(m,n) <= LCS(m+1,n), which means your taking maximum of all three possible cases are correct.
LCS(m,n) = max( LCS(m-1,n), LCS(m,n-1), LCS(m-1,n-1) + (String1[m]==String2[n]) );
takes the wrong path only when String1[m] != String2[n] and (LCS(m-1,n-1) > LCS(m,n-1) or LCS(m-1,n-1) > LCS(m-1,n)), but the latter case (LCS(m-1,n-1) > LCS(m,n-1) or LCS(m-1,n-1) > LCS(m-1,n)) never happens. So your approach is correct.

Related

XOR queries on a given array

Given an array of n integers, indexed from 1->n. The task is to perform of Q given queries, and print the sum of the array after each queries.
We can perform three types of operations:
1 X: add X to the array (its index will be n+1, n+2,...)
2 Y: remove element with index Y from the array
3 Z: for each element i in the array, perform i^Z (i xor Z)
Example:
Input
arr[] = {2, 3, 9, 5, 6, 6}, Q = 5
1 3
3 5
2 2
3 2
2 7
Output: 34 37 31 27 23
Explanation:
1 3 -> arr[] = {2, 3, 9, 5, 6, 6, 3} -> sum = 34
3 5 -> arr[] = {7, 6, 12, 0, 3, 3, 6} -> sum = 37
2 2 -> arr[] = {7, 12, 0, 3, 3, 6} -> sum = 31
3 2 -> arr[] = {5, 14, 2, 1, 1, 4} -> sum = 27
2 7 -> arr[] = {5, 14, 2, 1, 1} -> sum = 23
P/S: I'm trying to solve the problem with Segment Tree, but I can't update the tree with XOR operator. Is there any other way to solve this problem? I'm trying to solve it in O(n.logn)
Assuming your numbers do not exceed some standard constant like 232 or 264, we can do this in constant time, by counting the bits separately.
You will need to:
Remember how many numbers there are in the array
Remember how many lit bits there are at every position in the binary positioning system.
So here's your example, expanded into bits, with the least significant ones at the top:
2 3 9 5 6 6 3 | sum
-------------------------
0 1 1 1 0 0 1 | 4
1 1 0 0 1 1 1 | 5
0 0 0 1 1 1 0 | 3
0 0 1 0 0 0 0 | 1
Now, that means that there are
4 "first" bits lit
5 "second" bits lit
3 "third" bits lit and
1 "fourth" bit lit.
The number of numbers is 7.
The sum of these numbers is 34
We now xor this with 5, which is 0101 in binary, so there will now be
7 - 4 = 3 "first" bits lit
5 "second" bits lit
7 - 3 = 4 "third" bits lit
1 "fourth" bit lit
If we sum this up, we get 3 * 2^0 + 5 * 2^1 + 4 * 2^2 + 1 * 2^3 = 37 (where now by ^ I mean exponentiation as opposed to xor).
So this is what you do every time the xor operation pops up. Adding and removing numbers is the easy parts because you go over their bits and accordingly adjust the counts of lit "i-th" bits in the array.
Thanks to Maurycyt I have solved the problem. Below is my code in case anyone need it
const int MAX = 1e5 + 5;
const int MAXBIT = 32;
int n, q, num, xor_add;
int arr[MAX], sum[32];
int getSum()
{
int res = 0;
for(int i = 0; i < MAXBIT; i++)
res += sum[i]*(1<<i);
return res;
}
void updateXor(int x){
xor_add ^= x;
for(int i = 0; i < MAXBIT; i++)
if(x & (1<<i))sum[i] = num - sum[i];
}
void add(int x){
++num;
arr[n++] = x;
for(int i = 0; i < MAXBIT; i++)
if(x & (1<<i))sum[i]++;
}
void remv(int i){
--num;
int x = arr[i-1]^xor_add;
for(int i = 0; i < MAXBIT; i++)
if(x & (1<<i))sum[i]--;
}
int main()
{
cin >> n >> q;
num = n;
for(int i = 0; i < n; i++)cin >> arr[i];
for(int i = 0; i < MAXBIT; i++)
for(int j = 0; j < n; j++)
if(arr[j] & (1<<i))sum[i]++;
while(q--){
int id, x;
cin >> id >> x;
if(id == 1)add(x);
else if(id == 2)remv(x);
else updateXor(x);
cout << getSum() << '\n';
}
return 0;
}

Floyd's algorithm

This I keep running but its not running correctly I am not getting the right answers
public static void Floyd(int n, int [][] W, int [][] D, int [][] P)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
P[i][j]=0;
D = W;
for (int k = 0; k<=n; k++)
for(int i = 0; i<=n; i++)
for(int j=1;j<=n;j++)
{
if (D[i][k] + D[k][j]< D[i][j])
{
P[i][j] =k;
D[i][j] = D[i][k]+D[k][j];
}
}
} // end Floyd
public static void printArray(int n, int [][] A) {
int i, j;
System.out.println();
System.out.print(" ");
for (i = 1; i <= n; i++)
System.out.printf("%7d", i);
System.out.println("\n");
for (i = 1; i <= n; i++) {
System.out.printf("%7d", i);
for (j = 1; j <= n; j++)
System.out.printf("%7d", A[i][j]);
System.out.println();
}
System.out.println();
} // end printArray
Here is my main which and the above are my print method and floyd methods... I think there is something wrong with the floyd method
public static void main(String[] args) throws IOException {
Scanner kbd = new Scanner(System.in);
Scanner input;
String inputFileName;
System.out.print("\nEnter input file name: ");
inputFileName = kbd.nextLine();
FileReader f = new FileReader(inputFileName);
input = new Scanner(f);
int i, j, n;
n = input.nextInt();
System.out.println();
int [][] W = new int[n+1][n+1];
int [][] D = new int[n+1][n+1];
int [][] P = new int[n+1][n+1];
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
W[i][j] = input.nextInt();
System.out.println("W is: ");
printArray(n, W);
Floyd(n, W, D, P);
System.out.println("D is: ");
printArray(n, D);
System.out.println("P is: ");
printArray(n, P);
Here is the output i am getting The graphs are not filling the way that they are supposed too
W is:
1 2 3 4 5
1 0 10 9999 10 50
2 90 0 30 20 9999
3 9999 9999 0 40 9999
4 9999 9999 20 0 30
5 30 9999 9999 90 0
D is:
1 2 3 4 5
1 0 0 0 0 0
2 0 0 0 0 0
3 0 0 0 0 0
4 0 0 0 0 0
5 0 0 0 0 0
P is:
1 2 3 4 5
1 0 0 0 0 0
2 0 0 0 0 0
3 0 0 0 0 0
4 0 0 0 0 0
5 0 0 0 0 0

recent Google interview puzzle on bitwise operation

This is a recent interview question from Google:
We define f(X, Y) as number of different corresponding bits in binary
representation of X and Y. For example, f(2, 7) = 2, since binary
representation of 2 and 7 are 010 and 111, respectively. The first and
the third bit differ, so f(2, 7) = 2.
You are given an array of N positive integers, A1, A2 ,…, AN. Find sum
of f(Ai, Aj) for all pairs (i, j) such that 1 ≤ i, j ≤ N
For example:
A=[1, 3, 5]
We return
f(1, 1) + f(1, 3) + f(1, 5) + f(3, 1) + f(3, 3) + f(3, 5) + f(5, 1) +
f(5, 3) + f(5, 5) =
0 + 1 + 1 + 1 + 0 + 2 + 1 + 2 + 0 = 8
I could think of this solution which is O(n^2)
int numSetBits(unsigned int A) {
int count = 0;
while(A != 0) {
A = A & (A-1);
count++;
}
return count;
}
int count_diff_bits(int a, int b)
{
int x = a ^ b;
return numSetBits(x);
}
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) {
sum += count_diff_bits(A[i], A[j]);
}
}
Another approach i can think of is (considering that each element contains only one binary digit):
Start from the end of the array
keep a count of 1's and 0's found so far
If the current element is 1, then it will contribute count_of_zeros to the final sum
Continue like this till we reach the start of the array.
Is this approach correct.
Iterate the array, and count number of "on" bits in each bit index, for example [1, 3, 5]:
0 0 1
0 1 1
1 0 1
-----
1 1 3
Now, for each bit counter, calculate:
[bit count] * [array size - bit count] * 2
and sum for all bits...
With example above:
3 * (3 - 3) * 2 = 0
1 * (3 - 1) * 2 = 4
1 * (3 - 1) * 2 = 4
total = 8
To show why this works, lets look at a subset of the problem, using a single bit. Let's see what happens if we have an array with: [1, 1, 0, 0, 1, 0, 1]. Our count is 4 and size is 7. If we examine the first bit with all the bits in the array (including self, as in the question), we get:
1 xor 1 = 0
1 xor 1 = 0
1 xor 0 = 1
1 xor 0 = 1
1 xor 1 = 0
1 xor 0 = 1
1 xor 1 = 0
As can be seen, the contribution of this bit is the number of "off" bits. The same holds true for any other "on" bit. We could say that each "on" bit counts as the number of "off" bits:
[bit count] * [array size - bit count]
And where does the multiplication by 2 comes from? well, since we do the same with the "off" bits, except that for these, the contribution is the number of "on" bits:
[array size - bit count] * [bit count]
which of course is the same as above, and we can just multiply...
Complexity is O(n*k) where k is number of bits (32 in your code).
#include <bits/stdc++.h>
#define MOD 1000000007ll
using namespace std;
typedef long long LL;
int solve(int arr[], int n) {
int ans = 0;
// traverse over all bits
for(int i = 0; i < 31; i++) {
// count number of elements with ith bit = 0
long long count = 0;
for(int j = 0; j < n; j++) if ( ( arr[j] & ( 1 << i ) ) ) count++;
// add to answer count * (n - count) * 2
ans += (count * ((LL)n - count) * 2ll) % MOD;
if(ans >= MOD) ans -= MOD;
}
return ans;
}
int main() {
int arr[] = {1, 3, 5};
int n = sizeof arr / sizeof arr[0];
cout << solve(arr, n) << endl;
return 0;
}

Print ways to reach the n’th stair

I recently encountered this problem in an interview
There are n stairs, a person standing at the bottom wants to reach the top. The person can climb either 1 stair or 2 stairs at a time.
Print all possible ways person can reach the top.
For example, n=4 Output:
1 2 3 4
1 2 4
1 3 4
2 3 4
2 4
But I couldn't code this properly. How to code up solution for this?
To print the number of ways, you can first understand how to calculate the number of ways, and adjust it so each "count" will print instead of just count:
D(0) = 1
D(-1) = 0
D(i) = D(i-1) + D(i-2)
To adjust it to actual printing, you need to "remember" the choices you have made, and follow the same logic. Pseudo code:
printWays(curr, n, soFar):
if curr > n:
return
soFar.append(curr)
if n == curr:
print soFar
soFar.removeLast()
return
printWays(curr+1,n,soFar)
printWays(curr+2,n,soFar)
soFar.removeLast()
The idea is:
soFar is the current series of steps you did.
curr is the current step you're at.
n is the last stair you need to get to.
At each point, you either climb one stair or two. You check both options.
You can try some recursive solution where you call recursively CanClimb(n-1) and CanClimb(n-2) to visualize the possible ways.
Sample solution in C#:
public static void ClimbWays(int n, int currentIndex, int[] currectClimb)
{
if (n < 0) return;
if (n == 0)
{
for (var i = currentIndex - 1; i >= 0; i--)
{
Console.Write(currectClimb[i] + " ");
}
Console.WriteLine();
return;
}
currectClimb[currentIndex] = n;
ClimbWays(n - 1, currentIndex + 1, currectClimb);
ClimbWays(n - 2, currentIndex + 1, currectClimb);
}
Output for ClimbWays(4, 0, new int[4]);:
1 2 3 4
2 3 4
1 3 4
1 2 4
2 4
If you want to just count them you can use the well known Fibonacci sequence which can be calculated iteratively:
public static int Fibonacci(int n)
{
int a = 0;
int b = 1;
// In N steps compute Fibonacci sequence iteratively.
for (int i = 0; i < n; i++)
{
int temp = a;
a = b;
b = temp + b;
}
return a;
}

Number of submatricies containing all zeros

Is there a way to find a number of rectangular submatrices containing all zeros with a complexity smaller than O(n^3), where n is the dimension of given matrix?
Here is a solution O(n² log n).
First, let's convert the main problem to something like this:
For given histogram, find the number of submatrices containing all zeros.
How to convert it ?
For each position calculate the height of column that start on that position and contain only zeros.
Example:
10010 01101
00111 12000
00001 -> 23110
01101 30020
01110 40001
It can be easily find in O(n²).
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
up[i][j] = arr[i][j] ? 0 : 1 + up[i - 1][j];
Now we can consider each row as histogram with given heights.
Let's solve the problem with histogram.
Our goal is to travel all heights from left to right, and on each step we are going to update array L.
This array for each height is going to contain maximum widths so that we can make a rectangle of this width from current position, to the left and of given height.
Consider example:
0
0 0
0 000
00000 -> heights: 6 3 4 4 5 2
000000
000000
L[6]: 1 0 0 0 0 0
L[5]: 1 0 0 0 1 0
L[4]: 1 0 1 2 3 0
L[3]: 1 2 3 4 5 0
L[2]: 1 2 3 4 5 6
L[1]: 1 2 3 4 5 6
steps: 1 2 3 4 5 6
As you can see if we add all those numbers we will receive an answer for given histogram.
We can simply update array L in O(n), however we can also do it in O(log n) by using segment tree (with lazy propagation) that can add in interval, set value in interval and get sum from interval.
In each step we just add 1 to interval [1, height] and set 0 in interval[height + 1, maxHeight] and get sum from interval [1, maxHeight].
height - height of current column in histogram.
maxHeight - maximum height of column in histogram.
And thats how you can get O(n² * log n) solution :)
Here is main code in C++:
const int MAXN = 1000;
int n;
int arr[MAXN + 5][MAXN + 5]; // stores given matrix
int up[MAXN + 5][MAXN + 5]; // heights of columns of zeros
long long answer;
long long calculate(int *h, int maxh) { // solve it for histogram
clearTree();
long long result = 0;
for(int i = 1; i <= n; i++) {
add(1, h[i]); // add 1 to [1, h[i]]
set(h[i] + 1, maxh); // set 0 in [h[i] + 1, maxh];
result += query(); // get sum from [1, maxh]
}
return result;
}
int main() {
ios_base::sync_with_stdio(0);
cin >> n;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
cin >> arr[i][j]; // read the data
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
up[i][j] = arr[i][j] ? 0 : 1 + up[i - 1][j]; // calculate values of up
for(int i = 1; i <= n; i++)
answer += calculate(up[i], i); // calculate for each row
cout << answer << endl;
}
Here is the beginning of code, segment tree:
#include <iostream>
using namespace std;
// interval-interval tree that stores sums
const int p = 11;
int sums[1 << p];
int lazy[1 << p];
int need[1 << p];
const int M = 1 << (p - 1);
void update(int node) {
if(need[node] == 1) { // add
sums[node] += lazy[node];
if(node < M) {
need[node * 2] = need[node * 2] == 2 ? 2 : 1;
need[node * 2 + 1] = need[node * 2 + 1] == 2 ? 2 : 1;
lazy[node * 2] += lazy[node] / 2;
lazy[node * 2 + 1] += lazy[node] / 2;
}
} else if(need[node] == 2) { // set
sums[node] = lazy[node];
if(node < M) {
need[node * 2] = need[node * 2 + 1] = 2;
lazy[node * 2] = lazy[node] / 2;
lazy[node * 2 + 1] = lazy[node] / 2;
}
}
need[node] = 0;
lazy[node] = 0;
}
void insert(int node, int l, int r, int lq, int rq, int value, int id) {
update(node);
if(lq <= l && r <= rq) {
need[node] = id;
lazy[node] = value * (r - l + 1);
update(node);
return;
}
int mid = (l + r) / 2;
if(lq <= mid) insert(node * 2, l, mid, lq, rq, value, id);
if(mid + 1 <= rq) insert(node * 2 + 1, mid + 1, r, lq, rq, value, id);
sums[node] = sums[node * 2] + sums[node * 2 + 1];
}
int query() {
return sums[1]; // we only need to know sum of the whole interval
}
void clearTree() {
for(int i = 1; i < 1 << p; i++)
sums[i] = lazy[i] = need[i] = 0;
}
void add(int left, int right) {
insert(1, 0, M - 1, left, right, 1, 1);
}
void set(int left, int right) {
insert(1, 0, M - 1, left, right, 0, 2);
}
// end of the tree

Resources