Recursive Longest Common Substring (LCS) problem optmization - java

I have the following code in Java:
public static int Secret(String a, String b, int x, int y){
if ((x == -1) || (y == -1)) {
return 0;
}
if (a.charAt(x) == b.charAt(y)) {
return Secret(a, b, x-1, y-1) + 1;
} else {
int left = Secret(a, b, x, y-1);
int up = Secret(a, b, x-1, y);
if (left > up) {
return left ;
} else {
return up;
}
}
return -1;
}
This code looks like the Longest Common Substring Problem but with a garbage complexity. I am supposed to opmitize it to O(mn) (space and time).
I tried following the algorithm on the wikipedia (https://en.wikipedia.org/wiki/Longest_common_substring_problem), that is O(mn) (space and time).
public static int iterativeLCS(String a, String b, int x, int y) {
int[][] L = new int[x+1][y+1];
int z = 0;
for (int i = 0; i <= x; i++) {
for (int j = 0; j <= y; j++) {
if (a.charAt(i) == b.charAt(j)) {
if ((i == 0) || (j == 0)) {
L[i][j] = 1;
} else {
L[i][j] = L[i-1][j-1] + 1;
}
if (L[i][j] > z) {
z = L[i][j];
}
} else {
L[i][j] = 0;
}
}
}
}
But the results don't match for some inputs. For example:
xalmandriatico
talcolaritriom
13
13
Expected output (using the recursive alg): 8
Actual output (using the iterative alg from wikipedia): 2
Any idea on what I have to do?

Related

How can I output the points that are colinear?

THE PROBLEM: Write a program that reads N points in a plane and outputs any group of four or more colinear points
What I did: I calculated the slope of every 2 points and then put them in a hashmap to see which one is the max.
What I need to do: I need to output the points that are colinear from the initial 2D array. I found the number of points that are colinear with the hashmap.
import java.util.*;
public class app {
public static int maxPoints(int[][] points) {
int ans = 1;
int n = points.length;
for (int i = 0; i < n; i++) {
HashMap<String, Integer> map = new HashMap<>();
int OLP = 0;
int max = 0;
for (int j = i + 1; j < n; j++) {
if (points[i][0] == points[j][0] && points[i][1] == points[j][1]) {
OLP++;
continue;
}
int dy = points[j][1] - points[i][1];
int dx = points[j][0] - points[i][0];
int g = gcd(Math.abs(dy), Math.abs(dx));
int num = dy / g;
int deno = dx / g;
if (num == 0)
deno = 1;
if (deno == 0)
num = 1;
if ((num < 0 && deno < 0) || deno < 0) {
num *= -1;
deno *= -1;
}
map.put(createString(deno, num), map.getOrDefault(createString(deno, num), 0) + 1);
max = Math.max(max, map.get(createString(deno, num)));
}
ans = Math.max(ans, 1 + OLP + max);
}
return ans;
}
public static int gcd(int a, int b) {
if (a == 0)
return b;
if (b == 0)
return a;
int max = Math.max(a, b);
int min = Math.min(a, b);
return gcd(max % min, min);
}
public static String createString(int a, int b) {
return Integer.toString(a) + " " + Integer.toString(b);
}
public static void main(String[] args) {
int[][] points = { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 4 } };
System.out.println("max Points are: " + maxPoints(points));
}}

Each substring of a certian length of a binary substring should have at least one '1' character

You have been given a binary string containing only the characters '1' and '0'.
Calculate how many characters of the string need to be changed in order to make the binary string such that each of its substrings of at least a certain length contains at least one "1" character.
I came to think of the following idea but it fails for many testcases:
public static int minimumMoves(String s, int d) {
int n = s.length();
int i=0, answer = 0;
while(i<n)
{
boolean hasOne = false;
int j=i;
while(j<n && j<i+d)
{
if(s.charAt(j) == '1')
{
hasOne = true;
break;
}
j++;
}
if(!hasOne) {
answer++;
i += d;
}
else i++;
}
return answer;
}
Also my algorithm runs on O(|s|2) time. Can anyone suggest ideas on O(|s|) time?
Just throwing off an idea:
return s.split("(?<=\\G.{" + String.valueof(d) + "})").stream().filter(str -> str.contains("1")).count()
You just need to break ensure there is no run of d zeros.
public static int minimumMoves(String s, int d) {
int result = 0;
int runLength = 0;
for(char c: s.toCharArray()) {
if (c == '0') {
runLength += 1;
if (runLength == d) { // we need to break this run
result += 1;
runLength = 0;
}
} else {
runLength = 0;
}
}
return result;
}
I used the sliding window technique and Deque to solve this. This is my accepted solution:
public static int minimumMoves(String s, int d) {
int n = s.length();
Deque<Character> dq = new LinkedList<>();
int count = 0, answer = 0;
for(int i=0; i<d; i++)
{
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
}
if(count == 0) {
answer++;
count++;
dq.removeLast();
dq.addLast('1');
}
int i=d;
while(i<n)
{
if(dq.getFirst() == '1') count--;
dq.removeFirst();
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
if(count == 0)
{
answer++;
dq.removeLast();
dq.addLast('1');
count++;
}
i++;
}
return answer;
}
You just need to use a sliding window and a count of 1s so far at each index. Use a sliding window of d and if you don't see any ones so far, update the last index of that window with 1 and increment the result.
Code below:
public static int minimumMoves(String s, int d) {
int n = s.length();
int[] count = new int[n+1];
int res = 0;
for ( int i = 1; i <= d; i++ ) {
if ( s.charAt(i-1) == '1') count[i] = count[i-1]+1;
else count[i] = count[i-1];
}
if ( count[d] == 0 ) {
res++;
count[d] = 1;
}
for ( int i = d+1; i <= n; i++ ) {
if ( s.charAt(i-1) == '0' ) {
count[i] = count[i-1];
int ones = count[i] - count[i-d];
if ( ones == 0 ) {
count[i] = count[i-1] + 1;
res++;
}
} else {
count[i] = count[i-1] + 1;
}
}
return res;
}
Thought of another implementation you can do for this by working from the maximum possible changes (assumes at start that all values are '0' in String), reduce it when it finds a '1' value, and then jump to the next substring start. This allows it to run in O(n) and Ω(n/m) (n = String length, m = Substring length).
public static int minimumMoves(String s, int d)
{
char[] a = s.toCharArray();
//Total possible changes (not counting tail)
if(a.length < d)
return 0;
int t = (int) a.length / d;
//Total possible changes (counting tail)
//int t = (int) Math.ceil((double) a.length / (double) d);
for(int i = 0; i < a.length; i++)
{
if(a[i] == '1')
{
t--;
//Calculate index for start of next substring
i = (i / d + 1) * d - 1;
}
}
return t;
}

Interesting thus complex recursive Big-O Calculation - Specific examples

I am totally a beginner learning a subject called Algorithms and Data Structures and got to the part about Big-O Notation. I have read many different materials writing about this but most of them just show examples of calculation of simple cases.
The assignment for this topic has some really interesting complex examples with recursion calling each other and for loops, while loops, etc...which I could not figure out and need help on calculating. I really appreciate any help and explanation, to understand deeply about this.
Also:
Ex No.3: I don't understand what the meaning of return "0xCAFE + 0xBABE + s"? I couldn't see it appear anywhere in the method, really strange to me.
Ex No.4: At first I thought these are different examples but I notice in method g has a call for method f so it should be in one example, is my assumption correct?
1.
long c(int x) {
if (x <= 1) {
return 1;
} else {
long s = 0;
for (int i = 1; i < x; i++) {
s = s + c(x - 1);
}
return s;
}
}
2.
long d(int x) {
long s = -x * x;
while (s <= x * x * x) {
s++;
}
for (long i = s * x; i > 0; i--) {
s--;
}
return s;
}
3.
double e(long x, long y) {
double s = 0_0;
for (int i = 1; i <= x; i *= 2) {
for (double j = x; j >= 1; j /= 3) {
for (int k = 0; k < y; k += 4) {
s++;
}
}
}
return 0xCAFE + 0xBABE + s;
}
4.Calculate each f & g
long f(int x, int y) {
if (x <= 0) {
return y;
} else {
return f(x - 1, 2 * y);
}
}
double g(int x, int y) {
double s = 0.0D;
for (long i = f(x, y); i >= 0; i--) {
s++;
}
return s;
}
5.
char h(int x) {
char h = 'h';
for (long i = h; i-- > ++i; x--) {
h++;
}
return h;
}
Big-O is just a way to measure the Runtime it takes for algorithms to complete.
You should look at the base of how to understand this before you try to understand these examples because they're rather complex.
A small example: O(n)
public void o(int n, int i) {
if (i == n)
return;
o(n, i++);
}
This resembles a for loop,
for (int i = 0; i <= n; i++)
In example 3:
return 0xCAFE + 0xBABE + s;
Is arbitrary, it looks like it doesn't represent anything and 's' will be the big O value for the methods complexity through its loops,
for (int i = 1; i <= x; i *= 2) { // BigO = 2 ^ i
for (double j = x; j >= 1; j /= 3) { // BigO = (2 ^i) / 3
for (int k = 0; k < y; k += 4) { //BigO = y / 4

Why Longest common string can not recursive first and output latter

Here i want to output the longest common string using dynamic programming algorithm ,code below is my implementation.what make me wired is the output A C A D C B, it's obviously wrong, and if i change these two lines and make it print first and recurse latter, result is true.and i have draw such process in paper and really do not know why the first is wrong.
display(flags, c, x-1, y-1);
System.out.print(c[x] + " ");:
public class LCSubstring{
public static void main(String[] args){
String[] x = {"", "A","B","A","D","F","E","C","A"};
String[] y = {"", "B","A","C","A","D","F","C","B","A"};
int[][] flags = getFlag(x, y);
display(flags, x, x.length-1, y.length-1);
}
public static int[][] getFlag(String[] x, String[] y){
int[][] c = new int[x.length][y.length];
int[][] b = new int[x.length][y.length];
for(int i = 1; i < x.length; i++){
for(int j = 1; j < y.length; j++){
if(x[i] == y[j]){
c[i][j] = c[i-1][j-1] + 1;
b[i][j] = 1;
}else if(c[i][j-1] >= c[i-1][j]){
c[i][j] = c[i][j-1];
b[i][j] = 0;
}else{
c[i][j] = c[i-1][j];
b[i][j] = -1;
}
}
}
return b;
}
public static void display(int[][] flags, String[] c, int x, int y){
if (x == 0 || y == 0) {
return;
}
if(flags[x][y] == 1){
display(flags, c, x-1, y-1);
System.out.print(c[x] + " ");
}else if(flags[x][y] == 0){
display(flags, c, x, y-1);
}else if(flags[x][y] == -1){
display(flags, c, x-1, y);
}
}
}
UPDATE:non-recursive in finding result
public static void display(int[][] flags, String[] c, int x, int y){
while (x != 0 && y != 0){
if (flags[x][y] == 1){
System.out.print(c[x] + " ");
x--;
y--;
}else if (flags[x][y] == 0){
y--;
}else if (flags[x][y] == -1){
x--;
}
}
}
When traversing trees (which your code is effectively doing), you can traverse in one of three orders:
pre-order
in-order
post-order
Reference Tree traversal on Wikipedia.
When you change the order of the 2 lines in your code, you are switching between pre-order and in-order traversal. Take a look at the Wikipedia article and it should help you understand the difference between the different traversal orders, and how to code for them.

How to binary search in an array which is in an descending order?

my code doesn't work, I want to be able to binary search in an array which is in an descending order.
static int searchDescendingGT( double[] a, int i, int j, double x )
{
while(i!=j){
// | >x | unknown | >=x |
int m = i+(j-i)/2;
if (a[m]<x){
j = m;
}
else{
i = m+1;
}
}
return i;
}
What might be it's problems and what am I not seeing?
Try foll instead.
Assumption: a is your array, i = start, j= end, x is the element you're trying to find. Foll will return -1 if x not in a
static int searchDescendingGT(double[] a, int i, int j, double x) {
while (i <= j) {
int m = (i + j) / 2;
if (a[m] == x) {
return m;
} else if (a[m] < x) {
j = m - 1;
} else {
i = m + 1;
}
}
return -1;
}

Categories