📌  相关文章
📜  查询字符串给定范围的第 N 个最小字符

📅  最后修改于: 2021-09-07 02:35:58             🧑  作者: Mango

给定一个仅由小写字母组成的字符串str和一个数组arr[][]表示对给定字符串str 的范围查询,其中每个查询包含 3 个整数 {L, R, N} 这样对于每个查询我们必须输出查询中指定的给定范围 [L, R] 中的N最小字符。

例子:

朴素的方法:朴素的方法是运行从LR的循环并生成此范围内的子字符串。一旦子被发现,排序子找到N的排序字符串字符。

时间复杂度分析:

  • 在最坏的情况下,从L遍历到R的复杂度为O(N)
  • 对子字符串进行排序的复杂度为O(N * Log(N))
  • 由于我们对每个查询的子字符串进行排序,因此,整体时间复杂度为O(N 2 * Log(N))

有效的方法:这个想法是利用二维哈希表。哈希表H[][]被初始化为N 行26 列,其中 N 表示字符串的长度,26 表示共有 26 个小写字母。

hashtable 背后的想法是,对于每个索引i ,其中 ‘i’ 的范围从 1 到 N,我们跟踪第i索引上或之前的 26 个小写字母中的每一个出现的次数。为此,使用散列,其中每个字符都被视为一个数字,如下所示:

'a' -> 0
'b' -> 1
.
.
.
'z' -> 25

因此,对于每个查询 {L, R, N},我们通过从H[R][j]中减去H[L – 1][j]的元素来获得给定范围内每个字符的出现次数,其中 j 的范围为0 到 25 的哈希表形式。在这之后,我们需要做的就是从 0 到 25 遍历并添加结果数组的内容。每当总和等于或超过N 时,表示该索引的字符就是必需的答案。

例如,如果在5索引 (j = 4) 上,到那时为止的总和超过 N,则答案变为“e”,因为 4 相当于字符“e”。以下是示例案例的图示:

该图像描述了与给定字符串对应的哈希表。对于范围[2, 4] ,我们从H[4] 中减去H[2 – 1]中的内容。我们得到:

显然,这个结果数组包含范围 [2, 4] 内的元素计数。所以我们简单地从 0 到 25 遍历并计算内容,直到我们到达 N。在 N = 1 的查询中,答案是“b”,对于 N = 2,答案变成“c”,依此类推。

下面是上述方法的实现:

C++
// C++ implementation to find the Nth
// smallest character in a given range
// of a string
  
#include 
using namespace std;
  
// Query structure to represent a query range
// along with n
struct Query {
    int l, r, n;
};
  
// Function to print the Nth smallest
// character for a given range in a string
int findSmallest(string s, Query q[], int m)
{
  
    // Integer N contains the
    // length of the string s
    int N = s.length();
  
    // We initialise our hash array and
    // set all the elements to 0
    int H[N + 1][26];
    memset(H, 0, sizeof(H));
  
    // We preprocess our string in which we
    // update the current character
    // as well as add the H[i - 1]th
    // array to H[i]
    for (int i = 1; i <= N; i++) {
  
        // Incrementing the frequency of
        // ith row based on the occurrence
        // of the characters up to i-th index
        ++H[i][s[i - 1] - 'a'];
  
        // Adding the values of the array at
        // the previous index to the next index
        for (int j = 0; j < 26; j++) {
            H[i][j] += H[i - 1][j];
        }
    }
  
    // We traverse from 0 to m to
    // fetch all the queries
    for (int j = 0; j < m; j++) {
  
        // Extracting L, R and N
        // from the query array q
        int l = q[j].l, r = q[j].r,
            n = q[j].n;
  
        // The initial sum is set to 0
        int sum = 0;
  
        // We subtract H[l-1] from h[r]
        // and add it to the sum
        for (int i = 0; i < 26; i++) {
            sum += H[r][i] - H[l - 1][i];
  
            // Whenever the sum is greater than
            // or equal to N, the equivalent
            // character of the index is our
            // nth smallest character
            if (sum >= n) {
                cout << (char)('a' + i) << "\n";
                break;
            }
        }
    }
}
  
// Driver code
int main()
{
    // Input string s
    string s = "afbccdeb";
    // Query array q, for each q
    // it contains l, r and n
    Query q[] = { { 2, 4, 1 },
                  { 1, 6, 4 },
                  { 1, 8, 7 } };
    int x = sizeof(q) / sizeof(q[0]);
  
    findSmallest(s, q, x);
}


Java
// JAVA implementation to find the Nth
// smallest character for a given range
// in a string
  
import java.io.*;
import java.util.*;
  
class GFG {
  
    // Query class to represent a query range
    // along with n
    public static class Query {
        public int l, r, n;
  
        // Constructor for the Query class which
        // takes three integers L, R, N
        public Query(int l, int r, int n)
        {
            this.l = l;
            this.r = r;
            this.n = n;
        }
    }
  
    // Function to print the Nth smallest
    // character for a given range in a string
    public static void printSmallest(String s, Query[] q)
    {
  
        // Integer N contains the
        // length of the string s
        int N = s.length();
  
        // We initialise our hash array and
        // set all the elements to 0
        int[][] H = new int[N + 1][26];
  
        // We preprocess our string in which we
        // update the current character
        // as well as add the H[i - 1]th
        // array to H[i]
        for (int i = 1; i <= N; i++) {
  
            // Incrementing the frequency of
            // ith row based on the occurrence
            // of the characters up to i-th index
            ++H[i][s.charAt(i - 1) - 'a'];
  
            // Adding the values of the array at
            // the previous index to the next index
            for (int j = 0; j < 26; j++) {
                H[i][j] += H[i - 1][j];
            }
        }
  
        // Integer m contains the
        // number of queries
        int m = q.length;
  
        // We traverse from 0 to m to
        // fetch all the queries
        for (int j = 0; j < m; j++) {
  
            // Extracting l, r and n
            // from the query array q
            int l = q[j].l, r = q[j].r,
                n = q[j].n;
  
            // The initial sum is set to 0
            int sum = 0;
  
            // We subtract H[l-1] from h[r]
            // and add it to the sum
            for (int i = 0; i < 26; i++) {
                sum += H[r][i] - H[l - 1][i];
  
                // Whenever the sum is greater than
                // or equal to N, the equivalent
                // character of the index is our
                // nth smallest character
                if (sum >= n) {
                    System.out.println((char)('a' + i));
                    break;
                }
            }
        }
    }
  
    // Driver code
    public static void main(String args[])
    {
        // Input string s
        String s = "afbccdeb";
  
        // Query array q, for each q
        // it contains l, r and n
        Query[] q = { new Query(2, 4, 1),
                      new Query(1, 6, 4),
                      new Query(1, 8, 7) };
  
        // Calling the function
        printSmallest(s, q);
    }
}


Python3
# Python3 implementation to find the Nth
# smallest character in a given range
# of a string
  
# Function to print the Nth smallest
# character for a given range in a string
def findSmallest(s, q, m):
  
    # Integer N contains the
    # length of the s
    N = len(s)
  
    # We initialise our hash array and
    # set all the elements to 0
    H = [[0 for i in range(26)]for i in range(N + 1)]
  
    # We preprocess our in which we
    # update the current character
    # as well as add the H[i - 1]th
    # array to H[i]
    for i in range(1, N + 1):
  
        # Incrementing the frequency of
        # ith row based on the occurrence
        # of the characters up to i-th index
        H[i][ord(s[i - 1]) - ord('a')] += 1
  
        # Adding the values of the array at
        # the previous index to the next index
        for j in range(26):
            H[i][j] += H[i - 1][j]
  
    # We traverse from 0 to m to
    # fetch all the queries
    for j in range(m):
  
        # Extracting L, R and N
        # from the query array q
        l = q[j][0]
        r = q[j][1]
        n = q[j][2]
  
        # The initial sum is set to 0
        sum = 0
  
        # We subtract H[l-1] from h[r]
        # and add it to the sum
        for i in range(26):
            sum += H[r][i] - H[l - 1][i]
  
            # Whenever the sum is greater than
            # or equal to N, the equivalent
            # character of the index is our
            # nth smallest character
            if (sum >= n):
                print(chr(ord('a') + i))
                break
  
# Driver code
if __name__ == '__main__':
      
    # Input s
    s = "afbccdeb"
      
    # Query array q, for each q
    # it contains l, r and n
    q = [ [ 2, 4, 1 ],
        [ 1, 6, 4 ],
        [ 1, 8, 7 ] ]
    x = len(q)
  
    findSmallest(s, q, x)
      
# This code is contributed by mohit kumar 29


C#
// C# implementation to find the Nth
// smallest character for a given range
// in a string
using System;
  
class GFG {
  
    // Query class to represent a query range
    // along with n
    public class Query {
        public int l, r, n;
  
        // Constructor for the Query class which
        // takes three integers L, R, N
        public Query(int l, int r, int n)
        {
            this.l = l;
            this.r = r;
            this.n = n;
        }
    }
  
    // Function to print the Nth smallest
    // character for a given range in a string
    public static void printSmallest(String s, Query[] q)
    {
  
        // int N contains the
        // length of the string s
        int N = s.Length;
  
        // We initialise our hash array and
        // set all the elements to 0
        int[,] H = new int[N + 1,26];
  
        // We preprocess our string in which we
        // update the current character
        // as well as add the H[i - 1]th
        // array to H[i]
        for (int i = 1; i <= N; i++) {
  
            // Incrementing the frequency of
            // ith row based on the occurrence
            // of the characters up to i-th index
            ++H[i, s[i - 1] - 'a'];
  
            // Adding the values of the array at
            // the previous index to the next index
            for (int j = 0; j < 26; j++) {
                H[i, j] += H[i - 1, j];
            }
        }
  
        // int m contains the
        // number of queries
        int m = q.Length;
  
        // We traverse from 0 to m to
        // fetch all the queries
        for (int j = 0; j < m; j++) {
  
            // Extracting l, r and n
            // from the query array q
            int l = q[j].l, r = q[j].r,
                n = q[j].n;
  
            // The initial sum is set to 0
            int sum = 0;
  
            // We subtract H[l-1] from h[r]
            // and add it to the sum
            for (int i = 0; i < 26; i++) {
                sum += H[r, i] - H[l - 1, i];
  
                // Whenever the sum is greater than
                // or equal to N, the equivalent
                // character of the index is our
                // nth smallest character
                if (sum >= n) {
                    Console.WriteLine((char)('a' + i));
                    break;
                }
            }
        }
    }
  
    // Driver code
    public static void Main(String []args)
    {
        // Input string s
        String s = "afbccdeb";
  
        // Query array q, for each q
        // it contains l, r and n
        Query[] q = { new Query(2, 4, 1),
                    new Query(1, 6, 4),
                    new Query(1, 8, 7) };
  
        // Calling the function
        printSmallest(s, q);
    }
}
  
// This code is contributed by Rajput-Ji


输出:
b
c
e

时间复杂度分析:

  • 对于上述方法,尽管预处理由两个循环组成,但第二个循环运行的次数是恒定的(26)。因此,预处理所需的时间是O(N)
  • 预处理后,对于每个查询,字符以恒定时间返回,这里 for 循环再次运行恒定次数(26)。因此,回答每个查询所花费的时间是O(1)

如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live