C++ 如何进一步缩短执行时间?

C++ 如何进一步缩短执行时间?,c++,optimization,C++,Optimization,我正在试一道竞赛题。要求如下 问题: 输入格式: 预期产出: 我的C++代码是:-< /p> #include <iostream> using namespace std; int main() { long long n,i,j,k=0,p,q; cin>>n;//takes size of string// char s[n]; cin>>s; cin>>p;//Number of test cases// for(i=0;i<

我正在试一道竞赛题。要求如下

问题:

输入格式:

预期产出:

<>我的C++代码是:-< /p>
#include <iostream>
using namespace std;

int main() {

long long n,i,j,k=0,p,q;
cin>>n;//takes size of string//
char s[n];
cin>>s;
cin>>p;//Number of test cases//
for(i=0;i<p;i++)
{
    cin>>q;//takes index to check till//
    for(j=0;j<q-1;j++)
    {
        if(s[j]==s[q-1])//checks if characters are equal//
        {
            k++;//if yes then counts it//
        }
    }
    cout<<k<<endl;
    k=0;//makes cout 0 for next iteration//
}

return 0;
}


因此,代码似乎适用于大多数情况,但在某些情况下,时间限制似乎超出了范围。还可以做些什么来减少时间。提前感谢您花时间阅读此声明。

首先,此声明:

long long n
cin>>n;//takes size of string//
char s[n];
这是不标准的。g++支持它,但我不相信可变大小的数组已经成为C++的标准,就像C.那样,我怀疑你需要很长的时间作为索引类型,除非你正在超过20亿个项目。 更好:

int n;
cin>>n; //takes size of string
vector<char> s(n);
将s中的字符插入表格和positionCount表格,如下所示

for (int i = 0; i < n; i++)
{
    char c = s[i];

    // table[c] is the number of occurrences that "c" was seen in the input array so far
    table[c]++;

    // since table[c] is getting updated as we iterate, 
    // Keep track of the count of the char at position i in a separate array
    positionCount[i] = table[c];
};
然后针对每个测试用例:

for(i=0;i<p;i++)
{
    cin>>q; //takes index to check till

    q--; // off by 1 fix since the array is described as 1..N


    long result = positionCount[q];

    result--; // off by 1 fix again since the output is the preceeding count and doesn't include the character at position q.

    cout << result << endl;

}
由于没有内部for循环,上述所有操作直观上更快。哈希表插入和查找与每个数组查找一样是O1

如果你喜欢简洁的话,你可以把上面的简化为:

for (int i = 0; i < n; i++)
{
   positionTable[i] = table[s[i]]++;
}

for(i=0;i<p;i++)
{
   cin >> q;
   cout << positionTable[q-1] << endl;
}

假设我们有一个数组cnt,它存储字符串第i个字符之前的中每个字母的出现次数,对于某些i。通过简单地增加相关元素,我们可以轻松地更新此数组以包含第i个字符。因此,我们将遍历更新此数组的字符串,在第i次迭代时,cnt数组将包含索引i之前每个字母的计数

现在,在第i次迭代中,cnt数组中有助于回答查询的信息是cnt[s[i]],因为它包含索引i之前的字符串部分中索引i处字符的出现次数。我们将把这些信息存储在一个[i]中,其中a是另一个数组。所以现在a[i]是索引i中字母在i之前所有位置出现的次数,这正是我们在索引i处查询所需要的。因此,我们现在可以使用数组回答查询

可能的实施:

#include <iostream>
#include <string>
#include <vector>

int main()
{
    //read input
    int n;
    std::string s;
    std::cin >> n >> s;
    //iterate through string maintaining cnt array and adding relevant values to array a
    int cnt[26] = { 0 };
    std::vector<int> a;
    a.reserve(n);
    for (int i = 0; i < n; i++)
    {
        int c = s[i] - 'a';
        a.push_back(cnt[c]);
        cnt[c]++;
    }
    //answer queries
    int q;
    std::cin >> q;
    for (int i = 0; i < q; i++)
    {
        int p;
        std::cin >> p;
        p--;
        std::cout << a[p] << '\n';
    }
}

如果知道字符串前i个字符中每个字母的出现次数,如何计算字符串前i+1个字符中每个字母的出现次数?您需要遍历字符才能再次计数吗?您的代码有两个错误,第一个是char s[n];不是合法C++,因为C++中的数组边界必须是编译时常数,而n是变量。第二,即使考虑到这一点,也需要chars[n+1];因为您需要为每个C字符串结尾的nul终止符留出空间。@AlexanderZhang我们实际上可以通过将所有字符存储在数组中来存储在一次迭代中出现的所有字符,但在这种情况下,我们仍然需要一个循环,因为存在p test_情况,并且每个情况都有不同的计数。是的,最后,您将得到一个包含整个字符串计数的数组。但是,您不必只查看循环后的count数组。考虑一下计数数组在每个循环迭代中存储了什么。它不是包含了一些你可能想要存储的有用信息吗?@AlexanderZhang好的,就连我现在都明白了。噢,亲爱的Zhang!是的,它有效。你太棒了,谢谢你的算法人@阿南霍卡奇没问题。确保您了解它是如何工作的,以便将来能够解决类似的问题。不要只是复制代码。对于这样的查询问题,您几乎总是想找到一种对数据进行某种预处理的方法,以构建一些数据结构,帮助您回答查询。@Ananthokage这不是一个活跃的竞赛,是吗?我有理由相信是这样。
#include <iostream>
#include <string>
#include <vector>

int main()
{
    //read input
    int n;
    std::string s;
    std::cin >> n >> s;
    //iterate through string maintaining cnt array and adding relevant values to array a
    int cnt[26] = { 0 };
    std::vector<int> a;
    a.reserve(n);
    for (int i = 0; i < n; i++)
    {
        int c = s[i] - 'a';
        a.push_back(cnt[c]);
        cnt[c]++;
    }
    //answer queries
    int q;
    std::cin >> q;
    for (int i = 0; i < q; i++)
    {
        int p;
        std::cin >> p;
        p--;
        std::cout << a[p] << '\n';
    }
}