用map<string,int>m,通过string映射一个编号,再通过编号来在数组int f[N]中获取一个值为什么会出错?

#用mapm,通过string映射一个编号,再通过编号来在数组int f[N]中获取一个值为什么会出错?
#题目链接https://blog.csdn.net/qq_46373141/article/details/124276794
#交题链接https://pintia.cn/problem-sets/1635264548121292800/exam/problems/1636695635989049355
#问题代码


```c++
#include 
#include 
#include 
using namespace std;
const int MAXN = 100010;
mapint> mp;//相关步骤
 int f[MAXN];
int main()
{
    int n, s;
    cin >> n >> s;
    for ( int i = 0; i < n; i ++ ){
        string s1;//相关步骤
        cin >> s1;//
        mp[s1] = i;//
    }
        
    for ( int i = 1; i <= n / s; i ++ )
        for ( int j = 1; j <= s; j ++ )
            cin >> f[i * s - j];//相关步骤
    int k;
    cin >> k;
    string num;//相关步骤
    while ( k -- ) {
        cin >> num;

        if ( f[mp[num]] ) cout << f[mp[num]] << endl;//相关步骤
        else cout << "Wrong Number\n";
    }
    
    return 0;
}

#正确代码


```c++
#include 
#include 
#include 
using namespace std;
const int MAXN = 100010;
mapint> mp;
string str[MAXN];
 
int main(void)
{
    int n, s;
    cin >> n >> s;
    for ( int i = 0; i < n; i ++ )
        cin >> str[i];
    for ( int i = 1; i <= n / s; i ++ )
        for ( int j = 1; j <= s; j ++ )
            cin >> mp[str[i * s - j]];
    int k;
    cin >> k;
    string num;
    while ( k -- ) {
        cin >> num;
// count是STL库自带的函数,计算容器中值出现的次数
        if ( mp.count(num) ) cout << mp[num] << endl;
        else cout << "Wrong Number\n";
    }
    
    return 0;
}


// 我的思路:字符串映射int,再通过int在数组里获得编号,二维数组模拟栈存类型stirng->int->int
// 题解思路:用string数组维护编号与字符串,再套入map里,一维数组模拟二维数组+模拟栈
// 我的思路并没有问题,只是由于第一个读入的字符串在map中的值被映射为了0,会被判断不存在。输出Wrong Number
// 因此只要将判断Worng Number的条件改一下,写成mp.conut(num)即可,这样就可以避免合法元素map映射为0与非法元素混淆的问题

// 再就是二维数组的问题,看错了题目关键信息,盲盒总量 N(≤10^ 5),范围太大,不能用二维数组。
// 还有就是本题的数组模拟栈,只要读入时将下标倒转即可

参考GPT和自己的思路:

对于第一个代码,出错的原因在于:map中以string作为关键字,对应int作为值,建立映射关系之后,无法通过下标访问,只能通过关键字访问。因此,第29行的代码应该修改为 if(mp.find(num) != mp.end()) cout << f[mp[num]] << endl; 。

正确的代码使用了一个string类型的数组str存储输入的字符串,以其下标来作为编号,然后通过map来将字符串映射到数组中对应的下标上,最后通过map的count函数来判断某个字符串是否在map中,并输出其对应的数组值。

参考GPT和自己的思路:

这里涉及到几个关键问题:

  1. mp[s1] = i这行代码将string类型的s1映射为一个整数i,但是该整数并不是我们需要的数组下标,因为i是从0开始计数的,而本题需要的是从1开始计数。

  2. for ( int i = 1; i <= n / s; i ++ ) for ( int j = 1; j <= s; j ++ ) cin >> f[i * s - j]这段代码读入的数组下标也是从1开始计数的,而不是从0开始计数的,因此需要一些特殊处理。

  3. 在输出结果时,f[mp[num]]是找到一个整数对应的数组元素,但是因为map中的映射关系并不是唯一的(有可能两个不同的string映射到同一个整数),因此这里在查找时会出现问题。

下面是解决问题的正确代码:

#include <iostream>
#include <string>
#include <map>
using namespace std;
const int MAXN = 100010;
map<string, int> mp;
int f[MAXN] = { 0 };

int main()
{
    int n, s, m = 0;
    cin >> n >> s;
    for (int i = 1; i <= n; i++) {
        string s1;
        cin >> s1;
        mp[s1] = i;
    }
    for (int i = 1; i <= n / s; i++) {
        for (int j = s; j >= 1; j--) {
            cin >> f[m + j];
        }
        m += s;
    }
    int k;
    cin >> k;
    while (k--) {
        string num;
        cin >> num;
        if (mp.find(num) != mp.end() && mp[num] <= n && mp[num] > 0) {
            int index = mp[num];
            index = (index - 1) / s * s + s - (index - 1) % s;
            cout << f[index] << endl;
        }
        else {
            cout << "Wrong Number" << endl;
        }
    }
    return 0;
}

其中,mp.find(num) != mp.end() && mp[num] <= n && mp[num] > 0这行代码用于判断输入的字符串是否在map中,并且其对应的整数应该在1到n的范围内(这种情况主要是为了避免样例数据中存在不存在的字符串)。由于本题要求按照所给的顺序输出数组元素,因此我们需要计算每个输入字符串对应的数组下标。最后输出的时候,由于有换行符的存在,需要注意输出格式的问题。

参考GPT和自己的思路,问题出在错误代码中使用了字符串到整数的映射,然后将其作为数组下标来访问一个整型数组f,这样可能会导致数组越界或者映射值没有被初始化而访问到一个无效的位置。另外,使用字符串作为下标也可能会存在冲突,即不同的字符串映射到相同的整数值,这会导致错误的结果。正确的做法是使用字符串作为键,在map中保存对应的整数值,然后使用该键来查询对应的整数值,避免了上述问题。正确代码中使用了map.count()函数来查询键是否存在,该函数返回键存在的次数,如果为1表示存在,为0表示不存在。

在while循环中直接用mp[num]有可能会因为num不在mp的键中报错,应该先判断mp是否包含num,此外f是一个数组,你还要手动判断是否越界,而不是直接去索引它

if ( mp.count(num) &&(mp[num]<MAXN)) cout << f[mp[num]] << endl;

参考GPT和自己的思路:你出错的原因是在 map 中将字符串映射为编号,然后直接用这个编号作为数组下标来访问 f 数组,但是这个编号不一定是连续的,也不一定是从 0 开始的,因此可能会访问到超出数组范围的位置,导致出错。

正确的做法是使用一个字符串数组 str 来存储输入的字符串,然后使用 str 数组中每个字符串在 map 中的映射值作为下标来访问 f 数组。这样就能保证下标是连续的且从 0 开始。

另外,判断 map 中是否存在某个键可以使用 count 函数,它会返回该键在 map 中出现的次数,如果是 0 则表示不存在。因此可以将 if 语句改为:

if ( mp.count(num) ) cout << f[mp[num]] << endl;
else cout << "Wrong Number\n";

怎么全是机器人

该回答引用ChatGPT

如有疑问,可以回复我!

你在问题代码中出现了错误,原因是你在为map赋值时只赋了键值,而没有赋值对应的值。而在正确代码中,你为map分配了字符串和对应的值,因此可以正常工作。

问题代码中的错误:

for ( int i = 0; i < n; i ++ ){
    string s1;
    cin >> s1;
    mp[s1] = i;
}

上面的代码只是将字符串作为键值存入map中,但是没有赋值给它对应的值。这导致当你试图访问f[mp[num]]时,mp[num]并没有对应的值,可能导致未定义的行为。

正确代码中的正确操作:

for ( int i = 0; i < n; i ++ )
    cin >> str[i];
for ( int i = 1; i <= n / s; i ++ )
    for ( int j = 1; j <= s; j ++ )
        cin >> mp[str[i * s - j]];

在正确的代码中,你首先将字符串存储在str数组中,然后在第二个循环中为map中的字符串分配对应的值。这样,当你访问mp[num]时,它将返回正确的值。

另外,问题代码中使用if ( f[mp[num]] )来判断该字符串是否存在于map中,这是错误的。你应该使用mp.count(num)来判断字符串是否在map中,就像正确代码中所做的那样:

if ( mp.count(num) ) cout << mp[num] << endl;
else cout << "Wrong Number\n";