Least Common Subsequence with optimized space (two columns, since it's Markovian) - java

I'm trying to write LCS of two String objects using bottom-up dynamic programming. I'm able to get it to work properly with O(mn) space. However, as I could see, I don't need all the previous columns. So, I tried to modify it to get it fit in 2 columns so space become O(m). However, it's not working for all inputs (for example, to this: abcabc and abcbcca). What am I missing here? NOT HW, NOT CONTEST nothing. Practicing DP.
public int longestCommonSubsequence(String input) {
char[] firstStr = this.string.toCharArray();
char[] secondStr = input.toCharArray();
int[][] maxLength = new int[firstStr.length+1][2];
for(int i=0; i <= firstStr.length; i++) {
maxLength[i][0] = 0;
}
for(int j=0; j < 2; j++) {
maxLength[0][j] = 0;
}
for(int i=0; i < firstStr.length; i++) {
for(int j=0; j < secondStr.length; j++) {
if(firstStr[i] == secondStr[j]) {
maxLength[i+1][1] = 1 + maxLength[i][0];
}
else {
maxLength[i+1][1] = maxLength[i][1]>maxLength[i+1][0]?maxLength[i][1]:maxLength[i+1][0];
}
}
//Copy second row to first row
for(int l =0; l < firstStr.length; l++) {
maxLength[l][0] = maxLength[l][1];
}
}
return maxLength[firstStr.length -1][0];
}

This has two problems:
if(firstStr[i] == secondStr[j]) {
maxLength[i+1][1] = 1 + maxLength[i][0];
// check here if maxLength[i+1][1] is greather than the last max length
}
else {
maxLength[i+1][1] = maxLength[i][1]>maxLength[i+1][0]?maxLength[i][1]:maxLength[i+1][0];
// absolutely wrong: maxLength[i+1][1] = 0;
}
Here can see the algorithm with micro optimization.
public static int lcs(String s0, String s1) {
int maxLength = 0;
int [][]lengths = new int[2][s1.length()+1];
for (int i = 0; i < s0.length(); i++) {
for (int j = 0; j < s1.length(); j++) {
if (s0.charAt(i) == s1.charAt(j)) {
lengths[0][j+1] = lengths[1][j] + 1;
if (lengths[0][j+1] > maxLength) {
maxLength = lengths[0][j+1];
}
} else {
lengths[0][j+1] = 0;
}
}
int []temp = lengths[0];
lengths[0] = lengths[1];
lengths[1] = temp;
}
return maxLength;
}

Related

why is declaring inside for loop works but declaring outside for loop as global variable won't work

I am not sure why I need to declare count and correct inside the first for loop here. I originally declared them as global variable but I am modifying them inside for loop. If I don't declare them inside for loop they remain the same value I think. My logic is the value gets changed inside for loop. Am I approaching this thoughts wrong?
public static double[] gradeAllStudents(char[][] response, char[] soln) {
// int count = 0;
int len = soln.length;
// int correct = 0;
double[] result = new double[response.length];
int index = 0;
for(int i = 0; i < response.length; i++) {
int count = 0;
double correct = 0;
// System.out.println(response[i].length);
for(int j = 0; j < response[i].length; j++) {
if (soln[j] == response[i][j]) {
correct= correct+1;
}
count ++;
}
// System.out.println(correct);
result[index] = 100*(correct)/(response[i].length);
index++;
if(count != len) {
throw new IllegalArgumentException("wrong exam");
}
}
return result;
}
}
I'm not sure that i got your problem
but
you can declare variable outside for loop and changing them inside.
in your example the code will look like this
public static double[] gradeAllStudents(char[][] response, char[] soln) {
int count;
int len = soln.length;
int correct;
double[] result = new double[response.length];
int index = 0;
for(int i = 0; i < response.length; i++) {
count = 0; // restart value of count
correct = 0; // restart value of correct
// System.out.println(response[i].length);
for(int j = 0; j < response[i].length; j++) {
if (soln[j] == response[i][j]) {
correct= correct+1;
}
count ++;
}
// System.out.println(correct);
result[index] = 100*(correct)/(response[i].length);
index++;
if(count != len) {
throw new IllegalArgumentException("wrong exam");
}
}
return result;
}
}
PS : you can improve your code
this still simple but better
public static double[] gradeAllStudents(char[][] response, char[] soln) {
final int len = soln.length; // this is a constant
int correct;
double[] result = new double[response.length];
for (int i = 0; i < response.length; i++) {
correct = 0;
if (len != response[i].length) {
throw new IllegalArgumentException("wrong exam");
}
for (int j = 0; j < response[i].length; j++) {
if (soln[j] == response[i][j]) {
correct ++;
}
}
result[i] = (double)(100 * correct) / response[i].length; // casting after math operation improve the performance
}
return result;
}
finally welcome to java :D

JAVA - Compare two arrays and create a new array with only the unique values from the first

I have to solve an exercise with the following criteria:
Compare two arrays:
int[] a1 = {1, 3, 7, 8, 2, 7, 9, 11};
int[] a2 = {3, 8, 7, 5, 13, 5, 12};
Create a new array int[] with only unique values from the first array. Result should look like this: int[] result = {1,2,9,11};
NOTE: I am not allowed to use ArrayList or Arrays class to solve this task.
I'm working with the following code, but the logic for the population loop is incorrect because it throws an out of bounds exception.
public static int[] removeDups(int[] a1, int[] a2) {
//count the number of duplicate values found in the first array
int dups = 0;
for (int i = 0; i < a1.length; i++) {
for (int j = 0; j < a2.length; j++) {
if (a1[i] == a2[j]) {
dups++;
}
}
}
//to find the size of the new array subtract the counter from the length of the first array
int size = a1.length - dups;
//create the size of the new array
int[] result = new int[size];
//populate the new array with the unique values
for (int i = 0; i < a1.length; i++) {
int count = 0;
for (int j = 0; j < a2.length; j++) {
if (a1[i] != a2[j]) {
count++;
if (count < 2) {
result[i] = a1[i];
}
}
}
}
return result;
}
I would also love how to solve this with potentially one loop (learning purposes).
I offer following soulution.
Iterate over first array, and find out min and max it's value.
Create temporary array with length max-min+1 (you could use max + 1 as a length, but it could follow overhead when you have values e.g. starting from 100k).
Iterate over first array and mark existed values in temorary array.
Iterate over second array and unmark existed values in temporary array.
Place all marked values from temporary array into result array.
Code:
public static int[] getUnique(int[] one, int[] two) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 0; i < one.length; i++) {
min = one[i] < min ? one[i] : min;
max = one[i] > max ? one[i] : max;
}
int totalUnique = 0;
boolean[] tmp = new boolean[max - min + 1];
for (int i = 0; i < one.length; i++) {
int offs = one[i] - min;
totalUnique += tmp[offs] ? 0 : 1;
tmp[offs] = true;
}
for (int i = 0; i < two.length; i++) {
int offs = two[i] - min;
if (offs < 0 || offs >= tmp.length)
continue;
if (tmp[offs])
totalUnique--;
tmp[offs] = false;
}
int[] res = new int[totalUnique];
for (int i = 0, j = 0; i < tmp.length; i++)
if (tmp[i])
res[j++] = i + min;
return res;
}
For learning purposes, we won't be adding new tools.
Let's follow the same train of thought you had before and just correct the second part:
// populate the new array with the unique values
for (int i = 0; i < a1.length; i++) {
int count = 0;
for (int j = 0; j < a2.length; j++) {
if (a1[i] != a2[j]) {
count++;
if (count < 2) {
result[i] = a1[i];
}
}
}
}
To this:
//populate the new array with the unique values
int position = 0;
for (int i = 0; i < a1.length; i++) {
boolean unique = true;
for (int j = 0; j < a2.length; j++) {
if (a1[i] == a2[j]) {
unique = false;
break;
}
}
if (unique == true) {
result[position] = a1[i];
position++;
}
}
I am assuming the "count" that you implemented was in attempt to prevent false-positive added to your result array (which would go over). When a human determines whether or not an array contains dups, he doesn't do "count", he simply compares the first number with the second array by going down the list and then if he sees a dup (a1[i] == a2[j]), he would say "oh it's not unique" (unique = false) and then stop going through the loop (break). Then he will add the number to the second array (result[i] = a1[i]).
So to combine the two loops as much as possible:
// Create a temp Array to keep the data for the loop
int[] temp = new int[a1.length];
int position = 0;
for (int i = 0; i < a1.length; i++) {
boolean unique = true;
for (int j = 0; j < a2.length; j++) {
if (a1[i] == a2[j]) {
unique = false;
break;
}
}
if (unique == true) {
temp[position] = a1[i];
position++;
}
}
// This part merely copies the temp array of the previous size into the proper sized smaller array
int[] result = new int[position];
for (int k = 0; k < result.length; k++) {
result[k] = temp[k];
}
Making your code work
Your code works fine if you correct the second loop. Look at the modifications I did:
//populate the new array with the unique values
int counter = 0;
for (int i = 0; i < a1.length; i++) {
for (int j = 0; j < a2.length; j++) {
if (a1[i] == a2[j]) {
result[counter] = a1[i];
counter++;
}
}
}
The way I would do it
Now, here is how I would create a method like this without the need to check for the duplicates more than once. Look below:
public static int[] removeDups(int[] a1, int[] a2) {
int[] result = null;
int size = 0;
OUTERMOST: for(int e1: a1) {
for(int e2: a2) {
if(e1 == e2)
continue OUTERMOST;
}
int[] temp = new int[++size];
if(result != null) {
for(int i = 0; i < result.length; i++) {
temp[i] = result[i];
}
}
temp[temp.length - 1] = e1;
result = temp;
}
return result;
}
Instead of creating the result array with a fixed size, it creates a new array with the appropriate size everytime a new duplicate is found. Note that it returns null if a1 is equal a2.
You can make another method to see if an element is contained in a list :
public static boolean contains(int element, int array[]) {
for (int iterator : array) {
if (element == iterator) {
return true;
}
}
return false;
}
Your main method will iterate each element and check if it is contained in the second:
int[] uniqueElements = new int[a1.length];
int index = 0;
for (int it : a1) {
if (!contains(it, a2)) {
uniqueElements[index] = it;
index++;
}
}

how to use recursion for nested 'for' loops

I have a problem with nested for loops in java. My problem is that at the beginning I don't know exactly how many for loops I will need. It is set somewhere in the middle of my program. So let say my program creates an array. If the array has 3 elements then I create a three for loops like below.
for(int i = 0; i<tab[0].length() ; i++){
for(int j = 0; j<tab[1].length() ; j++){
for(int k = 0; k<tab[2].length() ; k++){
System.out.println(i+" "+j+" "+k);
}
}
}
If my program created an array with 4 elements then it would be like this:
for(int i = 0; i<tab[0].length() ; i++){
for(int j = 0; j<tab[1].length() ; j++){
for(int k = 0; k<tab[2].length() ; k++){
for(int h = 0; h<tab[3].length() ; h++){
System.out.println(i+" "+j+" "+k+" "+h);
}
}
}
}
Can any one tell me how to do this with recursion? I can have 2 nested loops but I can have 10 of them and always at the end I would like to print in the console numbers associated with all loops (i,j,k,h)
Here is a solution. At each recursive call, previousTabs becomes 1 longer and tabs becomes 1 shorter.
public static void iterate(int[] previousValues, int[] tabs) {
if (tabs.length == 0) {
System.out.println(Arrays.toString(previousValues));
}
else {
final int[] values = new int[previousValues.length + 1];
for (int i = 0; i < previousValues.length; i++) {
values[i] = previousValues[i];
}
final int[] nextTabs = new int[tabs.length - 1];
for (int i = 0; i < nextTabs.length; i++) {
nextTabs[i] = tabs[i + 1];
}
for (int i = 0; i < tabs[0]; i++) {
values[values.length - 1] = i;
iterate(values, nextTabs);
}
}
}
public static void iterate(int[] tabs) {
iterate(new int[0], tabs);
}

Radix Sort an array of strings using a queue in Java

I don't completely understand radix sort so that is making this more difficult for me to write this program. I need to sort an array of strings that is read from a .txt file. I was able to read the file and enter the strings into an array. A string can contain letters or special characters. I need help with writing the code for sorting the array. It feels like I'm close to the having the correct code, but I'm stuck and don't know what else to do. It would be greatly appreciated if I could get help and point me in the right direction.
Each string has the same amount of characters. I am also using a stackPackage that contains a queue class. I need to modify the code the my professor gave me to sort strings.
Here is the code I started with:
import queuepackage.*;
public class Radix {
public static void main(String[] args) {
int[] array = {143,934,782,687,555,222,111,213,842,2000};
printArray(array);
radixSort(array, 1000);
printArray(array);
}
public static void printArray(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + ", ");
}
System.out.println();
}
public static void radixSort(int[] array, int maxPowerOf10) {
Queue[] queueArray = new Queue[10];
for (int queueNum = 0; queueNum < 10; queueNum++) {
queueArray[queueNum] = new Queue();
}
for (int powerOf10 = 1; powerOf10 <= maxPowerOf10; powerOf10 = powerOf10 * 10) {
for (int item = 0; item < array.length; item++) {
int digit = getDigit(array[item], powerOf10);
queueArray[digit].enqueue(new Integer(array[item]));
}
int item = 0;
for (int queueNum = 0; queueNum < 10; queueNum++) {
while (!queueArray[queueNum].isEmpty()) {
array[item] = ((Integer) queueArray[queueNum].dequeue()).intValue();
item++;
}
}
}
}
public static int getDigit(int number, int powerOf10) {
return (number/powerOf10)%10;
}
}
This is what I have.
length = length of the array
wordLen = length of a string in the array
Here is my current code of the radixSort method:
public static void radixSort(String[] array, int length, int wordLen) {
Queue[] queueArray = new Queue[256];
for (int queueNum = 0; queueNum < 256; queueNum++) {
queueArray[queueNum] = new Queue();
}
for (int len = 0; len < wordLen; len++) {
for (int item = 0; item < length; item++) {
int letter = array[item].charAt(len);
queueArray[letter].enqueue(new String(array[item]));
}
int item = 0;
for (int queueNum = 0; queueNum < 256; queueNum++) {
while (!queueArray[queueNum].isEmpty()) {
array[item] = ((String) queueArray[queueNum].dequeue()).toString();
item++;
}
}
}
}
It's almost working, you just need to iterate the word backwards, look at the second for loop
public static void radixSort(String[] array, int length, int wordLen) {
Queue[] queueArray = new Queue[256];
for (int queueNum = 0; queueNum < 256; queueNum++) {
queueArray[queueNum] = new Queue();
}
for (int len = wordLen-1; len >= 0; len--) {
for (int item = 0; item < length; item++) {
int letter = array[item].charAt(len);
queueArray[letter].enqueue(new String(array[item]));
}
int item = 0;
for (int queueNum = 0; queueNum < 256; queueNum++) {
while (!queueArray[queueNum].isEmpty()) {
array[item] = ((String) queueArray[queueNum].dequeue()).toString(); // Here you need to swap the
item++;
}
}
}
}
If you iterate it in the regular way you are losing the previous information, so the last characters are the most important
Good luck!
The only mistake in your code that I can see is that in RadixSort you wanna start with sorting by the least significant digit and move up to more significant digits as you go. In this case however you are starting at the left and going right which is the wrong way around for natural order String sorting.
This however can be easily fixed by changing for (int len = 0; len < wordLen; len++) into for (int len = wordLen - 1; len >= 0; len--).
Changing for (int len = 0; len < wordLen; len++) into for (int len = wordLen - 1; len >= 0; len--) worked and makes my program does what it is supposed to

Finding uniques integers in an array

i have an array of integers like this one :
A={1,1,4,4,4,1,1}
i want to count the each number once , for this example the awnser is 2 becuase i want to count 1 once and 4 once
i dont want to use sorting methods
i am unable to find a way to solve it using java.
i did this but it gives me 0
public static void main(String args[]) {
int a[] = { 1,1,4,4,4,4,1,1};
System.out.print(new Test4().uniques(a));
}
public int uniques(int[] a) {
int unique = 0;
int tempcount = 0;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a.length; j++) {
if (a[i] == a[j]) {
tempcount++;
}
}
if (tempcount <= 2) {
unique=a[i];
}
tempcount = 0;
}
return unique;
}
the purpose of the question is to understand the logic of it but not solving it using ready methods or classes
This one should work. I guess this might be not the most elegant way, but it is pretty straightforward and uses only simple arrays. Method returns number of digits from array, but without counting duplicates - and this I believe is your goal.
public int uniques(int[] a) {
int tempArray[] = new int[a.length];
boolean duplicate = false;
int index = 0;
int digitsAdded = 0;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < tempArray.length; j++) {
if (a[i] == tempArray[j]) {
duplicate = true;
}
}
if(!duplicate) {
tempArray[index] = a[i];
index++;
digitsAdded++;
}
duplicate = false;
}
//this loop is needed if you have '0' in your input array - when creating temp
//array it is filled with 0s and then any 0 in input is treated as a duplicate
//again - not most elegant solution, maybe I will find better later...
for(int i = 0; i < a.length; i++) {
if(a[i] == 0) {
digitsAdded++;
break;
}
}
return digitsAdded;
}
Okay first of all in your solution you are returning the int unique, that you are setting as the value that is unique a[i]. So it would only return 1 or 4 in your example.
Next, about an actual solution. You need to check if you have already seen that number. What you need to check is that for every number in the array is only appears in front of your position and not before. You can do this using this code below.
public int uniques(int[] a) {
int unique = 1;
boolean seen = false;
for (int i = 1; i < a.length; i++) {
for (int j = 0; j < i; j++) {
if (a[i] == a[j]) {
seen = true;
}
}
if (!seen) {
unique++;
}
seen = false;
}
return unique;
}
In this code you are iterating over the number you have seen and comparing to the number you are checking (a[i]). You know that for it to be unique you cant have seen it before.
I see two possible solutions:
using set
public int unique(int[] a) {
Set<Integer> set = new HashSet<>();
for (int i : a) {
set.add(i);
}
return set.size();
}
using quick sort
public int unique(int[] a) {
Arrays.sort(a);
int cnt = 1;
int example = a[0];
for (int i = 1; i < a.length; i++) {
if (example != a[i]) {
cnt++;
example = a[i];
}
}
return cnt;
}
My performance tests say that second solution is faster ~ 30%.
if restricted to only arrays, consider trying this:
Lets Take a temporary array of the same size of orignal array, where we store each unique letter and suppose a is your orignal array,
int[] tempArray= new int[a.length];
int tempArraycounter = 0;
bool isUnique = true;
for (int i = 0; i < a.length; i++)
{
isUnique = true;
for (int j = 0; j < tempArray.length; j++)
{
if(tempArray[j] == a[i])
isUnique = false;
}
if(isUnique)
{
tempArray[tempArraycounter] = a[i];
tempArraycounter++;
isUnique = false;
}
}
now tempArraycounter will be your answer ;)
Try Following code:
int test[]={1,1,4,4,4,1,1};
Set<Integer> set=new LinkedHashSet<Integer>();
for(int i=0;i<test.length;i++){
set.add(test[i]);
}
System.out.println(set);
Output :
[1, 4]
At the end set would contain unique integers.

Categories

Resources