字符串操作|竞争规划

时间:2017-01-07 18:20:30

标签: java string algorithm data-structures time-complexity

我有一个大小为N的字符串(小写字母),基于1的索引 现在我给了Q查询,每个查询由两个整数x,y组成。
对于每个查询,我必须从子串(x,y)(包括x,y)打印最小删除数,使得子串具有相同频率的不同字符。

例如:考虑一个形成子串abbccd的查询,
现在最少没有。它的缺失是2(1b,1c)。

1 <= N,Q <= 10 ^ 5

1·; = X&LT; = Y&LT; = N

我尝试了蛮力方法,对于每个查询,我计算字符的频率,然后通过将所有频率等于最小频率来计算删除。

但我知道这种做法是错误的,也会导致TLE。任何人都可以帮助我。

我的代码:

import java.util.Arrays;
import java.util.Scanner;
public class q1 {
public static void main(String[] args) {
    // TODO Auto-generated method stub
    Scanner in = new Scanner(System.in);
    int n = in.nextInt();
    int q = in.nextInt();
    in.nextLine();
    String s = in.nextLine();
    int x,y;
    while(q>0){
        x = in.nextInt();
        y = in.nextInt();
        String temp = s.substring(x-1, y);
        char c[] = temp.toCharArray();
        int count[] = new int[26];
        //calculating the frequencies.
        for (int i = 0; i < c.length; i++) {
            count[c[i]-'a']++;
        }
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < count.length; i++) {
            if(count[i]!=0 && count[i]<min){
                min = count[i];
            }
        }
        int deletions = 0;
        for (int i = 0; i < count.length; i++) {
            if(count[i]!=0){
                deletions += (count[i]-min);
            }
        }
        System.out.println(deletions);



        q--;
    }
}

}

Problem Link

1 个答案:

答案 0 :(得分:0)

这是我的解决方案,每个查询的步骤为 O(26*26)。 制作了一个累积频率数组来存储每个字符的频率,直到字符串中的“第 i 个”位置。

dp[i][0] 是字符串中从索引 1 到 i 包含“a”的频率。
dp[i][1] 是“b”在字符串中从索引 1 到 i 包含的频率。
依此类推,直到 25 为“z”。

现在在每个查询中,我们可以计算子串 x 到 y 中每个字符的频率,通过从相同字符的频率中减去字符“i” up-til “x-1”的频率-直到“y”即

freq[i] = dp[x-1][i] - dp[y][i];

现在一旦我们获得了子字符串中每个字符的频率,我们就可以迭代这些频率并计算每个唯一字符的删除次数。

例如,如果我们有一个子字符串“ddddbbacc”
"a" 的频率为 1
“b”的频率为 2
"c" 的频率为 2
"d" 的频率是 4

frequencies = [1, 2, 2, 4]
在第一次迭代时,我们尝试使所有频率都等于 freq[0],即 1.
为此,我们从具有 freq = 2 的字符中删除一个字符,并从具有 freq = 4 的字符中删除 3 个字符。
这给了我们1+1+3 = 5的答案。

在第二次迭代中,我们尝试使所有频率等于 freq[1],即 2.
为此,我们从具有 freq = 4 的字符中删除 3 个字符。
我们还删除了所有 freq < 2
这给了我们1+2 = 3的答案。

在最坏的情况下,每个查询需要 26*26 步。 发现问题 here

import java.util.Arrays;
import java.util.Scanner;
import java.util.Collections;
import java.util.ArrayList;

class q1 {

static int[][] dp = new int[100005][27];

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    int n = in.nextInt();
    int q = in.nextInt();
    in.nextLine();
    String s = in.nextLine();
    
    for (int i = 0; i < s.length(); i++){                   //O(N*26)
        for (int j = 0; j < 26; j++)
            dp[i+1][j] = dp[i][j];
        dp[i+1][(int)(s.charAt(i))-(int)('a')]++;
    }
    
    int x,y;
    while(q>0){                                             //O(Q*700)
        x = in.nextInt();
        y = in.nextInt();
        int freq[] = new int[27];
        for(int i = 0; i < 26; i++)                         //O(1)
            freq[i] = dp[y][i] - dp[x-1][i];
        ArrayList<Integer> f = new ArrayList<Integer>();
        for(int i = 0; i < 26; i++)                         //O(1)
            if(freq[i] != 0)
                f.add(freq[i]);
        Collections.sort(f);                                //O(26*log26)
        int ans = s.length() + 1;
        int drop = 0;
        for(int i = 0; i < f.size(); i++){                  //O(26*26)
            int currans = drop;
            for(int j = i+1; j < f.size(); j++)
                currans += (f.get(j)-f.get(i));
            if (ans > currans)
                ans = currans;
            drop += f.get(i);
        }
        if (drop < ans)
            ans = drop;
        System.out.println(ans);
        q--;
    }
}

}
相关问题