时间:2011-01-19 22:47:42

标签: java algorithm

新程序员在这里。我观看了一个显示LCS(最长公共子串)的递归算法的视频。程序只返回一个int,它是两个字符串之间LCS的长度。我决定作为练习来调整算法以返回字符串本身。这是我提出的,似乎是正确的,但如果有任何错误,我需要让其他人更有经验;

const int mAX=1001; //max size for the two strings to be compared
string soFar[mAX][mAX]; //keeps results of strings generated along way to solution
bool Get[mAX][mAX]; //marks what has been seen before(pairs of indexes)

class LCS{ //recursive version,use of global arrays not STL maps
private: 
public:
 string _getLCS(string s0,int k0, string s1,int k1){
  if(k0<=0 || k1<=0){//base case
   return "";
  }  
  if(!Get[k0][k1]){ //checking bool memo to see if pair of indexes has been seen before
   Get[k0][k1]=true; //mark seen pair of string indexs
   if(s0[k0-1]==s1[k1-1]){
    soFar[k0][k1]=s0[k0-1]+_getLCS(s0,k0-1,s1,k1-1);//if the char in positions k0 and k1 are equal add common char and move on
   }
   else{
    string a=_getLCS(s0,k0-1,s1,k1);//this string is the result from keeping the k1 position the same and decrementing the k0 position
    string b=_getLCS(s0,k0,s1,k1-1);//this string is the result from decrementing the k1 position keeping k0 the same
    if(a.length()> b.length())soFar[k0][k1]=a;//the longer string is the one we are interested in
    else
     soFar[k0][k1]=b;
   }
  } 
  return soFar[k0][k1];
 }
 string LCSnum(string s0,string s1){
  memset(Get,0,sizeof(Get));//memset works fine for zero, so no complaints please
  string a=_getLCS(s0,s0.length(),s1,s1.length());
  reverse(a.begin(),a.end());//because I start from the end of the strings, the result need to be reversed
  return a;
 }
};

我只编程了6个月,所以我无法确定是否存在一些错误或情况,此算法无效。它似乎适用于两个大小不超过1001个字符串的字符串。

有什么错误,等效的动态编程解决方案会更快或者使用更少的内存来获得相同的结果吗?

由于

1 个答案:

答案 0 :(得分:0)

  1. 您的程序不正确。 LCSnum(“aba”,“abba”)的回报是什么?

  2. string soFar[mAX][mAX]应该暗示这不是一个好方法。一个简单的动态编程解决方案(它具有你几乎遵循的逻辑)有一个size_t数组,其大小为m * n,也没有bool Get[mAX][mAX]。 (更好的动态编程算法只有2 * min(m,n)的数组。)

  3. 编辑:顺便说一句,这是Java中节省空间的动态编程解决方案。复杂度:时间是O(m * n),空间是O(min(m,n)),其中m和n是字符串的长度。结果集按字母顺序给出。

    import java.util.Set;
    import java.util.TreeSet;
    
    class LCS {
        public static void main(String... args) {
            System.out.println(lcs(args[0], args[1]));
        }
    
        static Set<String> lcs(String s1, String s2) {
            final Set<String> result = new TreeSet<String>();
    
            final String shorter, longer;
            if (s1.length() <= s2.length()) {
                shorter = s1;
                longer = s2;
            }else{
                shorter = s2;
                longer = s1;
            }
    
            final int[][] table = new int[2][shorter.length()];
            int maxLen = 0;
    
            for (int i = 0; i < longer.length(); i++) {
                int[] last = table[i % 2]; // alternate
                int[] current = table[(i + 1) % 2];
                for (int j = 0; j < shorter.length(); j++) {
                    if (longer.charAt(i) == shorter.charAt(j)) {
                        current[j] = (j > 0? last[j - 1] : 0) + 1;
    
                        if (current[j] > maxLen) {
                            maxLen = current[j];
                            result.clear();
                        }
                        if (current[j] == maxLen) {
                            result.add(shorter.substring(j + 1 - maxLen, j + 1));
                        }
                    }
                }
            }
    
            return result;
        }
    }