I've implemented a DP algorithm that finds the longest common subsequence in three arrays. The problem though, is that my algorithm doesn't work when the arrays are of different lengths, and I have no idea why. From what I can tell, my algorithm is correct, so I think it's something to do with the Java implementation. Here is my Java code:
static int[] lcsOf3(int[] X, int[] Y, int[] Z, int xLength, int yLength, int zLength) {
int[][][] S = new int[xLength + 1][yLength + 1][zLength + 1];
for (int i = 0; i <= xLength; i++) {
for (int j = 0; j <= yLength; j++) {
for (int k = 0; k <= zLength; k++) {
if (i == 0 || j == 0 || k == 0) {
S[i][j][k] = 0;
} else if (X[i - 1] == Y[j - 1] && X[i - 1] == Z[k - 1]) {
S[i][j][k]= S[i - 1][j - 1][k - 1] + 1;
} else {
S[i][j][k] = Math.max(Math.max(S[i - 1][j][k], S[i][j - 1][k]), S[i][j][k - 1]);
}
}
}
}
System.out.println(S[xLength][yLength][zLength]);
}
I took another look at my code,and it turns out that it was something with my implementation, not the algorithm itself. There was a bug in the part of my code that gets the input arrays(X,Y,Z). After fixing the bug, it works correctly on lists of different sizes.
Thanks to everyone who tried to help out, and sorry for wasting your time.
Related
I'm working on the 3sum problem. I did it by sorting the array in the beginning and then using two pointer method to find all the unique triplets in the array which gives the sum of zero.
My question is that if I comment out the two while loops at the end, the runtime can be improved from 32ms to 26ms. I get a 6 ms speed boost. I think the time complexity is still O(n^2). Does anyone know why commenting out the while loops is faster?
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new LinkedList<List<Integer>>();
if(nums.length < 3){
return result;
}
int left = 0;
int right = nums.length - 1;
int threeSum = 0;
Arrays.sort(nums);
for (int i = 0; i < nums.length - 2 && nums[i] <= 0; i ++) {
right = nums.length - 1;
if (i > 0) {
while (i < right && nums[i - 1] == nums[i])
i ++;
}
left = i + 1;
while (left < right) {
threeSum = nums[i] + nums[left] + nums[right];
if (threeSum == 0) {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
left ++;
right --;
while (left < right && nums[left - 1] == nums[left])
left ++;
while (left < right && nums[right + 1] == nums[right])
right --;
} else if (threeSum < 0) {
// move to the right
left ++;
// Skip duplicate numbers
// Comment this out get 6 ms speed increase
while (left < right && nums[left - 1] == nums[left])
left ++;
} else {
right --;
// Skip duplicate numbers
// Comment this out get 6 ms speed increase
while (left < right && nums[right + 1] == nums[right])
right --;
}
}
}
return result;
}
This code prints out the biggest temperature fluctuation of the array in two consecutive days.
But I don't really understand, what happens in the if statements.
Would someone please be so kind to explain it to me?
public class NurTests {
public static void main(String[] args) {
int[] temperature = { 12, 14, 9, 12, 15, 16, 15, 15, 11, 8, 13, 13, 15, 12 };
int maxTempDiff = 0;
int foundDay = 0;
for (int i = 0; i < temperature.length; i++) {
int newMaxDiff = 0;
if ((i + 1) < temperature.length) {
if (temperature[i] < temperature[i + 1]) {
newMaxDiff = temperature[i + 1] - temperature[i];
}
if (temperature[i] >= temperature[i + 1]) {
newMaxDiff = temperature[i] - temperature[i + 1];
}
if (maxTempDiff < newMaxDiff) {
maxTempDiff = newMaxDiff;
foundDay = i;
}
}
}
}
}
Thanks in advance.
I've added some comments - should help.
// Make sure we don't access beyond the length of the array.
if ((i + 1) < temperature.length) {
// Is this temp less than the next one?
if (temperature[i] < temperature[i + 1]) {
// New max diff is next minus this.
newMaxDiff = temperature[i + 1] - temperature[i];
}
// Is this temp greater than or equal to the next one?
if (temperature[i] >= temperature[i + 1]) {
// New max diff is this minus next.
newMaxDiff = temperature[i] - temperature[i + 1];
}
// Is the new temp diff the greatest so far?
if (maxTempDiff < newMaxDiff) {
maxTempDiff = newMaxDiff;
foundDay = i;
}
}
#OldCurmudgeon answered the question already, but perhaps you could make use of some additional comments:
the if ((i + 1) < temperature.length) can be eliminated by running the loop until i < temperature.length-1: this way i+1 will be a valid index for the array all the time, and thus no check is necessary
the first two indented if-s deal with temperature rise and drop, and for both kind of change they provide a positive number at the end. There is a mathematical function for that, absolute value, Math.abs in Java.
Combined together:
for (int i = 0; i < temperature.length - 1; i++) {
int newMaxDiff = Math.abs(temperature[i] - temperature[i + 1]);
if (maxTempDiff < newMaxDiff) {
maxTempDiff = newMaxDiff;
foundDay = i;
}
}
Basically I replaced n with aData[i] in the Non-working implementation. Am I missing something fundamentally wrong? The Second implementation fails on the same TEST Data.
Passing implementation:
static long[] sort(long[] aData) {
for (int i = 1; i < aData.length; i++) {
long n = aData[i];
int j = i - 1;
while (j >= 0 && aData[j] > n) {
aData[j + 1] = aData[j];
j--;
}
aData[j + 1] = n;
}
return aData;
}
Failing implementation:
static long[] sort(long[] aData) {
for (int i = 1; i < aData.length; i++) {
int j = i - 1;
while (j >= 0 && aData[j] > aData[i]) {
aData[j + 1] = aData[j];
j--;
}
aData[j + 1] = aData[i];
}
return aData;
}
In the first iteration of the while loop, j + 1 == i. So when you write aData[j + 1] = aData[j], you change the value of aData[i] within the loop.
In the initial version, n is constant throughout the operation. Also note that using aData[i] instead of n is very unlikely to improve performance (if anything, it will probably be slower).
This question already has answers here:
How can I avoid ArrayIndexOutOfBoundsException or IndexOutOfBoundsException? [duplicate]
(2 answers)
Closed 7 years ago.
Help me to solve this error. This code is for Gutherine series.Consider the following algorithm
Start with a positive number n
if n is even then divide by 2
if n is odd then multiply by 3 and add 1
continue this until n becomes 1
public class Gutherine {
public static void main(String[] args) {
int a[] = {8, 3,2, 1};
int result = isGutherineSequence(a);
System.out.println(result);
}
public static int isGutherineSequence(int a[]) {
int i = 0;
int t = 0;
for (i = 0; i < 4; i++) {
if (a[i] % 2 == 0) {
if (a[i + 1] == a[i] / 2) {
t++;
}
} else if (a[i + 1] == a[i] * 3 + 1) {
t++;
}
}
if (t == 3) {
return 1;
} else {
return 0;
}
}
}
Since inside your loop you access a[i+1], you should iterate i until the next to last element, so change
for (i = 0; i < 4; i++)
to
for (i = 0; i < a.length - 1; i++)
BTW, you don't need the t counter. Once you discover that the series is not a Gutherine sequence, you can return false. You also fail to check that the last element is 1. And you should return a boolean instead of 0 or 1.
Here's a suggested implementation :
public static boolean isGutherineSequence(int a[]) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] % 2 == 0) {
if (a[i + 1] != a[i] / 2) {
return false;
}
} else if (a[i + 1] != a[i] * 3 + 1) {
return false;
}
}
return (a[a.length - 1] == 1);
}
The exception is caused by your referring to
a[i + 1]
If a[i] could be any element of the array, a[i + 1] could be one to the right of the rightmost element. So your array index would be out of bounds in that case.
The out-of-bounds exception results from your the indirection a[i + 1] even when i is odd. The loop in your isGutherineSequence function will let i reach 3 and the offending line
} else if (a[i + 1] == a[i] * 3 + 1) {
Will effectively try to extract a non-existent a[4].
You should either stop the loop at a previous spot or provide an alternate test for the last element.
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;
}
}
}