求最长公共子序列

2018-03-11  本文已影响10人  Stroman

问题

给出两个字符串,求出它们之中相对顺序相同,字符相同的最长的公共子序列。

用法

package com.company;

public class Main {

    public static void main(String[] args) {
    // write your code here
        String string0 = "abcicba";
        String string1 = "abdkscab";
        System.out.println(Solution.findLongestSubsequence(string0,string1));
    }
}

输出

解集:
1 1 1 1 1 1 1 1 
1 2 2 2 2 2 2 2 
1 2 2 2 2 3 3 3 
1 2 2 2 2 3 3 3 
1 2 2 2 2 3 3 3 
1 2 2 2 2 3 3 4 
1 2 2 2 2 3 4 4 
最长公共子序列长度为:4
倒序输出最长子序列:ab<>c<>a

Process finished with exit code 0

代码实现

package com.company;

public class Solution {
    /**
     * 查找两个字符串的最长公共子序列。
     * 所谓最长公共子序列,需要满足两个条件。
     * 1、它包含的字符相同。
     * 2、相对顺序相同。
     * 最长公共子序列并不是最长公共子串
     * 二者的区别很大。
     * 很简单如果矩阵对应的两个字符不相等,该单元格的值就等于它上面的和左边的较大的单元格的值。
     * 如果相等,就等于左上角单元格的值+1。
     * 本问题需要输出那个子序列,这个有点麻烦,从解集可以看出来
     * 不一定相等就是最长公共子序列的开始。
     * 所以用单链表的回溯法可以打印出最长公共子序列。
     * 把其中重复的结点合并作为间隔符<>来显示
     * @param string0
     * @param string1
     * @return
     */
    static public String findLongestSubsequence(String string0,String string1) {
        if (string0.length() == 0 || string1.length() == 0)return "";
        SingleLinker[][] answerArray = new SingleLinker[string0.length()][string1.length()];
        for (int counter = 0;counter < string0.length();counter++) {
            for (int counter0 = 0;counter0 < string1.length();counter0++) {
                answerArray[counter][counter0] = new SingleLinker(counter,counter0);
                if (string0.charAt(counter) == string1.charAt(counter0)) {
                    if (counter - 1 >= 0 && counter0 - 1 >= 0) {
                        answerArray[counter][counter0].setEqualCounter(answerArray[counter - 1][counter0 - 1].getEqualCounter() + 1);
                        answerArray[counter][counter0].prePointer = answerArray[counter - 1][counter0 - 1];
                    }
                    else answerArray[counter][counter0].setEqualCounter(1);
                }
                else {
                    if (counter - 1 >= 0 && counter0 - 1 < 0) {
                        answerArray[counter][counter0].setEqualCounter(answerArray[counter - 1][counter0].getEqualCounter());
                        answerArray[counter][counter0].prePointer = answerArray[counter - 1][counter0];
                    }
                    else if (counter - 1 < 0 && counter0 - 1 >= 0) {
                        answerArray[counter][counter0].setEqualCounter(answerArray[counter][counter0 - 1].getEqualCounter());
                        answerArray[counter][counter0].prePointer = answerArray[counter][counter0 - 1];
                    }
                    else if (counter - 1 < 0 && counter0 - 1 < 0)
                        answerArray[counter][counter0].setEqualCounter(0);
                    else {
                        if (answerArray[counter - 1][counter0].getEqualCounter() > answerArray[counter][counter0 - 1].getEqualCounter()) {
                            answerArray[counter][counter0].setEqualCounter(answerArray[counter - 1][counter0].getEqualCounter());
                            answerArray[counter][counter0].prePointer = answerArray[counter - 1][counter0];
                        } else {
                            answerArray[counter][counter0].setEqualCounter(answerArray[counter][counter0 - 1].getEqualCounter());
                            answerArray[counter][counter0].prePointer = answerArray[counter][counter0 - 1];
                        }
                    }
                }
            }
        }
        System.out.println("解集:");
        for (int counter = 0;counter < string0.length();counter++) {
            for (int counter0 = 0;counter0 < string1.length();counter0++) {
                System.out.print(answerArray[counter][counter0].getEqualCounter() + " ");
            }
            System.out.println();
        }
        System.out.println("最长公共子序列长度为:" + answerArray[string0.length() - 1][string1.length() - 1].getEqualCounter());
        System.out.print("倒序输出最长子序列:");
        SingleLinker currentNode = answerArray[string0.length() - 1][string1.length() - 1];
        SingleLinker[] nodeStack = new SingleLinker[answerArray[string0.length() - 1][string1.length() - 1].getEqualCounter()];
        int nodeStackPointer = -1;
        while (currentNode != null && currentNode.getEqualCounter() > 0) {
            if (nodeStackPointer == -1 || nodeStack[nodeStackPointer].getEqualCounter() != currentNode.getEqualCounter())
                nodeStack[++nodeStackPointer] = currentNode;
            else {
                nodeStack[nodeStackPointer] = currentNode;
                nodeStack[nodeStackPointer].setHasDivider(true);
            }
            currentNode = currentNode.prePointer;
        }
        //逆转单链表
        StringBuilder longestSubsequence = new StringBuilder();
        while (nodeStackPointer > -1) {
            longestSubsequence.append(string0.charAt(nodeStack[nodeStackPointer].getX()));
            if (nodeStack[nodeStackPointer].isHasDivider() && nodeStackPointer != 0)longestSubsequence.append("<>");
            nodeStackPointer--;
        }
        return longestSubsequence.toString();
    }
}

package com.company;

public class SingleLinker {
    private int x = -1;
    private int y = -1;
    private int equalCounter = 0;
    private boolean hasDivider = false;
    public SingleLinker prePointer = null;

    public SingleLinker(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getEqualCounter() {
        return equalCounter;
    }

    public void setEqualCounter(int equalCounter) {
        this.equalCounter = equalCounter;
    }

    public boolean isHasDivider() {
        return hasDivider;
    }

    public void setHasDivider(boolean hasDivider) {
        this.hasDivider = hasDivider;
    }
}

上一篇下一篇

猜你喜欢

热点阅读