簡體   English   中英

在尋找最佳解決方案時嘗試數據結構

[英]Trie Data Structure in Finding an Optimal Solution

這個問題是正在進行的比賽的一部分,我已經解決了這個問題數據集的 75%,但 25% 給了我 TLE。 我在問為什么它給了TLE我確定我的復雜度是O(n*n)

題:

由 N 個小寫英文字母組成的字符串 S。 我們准備了一個由all non empty substrings of the string Sall non empty substrings of the string S組成的列表 L 。

現在他問你Q問題。 對於第 i 個問題,您需要計算從列表 L 中選擇恰好 Ki 相等的字符串的方法數

例如:

    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 .

問題鏈接


我的方法

我正在制作 IT 的 TRIE 並計算 The 和 Array F[i] ,其中 F[i] 表示 i 等於 String Occur 的次數。 我的特里:

 static class Batman{

        int value;
        Batman[] next = new Batman[26];

        public Batman(int value){
            this.value = value;
            } 
 }

我的插入功能

 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];
     }

 }

我的主要功能

public static void main(String args[] ) throws  java.lang.Exception  {

Root = new Batman(0);
int n = in.nextInt();
int Q = in.nextInt();
String S = in.next();
int[] F = new int[n+1];

for(int i=0;i<n;i++)
    Insert(S,F,i);


long[] ans = new long[n+1];


for(int i=1;i<=n;i++){
    for(int j=i;j<=n;j++){
        ans[i]+= F[j]*C[j][i];  // C[n][k] is the Binomial Coffecient
        ans[i]%=mod;
    }
}


 while(Q>0){
     Q--;
    int cc = in.nextInt();
    long o =0;
    if(cc<=n) o=ans[cc];
     System.out.println(o+" "+S.length());
 }
}



為什么我的方法給 TLE 作為時間復雜度是 O(N*N) 並且字符串的長度是 N<=5000。 請幫我工作代碼

該程序獲得 TLE 的原因之一(請記住,時間限制為 1 秒):

每次創建Batman對象時,都會創建一個長度為 [26] 的數組,相當於添加了一個 n = 26 的循環。

所以,你的時間復雜度是 26*5000*5000 = 650000000 = 6.5*10^8 次操作,理論上,如果 CPU 速度為每秒 10^9 次操作,它仍然可以適應時間限制,但也要記住,有一些這之后計算量很大,所以,這應該是原因。

為了解決這個問題,我使用了Z 算法並被接受:鏈接

實際代碼相當復雜,所以想法是,你有一個表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]++;
            }
        }

Z算法方法:

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;
}

實際代碼: http : //ideone.com/5GYWeS

說明

首先,我們有一個數組長度,其中length[i]是與從索引i開始的字符串匹配的最長子字符串

對於每個索引i ,在計算 Z 函數后,我們看到, if cur[i][j] > length[j + i] ,這意味着存在一個比索引j + i處匹配的前一個子串更長的子串,並且我們還沒有將它們計入我們的結果中,所以我們需要計算它們。

因此,即使有 3 個嵌套的 for 循環,但每個子串只計算一次,這使得整個時間復雜度為 O(n ^2)

        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];
            }          
        }

對於下面的循環,我們注意到,如果有匹配的子串 (i,j), length[i] >= length of substring (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]++;
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM