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;  
    }
    }
5
  • Take care of java naming conventions. Method names should start with lower case character Commented Dec 15, 2019 at 16:05
  • Also you should learn how to use a debugger. It will help you to find the error Commented Dec 15, 2019 at 16:06
  • How are your text files structured? Commented Dec 15, 2019 at 16:12
  • @Demetrio each line has one letter Commented Dec 15, 2019 at 16:20
  • Your question presents a lot of code and is quite certainly not a minimal example. Please try to shorten the code in your questions to the bare minimum. Often, you’ll find that while preparing a really good questions, you suddenly find the answer yourself. Commented Dec 15, 2019 at 18:06

2 Answers 2

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?

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the information. It made me understand it
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]);
}

2 Comments

Thank you. I did everything you stated but this time I get the last element of the first textfile
Only 3 changes to your code were necessary. Two in A method and one in LCSLength method. See my updated post.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.