5

When I define my array strings in this way:

String[] X = {"X","M","J","Y","A","U","Z"};
String[] Y = {"M","Z","J","A","W","X","U"};

my code works and it prints [M, J, A, U] which is the longest common subsequence of X and Y but when I define text files for the string arrays, which have the same input, then my code prints an empty array []. How can I solve this?

    public class LCS   {
    // Function to find LCS of String X[0..m-1] and Y[0..n-1]
    public static String A(String[] x, String[] y, int m, int n, int[][] T)
    {
        // return empty string if we have reached the end of
        // either sequence
        if (m == 0 || n == 0) {
            return new String();
        }
        // if last character of X and Y matches
        if (x[m - 1] == y[n - 1])
        {
            // append current character (X[m-1] or Y[n-1]) to LCS of
            // substring X[0..m-2] and Y[0..n-2]
            return A(x, y, m - 1, n - 1, T) + x[m - 1];
        }

        // else when the last character of X and Y are different

        // if top cell of current cell has more value than the left
        // cell, then drop current character of String X and find LCS
        // of substring X[0..m-2], Y[0..n-1]

        if (T[m - 1][n] > T[m][n - 1]) {
            return A(x, y, m - 1, n, T);
        }
        else {
            // if left cell of current cell has more value than the top
            // cell, then drop current character of String Y and find LCS
            // of substring X[0..m-1], Y[0..n-2]

            return A(x, y, m, n - 1, T);
        }
    }

    // Function to fill lookup table by finding the length of LCS
    // of substring X[0..m-1] and Y[0..n-1]
    public static void LCSLength(String[] x, String[] y, int m, int n, int[][] T)
    {
        // fill the lookup table in bottom-up manner
        for (int i = 1; i <= m; i++)
        {
            for (int j = 1; j <= n; j++)
            {

                // if current character of X and Y matches
                if (x[i - 1] == y[j - 1]) {
                    T[i][j] = T[i - 1][j - 1] + 1;
                }

                // else if current character of X and Y don't match
                else {
                    T[i][j] = Integer.max(T[i - 1][j], T[i][j - 1]);
                }
            }
        }
    }

    // main function
    public static void main(String[] args) throws IOException
    {
         String[] X =  read("C:\\Users\\fener\\Desktop\\producerconsumer\\Yeni Metin Belgesi.txt");
         String[] Y = read("C:\\Users\\fener\\Desktop\\producerconsumer\\Yeni Metin Belgesi (2).txt");

        //String[] X = {"X","M","J","Y","A","U","Z"}, Y = {"M","Z","J","A","W","X","U"};
        int m = X.length, n = Y.length;


        // T[i][j] stores the length of LCS of substring
        // X[0..i-1], Y[0..j-1]
        int[][] T = new int[m + 1][n + 1];

        // fill lookup table
        LCSLength(X, Y, m, n, T);

        String[] arr = A(X, Y, m, n, T).split("");
        // find longest common sequence
        System.out.print(Arrays.toString(arr));
        System.exit(0);
    }
    private static String[] read(String location) throws IOException {
        BufferedReader reader1 = new BufferedReader(new FileReader(location));
        String line;
        ArrayList<String> lines = new ArrayList<String>();
        while ((line = reader1.readLine()) != null) {
            lines.add(line);
        }
        reader1.close();
        String[] result = new String[lines.size()];
        for(int i=0; i<lines.size(); i++) {
            result[i] = lines.get(i);
        }
        return result;  
    }
    }
dems98
  • 814
  • 3
  • 9
  • 22
John Montana
  • 175
  • 10

2 Answers2

4

You should use Object#equals(Object anotherObject) method to compare strings or, in general, every object.
In your code, you are using == operator which will compare the strings references (if they are the same String instance) instead of their value.
Your code worked (when using Array initializer) because you initialized the String array with literals and two identical literals will be the same instance.
When you read a line in a file with readLine(), It creates a new String so two lines with the same content will result in two strings with the same value but different instances.
So, when comparing strings, use equals and your code will work.
See also: What is the difference between == and equals() in Java?

dems98
  • 814
  • 3
  • 9
  • 22
2

Here are some pointers:

In Java there is a difference in instantiating a String with the "" and by using the new String() constructor.

For example:

// Example 1
String a = "Y";
String b = "Y";
boolean result1 = a == b; // true

// Example 2
String c = new String("Y");
String d = new String("Y");
boolean result2 = c == d; // false

This happens because when you create a String using "Y", the actual object is allocated in a separate place in the heap called String Constant Pool. Any subsequent allocation of "Y" will return a reference to the same object in the String Constant Pool.

When you use new String("Y") you are saying that you want a completely new String object instance to be allocated in the common heap.

The == operator compares 2 objects to determine if they reference the same object instance, which in this case will be different as the Example 2 demonstrates.

For the presented code, the necessary changes are:

In A method

// return empty string if we have reached the end of
// either sequence
if (m == 0 || n == 0) {
    return "";
}
...

// if last character of X and Y matches
if (Objects.equals(x[m - 1], y[n - 1])) {
...

In LCSLength method

// if current character of X and Y matches
if (Objects.equals(x[i - 1], y[j - 1])) {
...

Here java.util.Objects.equals safely compares with == then equals().

By applying these changes the result is:

[M, J, A, U]

And lastly the read method do not need to be changed but could be simplified by using java.nio API:

private static String[] read(String folder, String filename) throws IOException {
    Path path = Paths.get(folder, filename);
    List<String> lines = Files.readAllLines(path);
    return lines.toArray(new String[0]);
}
rbento
  • 9,919
  • 3
  • 61
  • 61