Java Trie数据结构在寻找最优解中的应用

Java Trie数据结构在寻找最优解中的应用,java,algorithm,data-structures,tree,trie,Java,Algorithm,Data Structures,Tree,Trie,这个问题是正在进行的竞争的一部分,我已经解决了这个问题数据集的75%,但25%给了我TLE。我在问为什么它给了TLE一个我确信我的复杂性是O(n*n)问题: 由N个小写英文字母组成的字符串S。我们准备了一个列表L,其中包含字符串S的所有非空子字符串 现在他问你问题。要解决第i个问题,您需要计算从列表L中选择完全相等的字符串的方法的数量 例如: String = ababa L = {"a", "b", "a", "b", "a", "ab", "ba", "ab", "ba", "ab

这个问题是正在进行的竞争的一部分,我已经解决了这个问题数据集的75%,但25%给了我TLE。我在问为什么它给了
TLE
一个我确信我的复杂性是
O(n*n)

问题:

由N个小写英文字母组成的字符串S。我们准备了一个列表L,其中包含字符串S的所有非空子字符串


现在他问你问题。要解决第i个问题,您需要计算从列表L中选择完全相等的字符串的方法的数量

例如:

    String  = ababa
L = {"a", "b", "a", "b", "a", "ab", "ba", "ab", "ba", "aba", "bab", "aba", "abab", "baba", "ababa"}.
k1 = 2: There are seven ways to choose two equal strings ("a", "a"), ("a", "a"), ("a", "a"), ("b", "b"), ("ab", "ab"), ("ba", "ba"), ("aba", "aba").
k2 = 1: We can choose any string from L (15 ways).
k3 = 3: There is one way to choose three equal strings - ("a", "a", "a").
k4 = 4: There are no four equal strings in L .



我的方法

我正在对它进行TRIE,并计算和数组F[I]其中F[I]表示相等字符串出现的次数。 我的朋友:

我的插入功能

 public static void  Insert(String S,int[] F , int start){

     Batman temp = Root;
     for(int i=start;i<S.length();i++){
         int index = S.charAt(i)-'a';

         if(temp.next[index]==null){
             temp.next[index] = new Batman(1);
             F[1]+=1;

         }else{
             temp.next[index].value+=1;
             int xx = temp.next[index].value;
             F[xx-1]-=1;
             F[xx]+=1;

            // Calculating The Frequency of I equal Strings
         }
         temp = temp.next[index];
     }

 }
publicstaticvoidinsert(字符串S,int[]F,int start){
蝙蝠侠温度=根;

对于(int i=start;i此程序获得TLE的一个原因(请记住,时间限制为1秒):

每次创建一个
Batman
对象时,它都会创建一个长度为[26]的数组,这相当于添加一个n=26的循环

所以,你的时间复杂度是26*5000*5000=650000000=6.5*10^8次运算,理论上,如果CPU速度是每秒10^9次运算,它仍然可以满足时间限制,但也要记住,这之后会有一些繁重的计算,所以,这应该是原因

为了解决这个问题,我使用并被接受了:

实际的代码非常复杂,所以我们的想法是,您有一个表
count[i][j]
,它是匹配子字符串(i,j)的子字符串的数量。使用Z算法,您的时间复杂度可以是O(n^2)

对于每个字符串
s

        int n = in.nextInt();
        int q = in.nextInt();
        String s = in.next();
        int[][] cur = new int[n][];
        int[][] count = new int[n][n];
        int[] length = new int[n];
        for (int i = 0; i < n; i++) {
            cur[i] = Z(s.substring(i).toCharArray());//Applying Z algorithm
            for (int j = 1; j < cur[i].length; j++) {
                if (cur[i][j] > length[j + i]) {
                    for (int k = i + length[j + i]; k < i + cur[i][j]; k++) {
                        count[i][k]++;
                    }
                    length[j + i] = cur[i][j];
                }

            }
        }
        int[] F = new int[n + 1];
        for(int i = 0; i < n; i++){
            for(int j = i; j < n; j++){
                int v = count[i][j] + (length[i] < (j - i + 1) ? 1 : 0);
                F[v]++;
            }
        }
对于下面的循环,我们注意到,如果子字符串(i,j)有一个匹配项,
length[i]>=子字符串(i,j)的长度
,但是如果没有匹配项,我们需要添加1来计算子字符串(i,j),因为这个子字符串是唯一的

        for(int j = i; j < n; j++){
            int v = count[i][j] + (length[i] < (j - i + 1) ? 1 : 0);
            F[v]++;
        }
for(int j=i;j
一定要记住
10n*n
1000000n*n
两者都是
O(n*n)
@azurefrog我无法理解你,请解释一下当你思考时,尤其是当你尝试时,你需要记住当n很小时(就像你的例子中那样),与n较大时相比,二次项在总时间中的主导作用要小得多。仅仅因为程序是O(n*n)并不意味着它运行得很快,只是其运行时的比例将随输入大小的平方而变化。如果您查看我的
Insert
函数,它是O(n)我在我的主函数中多次调用它,所以总体上
O(n*n)
@user4996457您的回答是正确的,刚刚更新了我的回答,那么应该遵循哪种数据结构或方法我不知道Z算法,如果发现问题,我会学习它并锁定您,但我在本地计算机上的Trie解决方案在大数据上运行良好set@user4996457这个问题在时间限制上非常紧迫:)
        int n = in.nextInt();
        int q = in.nextInt();
        String s = in.next();
        int[][] cur = new int[n][];
        int[][] count = new int[n][n];
        int[] length = new int[n];
        for (int i = 0; i < n; i++) {
            cur[i] = Z(s.substring(i).toCharArray());//Applying Z algorithm
            for (int j = 1; j < cur[i].length; j++) {
                if (cur[i][j] > length[j + i]) {
                    for (int k = i + length[j + i]; k < i + cur[i][j]; k++) {
                        count[i][k]++;
                    }
                    length[j + i] = cur[i][j];
                }

            }
        }
        int[] F = new int[n + 1];
        for(int i = 0; i < n; i++){
            for(int j = i; j < n; j++){
                int v = count[i][j] + (length[i] < (j - i + 1) ? 1 : 0);
                F[v]++;
            }
        }
public static int[] Z(char[] s) {
    int[] z = new int[s.length];
    int n = s.length;
    int L = 0, R = 0;
    for (int i = 1; i < n; i++) {
        if (i > R) {
            L = R = i;
            while (R < n && s[R - L] == s[R])
                R++;

            z[i] = R - L;

            R--;
        } else {
            int k = i - L;
            if (z[k] < R - i + 1) {
                z[i] = z[k];
            } else {
                L = i;
                while (R < n && s[R - L] == s[R])
                    R++;
                z[i] = R - L;
                R--;
            }
        }
    }
    return z;
}
        for (int j = 1; j < cur[i].length; j++) {
            if (cur[i][j] > length[j + i]) {
                for (int k = i + length[j + i]; k < i + cur[i][j]; k++) {
                    count[i][k]++;
                }
                length[j + i] = cur[i][j];
            }          
        }
        for(int j = i; j < n; j++){
            int v = count[i][j] + (length[i] < (j - i + 1) ? 1 : 0);
            F[v]++;
        }