I wanted to compare the LCS of two files from their binary, therefore i used the usual LCS source code, and using the GenStr command to change the bytes of the file to String first.
The problem is, I received memory out of bound error because comparing String has limit, therefore i am planning to use array that stores the bytes then compare it. Is it possible to use LCS algorithm to compare two arrays of bytes?
EDIT:
public static byte[] Compare(byte[] x, byte[] y) {
int i, j;
final int x_length = x.length;
final int y_length = y.length;
int n = 2048;
int m = 2048;
// D[i][j] = direction, L[i][j] = Length of LCS
int[][] D = new int[n + 1][m + 1];
byte[][] L = new byte[n + 1][m + 1]; // { 1, 2, 3 }
// D[i][0] = 0 for 0<=i<=n
// D[0][j] = 0 for 0<=j<=m
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
if (x[i - 1] == y[j - 1]) {
D[i][j] = D[i - 1][j - 1] + 1;
L[i][j] = 1;
} else if (D[i - 1][j] >= D[i][j - 1]) {
D[i][j] = D[i - 1][j];
L[i][j] = 2;
} else {
D[i][j] = D[i][j - 1];
L[i][j] = 3;
}
}
}
// Backtrack
ByteArrayOutputStream lcs = new ByteArrayOutputStream();
i = n;
j = m;
while (i != 0 && j != 0) {
switch (L[i][j]) {
case 1: // diagonal
lcs.write(x[i - 1]); // Unreversed LCS
--i;
--j;
break;
case 2: // up
--i;
break;
case 3: // backward
--j;
break;
}
}
byte[] result = lcs.toByteArray();
// Reverse:
for (i = 0, j = result.length - 1; i < j; ++i, --j) {
byte b = result[i];
result[i] = result[j];
result[j] = b;
}
return result;
//While not end of file
while(n < x_length && m < y_length){
if(n+2048 < x.length){
n = n+2048;
} else {
n = x.length;
}
if(m+2048 < y.length){
m = m+2048;
} else {
m = y.length;
}
// D[i][j] = direction, L[i][j] = Length of LCS
int[][] D_new = new int[n + 1][m + 1];
byte[][] L_new = new byte[n + 1][m + 1]; // { 1, 2, 3 }
// D[i][0] = 0 for 0<=i<=n
// D[0][j] = 0 for 0<=j<=m
for (i = i+2048; i <= n; i++) {
for (j = j+2048; j <= m; j++) {
if (x[i - 1] == y[j - 1]) {
D_new[i][j] = D_new[i - 1][j - 1] + 1;
L_new[i][j] = 1;
} else if (D_new[i - 1][j] >= D_new[i][j - 1]) {
D_new[i][j] = D_new[i - 1][j];
L_new[i][j] = 2;
} else {
D_new[i][j] = D_new[i][j - 1];
L_new[i][j] = 3;
}
}
}
// Backtrack
ByteArrayOutputStream lcs_next = new ByteArrayOutputStream();
i = n;
j = m;
while (i != 0 && j != 0) {
switch (L[i][j]) {
case 1: // diagonal
lcs_next.write(x[i - 1]); // Unreversed LCS
--i;
--j;
break;
case 2: // up
--i;
break;
case 3: // backward
--j;
break;
}
}
byte[] result_new = lcs_next.toByteArray();
// Reverse:
for (i = 0, j = result_new.length - 1; i < j; ++i, --j) {
byte b = result_new[i];
result_new[i] = result_new[j];
result_new[j] = b;
}
return result_new;
Arrays.fill(D_new, null);
Arrays.fill(L_new, null);
Arrays.fill(result_new, null);
lcs_next.reset();
}
}
I tried, but haven't been able to check if this can be used or not, because of some errors.
Questions:
how do you append the lcs in line (return result) and line (return result_new)?
how do you clear the array so i can use it over and over again with different input?
(Array.fill(D_new, null) and Array.fill(L_new, null) doesn't work)?
Thank you in advance
There's nothing to stop you using a byte array instead. This will use half the memory of an int array, but the maximum length of it will be the same: Integer.MAX_VALUE. If you're running out of RAM, but not hitting the length limit, then this might save you.
If these are coming from files, then that's what you should be doing anyway. You really shouldn't be reading them in as entire strings. Read them byte by byte.
But the right way to do this if the files are huge (more than 2GB) is to process the files as you go, rather than reading them in beforehand, and also using a file to store the LCS data that you're creating. The nice thing about the algorithm is that all the access is localised: you scan the input files sequentially (so you don't gain anything from reading them in in advance); and you write the arrays fairly close to sequentially, by only considering the previous and current rows when you calculate a new value (so you don't gain much by having them in RAM either).
Doing it like this will allow you to scale the files arbitrarily. CPU time will then be the deciding factor. The disk cache will give you close to the same performance you'd get by reading the files in first and doing it from RAM.
A conversion without algorithmic consideration.
In java new initializes to 0 / 0.0 / false / null.
On the other hand prepending to lcs cannot be done out-of-the-box. However reversing an array is simple.
public static byte[] compare(byte[] x, byte[] y) {
int i, j;
final int n = x.length;
final int m = y.length;
/* D[i][j] = direction, L[i][j] = Length of LCS */
int[][] D = new int[n + 1][m + 1];
byte[][] L = new byte[n + 1][m + 1]; // { 1, 2, 3 }
/* D[i][0] = 0 for 0<=i<=n */
/* D[0][j] = 0 for 0<=j<=m */
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
if (x[i - 1] == y[ - 1]) {
D[i][j] = D[i - 1][j - 1] + 1;
L[i][j] = 1;
} else if (D[i - 1][j] >= D[i][j - 1]) {
D[i][j] = D[i - 1][j];
L[i][j] = 2;
} else {
D[i][j] = D[i][j - 1];
L[i][j] = 3;
}
}
}
/* Backtrack */
ByteArrayOutputStream lcs = new ByteArrayOutputStream();
i = n;
j = m;
while (i != 0 && j != 0) {
switch (L[i][j]) {
case 1: /* diagonal */
lcs.write(x[i - 1]); // We want lcs reversed though.
--i;
--j;
break;
case 2: /* up */
--i;
break;
case 3: /* backward */
--j;
break;
}
}
byte[] result = lcs.toByteArray();
// Reverse:
for (i = 0, j = result.length - 1; i < j; ++i, --j) {
byte b = result[i];
result[i] = result[j];
result[j] = b;
}
return result;
}
Related
i'm try find most similar string in a array, and i found a code in c sharp that is this one
public static int LevenshteinDistance(string s, string t)
{
int n = s.Length;
int m = t.Length;
int[,] d = new int[n + 1, m + 1];
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
Console.WriteLine(cost);
d[i, j] = Math.Min(
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
d[i - 1, j - 1] + cost);
}
}
return d[n, m];
}
and i'm trying to convert it into java but i get 1 error this is my code in java
public static int LevenshteinDistance(String s, String t)
{
int n = s.length();
int m = t.length();
int[][] d = new int[n + 1][ m + 1];
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
int cost = (t[j - 1] == s[i - 1])? 0 : 1;
d[i][ j] = Math.min(
Math.min(d[i - 1][ j] + 1, d[i][ j - 1] + 1),
d[i - 1][ j - 1]+cost );
}
}
return d[n] [m];
}
i get the error in this line of code
int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
the error that i have is "Array is required,but string found" this is what i have in my main
String []ray ={"food","drinks","stuffs"};
String fa="drink";
for (int i = 0; i < ray.length; i++)
{
System.out.print(LevenshteinDistance(fa, ray[i]));
}
i would appreciate any help
Use t.charAt(j-1) == s.charAt(i-1) as to access characters (letters) in string You cannot access them directly via index (brackets []).
int cost = (t.charAt(j - 1) == s.charAt(i - 1))? 0 : 1;
You are accessing the strings as arrays here with the [] array operator:
t[j - 1] == s[i - 1]
to get the nth char of a string, instead use .charAt(n)
so in this case change it to:
t.charAt(j - 1) == s.charAt(i - 1)
the same applies to the rest of the code.
I have the following code translated as best I could from Java to C#:
public double maxProfit(double[] prices, int K)
{
if (K == 0 || prices.Length == 0)
{
return 0;
}
var dp = new double[K + 1, prices.Length];
for (int i = 1; i < K + 1; i++)
{
double maxDiff = -prices[0];
for (int j = 1; j < prices.Length; j++)
{
dp[i, j] = Math.Max(dp[i, j - 1], prices[j] + maxDiff);
maxDiff = Math.Max(maxDiff, dp[i - 1, j] - prices[j]);
}
}
printTrans(dp, prices, K);
return dp[K, prices.Length - 1];
}
public void printTrans(double[,] dp, double[] prices, int K)
{
int i = K - 1;
int j = prices.Length;
var priceList = new List<double>();
while (true)
{
if (i == 0 || j == 0)
{
break;
}
if (dp[i, j] == dp[i, j - 1])
{
j = j - 1;
}
else
{
priceList.Add(j);
double maxDiff = dp[i, j] - prices[j];
for (int z = j - 1; z >= 0; z--)
{
if (dp[i - 1, z] - prices[z] == maxDiff)
{
i = i - 1;
j = z;
priceList.Add(j);
break;
}
}
}
}
while (priceList.Count > 0)
{
Console.WriteLine("Buy # " + prices[priceList.IndexOf(0)]);
Console.WriteLine("Sell # " + prices[priceList.IndexOf(0)]);
}
}
Error occurs in the second method on lines:
if (dp[i, j] == dp[i, j - 1])
and
for (int z = j - 1; z >= 0; z--)
{
if (dp[i - 1, z] - prices[z] == maxDiff)
I am getting an Index was outside the bounds of the array. error. I understand what this error means but I have no clue on my to fix it. It took me quite a bit to understand the first part of this code but for the second part, I am at a loss.
Also what is the C# equivalent of the Java pollFirst() method?
Probably this line is the cause
public void printTrans(double[,] dp, double[] prices, int K)
{
int i = K - 1;
int j = prices.Length; // <=== this line is the cause
its causing the j to refer an index outside the bounds of the 2D array.
If you have ported from java recheck your java code.
Either make that line
int j = prices.Length - 1;
Or you need to make changes to how you create your array
var dp = new double[K + 1, prices.Length]; // <-- prices.Length would have to change here
I am designing a problem in which I have to use an int array to add or subtract values. For example instead of changing 100 to 101 by adding 1, I want to do the same thing using the int array. It work like this:
int[] val = new int[3];
val[0] = 1;
val[1] = 0;
val[2] = 0;
val[2] += 1;
so, If I have to get a value of 101, I will add 1 to val[2].
The only problem I have is finding a way to make int array work like how adding and subtracting from an ordinary integer data set works.
Is this possible using a for loop or a while loop?
Any help will be appreciated!
Here's your homework:
public static int[] increment(int[] val) {
for (int i = val.length - 1; i >= 0; i--) {
if (++val[i] < 10)
return val;
val[i] = 0;
}
val = new int[val.length + 1];
val[0] = 1;
return val;
}
Make sure you understand how and why it works before submitting it as your own work.
Solution of this problem is designed by using String
You can refer to this method which will return sum of 2 nos having input in String format.
Input String should contain only digits.
class Demo {
public static String add(String a1, String b1) {
int[] a = String_to_int_Array(a1);
int[] b = String_to_int_Array(b1);
int l = a.length - 1;
int m = b.length - 1;
int sum = 0;
int carry = 0;
int rem = 0;
String temp = "";
if (a.length > b.length) {
while (m >= 0) {
sum = a[l] + b[m] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
m--;
l--;
}
while (l >= 0) {
sum = a[l] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
l--;
}
if (carry > 0) {
temp = carry + temp;
}
} else {
while (l >= 0) {
sum = a[l] + b[m] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
m--;
l--;
}
while (m >= 0) {
sum = b[m] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
m--;
}
if (carry > 0) {
temp = carry + temp;
}
}
return temp;
}
public static int[] String_to_int_Array(String s) {
int arr[] = new int[s.length()], i;
for (i = 0; i < s.length(); i++)
arr[i] = Character.digit(s.charAt(i), 10);
return arr;
}
public static void main(String a[]) {
System.out.println(add("222", "111"));
}
}
Quick & dirty:
static void increment(int[] array){
int i = array.length-1;
do{
array[i]=(array[i]+1)%10;
}while(array[i--]==0 && i>=0);
}
Note the overflow when incementing e.g. {9, 9}. Result is {0, 0} here.
public static void increment() {
int[] acc = {9,9,9,9};
String s="";
for (int i = 0; i < acc.length; i++)
s += (acc[i] + "");
int i = Integer.parseInt(s);
i++;
System.out.println("\n"+i);
String temp = Integer.toString(i);
int[] newGuess = new int[temp.length()];
for (i = 0; i < temp.length(); i++)
{
newGuess[i] = temp.charAt(i) - '0';
}
printNumbers(newGuess);
}
public static void printNumbers(int[] input) {
for (int i = 0; i < input.length; i++) {
System.out.print(input[i] + ", ");
}
System.out.println("\n");
}
If someone is looking for this solution using JavaScript or if you can translate it to java, here's your optimum solution:
function incrementArr(arr) {
let toBeIncrementedFlag = 1, // carry over logic
i = arr.length - 1;
while (toBeIncrementedFlag) {
if (arr[i] === 9) {
arr[i] = 0; // setting the digit as 0 and using carry over
toBeIncrementedFlag = 1;
} else {
toBeIncrementedFlag = 0;
arr[i] += 1;
break; // Breaking loop once no carry over is left
}
if (i === 0) { // handling case of [9,9] [9,9,9] and so on
arr.unshift(1);
break;
}
i--; // going left to right because of carry over
}
return arr;
}
What Im trying to implement is a BubbleSort/similar algorithm, but with just one single cycle.
What that means is, I want to change this:
for (i = 0; i < N - 1; i++)
for(j = i+1; j < N; j++)
//code
into this:
for (ij = 0; ij < N * (N - 1) / 2; ij++)
i = ?
j = ?
//code
The problem is, I need to implement the values of 'i' and 'j' manually. Does anybody know if this is possible?
Assuming you meant i+1, not 1+1, the code
for (i = 0; i < N - 1; i++)
for(j = i+1; j < N; j++)
//code
is equivalent to
int k = 2 * N - 1;
for (int ij = 0; ij < N * (N - 1) / 2; ij++) {
int i = (int) Math.floor((k - Math.sqrt(k * k - 8 * ij)) / 2);
int j = i + 1 + ij - (k - i) * i / 2;
//code
}
This is completely pointless though...
You could do it like this:
while (ij < N * (N - 1) / 2) {
j = (j + 1) % N;
if (j==0)
i++;
}
I don't see the benefit though
Here is a while-loop version, though I also don't see the point. Generally, you can turn almost anything into one loop by having a boolean that indicates whether to continue, and various if-tests to decide what to do inside the loop. If applied to a naturally nested loop algorithm, the result will be less readable and maintainable than using multiple loops.
public static void weirdSort(int[] data) {
boolean sortDone = false;
boolean swapDone = false;
if (data.length < 2) {
// Lengths 0 and 1 create special cases, and are already sorted.
return;
}
int i = 0;
while (!sortDone) {
if (data[i] > data[i + 1]) {
swapDone = true;
int temp = data[i + 1];
data[i + 1] = data[i];
data[i] = temp;
}
i++;
if (i == data.length - 1) {
sortDone = !swapDone;
swapDone = false;
i = 0;
}
}
}
I am trying to add the elements of two arrays with different lengths together.
The code below is only for the same length and here is all I have so far.
//for the same lengths
int[]num1 = {1,9,9,9};
int[]num2 = {7,9,9,9};// {9,9,9}
int total = 0, carry = 1;
int capacity = Math.max(num1.length,num2.length);
int []arraySum = new int [capacity];
for (int i = capacity - 1 ; i >= 0; i--)
{
arraySum[i] = num1[i]+ num2[i];
if (arraySum[i] > 9)
{
arraySum[i] = arraySum[i] % 10;
num2[i-1] = num2[i-1] + carry;
}
}
for(int i = 0; i < arraySum.length; i++)
{
System.out.print(arraySum[i]);
}
What should I do if I change the elements in num2 and length to like {9,9,9}?
I know I probably need to put another for-loop as an inside for-loop and control the indices of the array with smaller length but how....?? One more thing... what should I do for those for-loops conditions because num1 and num2 will be eventually INPUTED by the user.
Well, you can tell that the inputs are limited because if num1[0] + num2[0] > 9 the carry has no index to be placed, then it can't be compiled. So, I need to shift the whole array to the right and place the carry from num1[0] + num2[0]. Here is the problem!! Where should I put the shifting code? I am kinda confused.......
Actually, you declare an int[] array with the capacity as Math.max(num1.length, num2.length).
It is not encough. You should set the capacity as Math.max(num1.length, num2.length) +1.
Why?
See if num1 is {1,9,9,9} and num2 is {9,9,9,9}, how can the arraySum to represent the sum {1,1,9,9,8}?
So we need to declare it as below to consider if carry is needed.
int[] arraySum = new int[capacity + 1];
Then when print the sum, check if arraySum[0] is 0 or 1, if it euqals to 0, do not print it in Console.
Modified code for reference is as follows:
package question;
public class Example {
public static void main(String[] args) {
// for the same lengths
int[] num1 = { 1,9,9,9 };
int[] num2 = { 9,9,9,9};// {9,9,9}
// 1999+9999 = 11998, its length is greater than the max
int capacity = Math.max(num1.length, num2.length);
int[] arraySum = new int[capacity + 1];
int len2 = num2.length;
int len1 = num1.length;
if (len1 < len2) {
int lengthDiff = len2 - len1;
/*
* Flag for checking if carry is needed.
*/
boolean needCarry = false;
for (int i = len1 - 1; i >= 0; i--) {
/**
* Start with the biggest index
*/
int sumPerPosition =0;
if (needCarry) {
sumPerPosition = num1[i] + num2[i + lengthDiff] +1;
needCarry = false;
}else
{
sumPerPosition = num1[i] + num2[i + lengthDiff];
}
if (sumPerPosition > 9) {
arraySum[i + lengthDiff + 1] = sumPerPosition % 10;
needCarry = true;
}else
{
arraySum[i + lengthDiff + 1] = sumPerPosition % 10;
}
}
/**
* Handle the remaining part in nun2 Array
*/
for (int i = lengthDiff - 1; i >= 0; i--) {
/*
* Do not need to care num1 Array Here now
*/
if(needCarry){
arraySum[i + 1] = num2[i]+1;
}else
{
arraySum[i + 1] = num1[i] ;
}
if (arraySum[i + 1] > 9) {
arraySum[i + 1] = arraySum[i + 1] % 10;
needCarry = true;
} else {
needCarry = false;
}
}
/*
* Handle the last number, if carry is needed. set it to 1, else set
* it to 0
*/
if (needCarry) {
arraySum[0] = 1;
} else {
arraySum[0] = 0;
}
} else {
int lengthDiff = len1 - len2;
/*
* Flag for checking if carry is needed.
*/
boolean needCarry = false;
for (int i = len2 - 1; i >= 0; i--) {
/**
* Start with the biggest index
*/
int sumPerPosition = 0;
if (needCarry) {
sumPerPosition = num2[i] + num1[i + lengthDiff] +1;
needCarry = false;
}else
{
sumPerPosition = num2[i] + num1[i + lengthDiff];
}
if (sumPerPosition > 9) {
arraySum[i + lengthDiff + 1] = sumPerPosition % 10;
needCarry = true;
}else
{
arraySum[i + lengthDiff + 1] = sumPerPosition % 10;
}
}
/**
* Handle the remaining part in nun2 Array
*/
for (int i = lengthDiff - 1; i >= 0; i--) {
/*
* Do not need to care num1 Array Here now
*/
if(needCarry){
arraySum[i + 1] = num1[i]+1;
}else
{
arraySum[i + 1] = num1[i] ;
}
if (arraySum[i + 1] > 9) {
arraySum[i + 1] = arraySum[i + 1] % 10;
needCarry = true;
} else {
needCarry = false;
}
}
/*
* Handle the last number, if carry is needed. set it to 1, else set
* it to 0
*/
if (needCarry) {
arraySum[0] = 1;
} else {
arraySum[0] = 0;
}
}
/*
* Print sum
*
* if arraySum[0] ==1, print 1
*
* Do not print 0 when arraySum[0] ==0
*/
if(arraySum[0] == 1)
{
System.out.print(1);
}
for (int i = 1; i < arraySum.length; i++) {
System.out.print(arraySum[i]);
}
}
}
An example that num1 is {1,9,9,9} and num2 is {9,9,9,9}, the sum result is as follows:
output in Console:
11998
It's quite simpe actually. Inside your loop, check that the current index is valid for both array, and replace the value to add by 0 in case of an invalid index:
int value1 = (i < num1.length) ? num1[i] : 0;
int value2 = (i < num2.length) ? num2[i] : 0;
arraySum[i] = value1 + value2;
EDIT: I didn't understand that you wanted to right-align the arrays and not left-align them. The simplest solution is probably to write and read everything in the arrays in reverse order. So if the numbers are 456 and 7658, the first array would contain 6, 5, 4 and the second one would contain 8, 5, 6, 7.
Here is more performance centric solution:
public class SumArrays {
public static void main(String[] args) {
int[] num1 = {1, 9, 9, 9};
int[] num2 = {7, 9, 9, 9, 9, 9, 9};
int[] biggerArray = num1.length > num2.length ? num1 : num2;
int[] smallerArray = num1.length <= num2.length ? num1 : num2;
int[] summedArray = new int[biggerArray.length];
System.arraycopy(biggerArray, 0, summedArray, 0, biggerArray.length);
for (int i = 0; i < smallerArray.length; i++) {
summedArray[i] += smallerArray[i];
}
for (int i = 0; i < summedArray.length; i++) {
System.out.println(summedArray[i]);
}
}
}
You can use an ArrayList instead of an array and implement a normal addition method to it:
public static ArrayList<Integer> sum(int[] arr, int[] arr2) {
ArrayList<Integer> al = new ArrayList<>();
int i = arr.length - 1;
int j = arr2.length - 1;
int c = 0;
while (i >= 0 && j >= 0) {
int temp = arr[i] + arr2[j] + c;
if (temp >= 10) {
int r = temp % 10;
al.add(0, r);
c = temp / 10;
} else {
al.add(0, temp);
c = 0;
}
i--;
j--;
}
if (i < 0 && j >= 0) {
while (j >= 0) {
al.add(0, arr2[j] + c);
c = 0;
j--;
}
} else if (j < 0 && i >= 0) {
while (i >= 0) {
al.add(0, arr[i] + c);
c = 0;
i--;
}
} else
al.add(0, c);
return al;
}
for kicks, here is an alternative:
int[] num1 =
{ 1, 9, 9, 9 };
int[] num2 =
{ 7, 9, 9, 9 };
//convert the int array to a string
StringBuilder sb = new StringBuilder(num1.length);
for (int i : num1)
{
sb.append(i);
}
String sNum1 = sb.toString();
System.out.println(sNum1);
StringBuilder sb2 = new StringBuilder(num2.length);
for (int i : num2)
{
sb2.append(i);
}
String sNum2 = sb2.toString();
System.out.println(sNum2);
try
{
//parse the string to an int
int iNum1 = Integer.parseInt(sNum1);
int iNum2 = Integer.parseInt(sNum2);
//add them together
int sum = iNum1 + iNum2;
String sSum = Integer.toString(sum);
System.out.println(sSum);
// convert num back to array
int[] sumArray = new int[sSum.length()];
for (int i = 0; i < sSum.length(); i++)
{
sumArray[i] = sSum.charAt(i) - '0';
System.out.println(sumArray[i]);
}
}
catch (Exception e)
{
// couldnt parse ints
}