【问题标题】:C++ String Element FindingC++ 字符串元素查找
【发布时间】:2014-03-23 08:09:19
【问题描述】:

我正在解决这个问题: 编写一个接收字符串并打印第一个非重复字符的函数。换句话说,我需要找到在整个字符串中只出现一次的第一个字符。 我知道解决方案已经可用,但以下是我编写的代码:

#include <iostream>
#include <string>
#include <unordered_map>


using namespace std;


void main()
{
    string S1;
    int NonRepeatElement,StringLenght,temp;
    unordered_map <char, int> ElementMap;
    unordered_map<char,int>::iterator it;
    char KeyValue;

    cout<<"Please enter your string"<<endl;

    cin>>S1;

    StringLenght=S1.length();

    NonRepeatElement=0;

    for(int i=0;i<StringLenght;i++)
        {
            if(ElementMap.find(S1[i]) == ElementMap.end())
                ElementMap[S1[i]]=1;
            else
                ElementMap.find(S1[i])->second++;
        }

    for(it=ElementMap.begin();it!=ElementMap.end();++it)
    {
        if(it->second==1)
        { KeyValue=it->first;
          break;
        }
    }


   for(int i=0;i<StringLenght;i++)
   {
       if(S1[i]==KeyValue)
       {
           cout<<"First Non Repeating character is "<<S1[i]<<endl;
           break;
       }
   }

}

现在我确实得到了只出现一次的元素,但它不是第一个真正的元素,而是它的第一个排序元素。 例如。如果输入字符串是 zaaabbcccdjjj 那么输出是 d 而不是 z 谁能提出为什么甚至 unordered_map 的行为是这样的?

【问题讨论】:

  • 第一个非重复字符是指与相同字符值不相邻的字符吗? IE。如果定义正在寻找一些“cc”而不是“cac”,则“abcac”有 no 个“重复”字符。两者都是可以解决的,但是解决方案将完全不同,因此请澄清您的问题(您似乎试图解释后者而不是前者)。我希望这种情况下的白话是“找到第一个 unique 字符”。
  • 是的,你是对的。我编辑了我的问题。它实际上是“找到第一个独特的字符”。
  • 好的。那么答案是在构建地图后不要通过迭代枚举地图。再次枚举字符串,通过映射find 方法搜索第一个条目,该方法的计数为1。如果您需要下面的答案,我会发布它(并且可能无论如何都应该)。
  • 哦,太好了。这很好用,但是你能解释一下为什么迭代 map 会给出错误的结果吗? MAP 的哪些功能导致了这种错误行为?
  • 地图对 anything 是无序的(当然不完全正确,它是一个哈希映射,但这不是重点,而且看起来 d 的哈希较低比z 的哈希值)。枚举它将为您提供带有冲突的哈希表排序即使使用有序映射仍然不起作用,因为它只是按字符排序。 字符串中的位置是你感兴趣的。

标签: c++ string map


【解决方案1】:

您不应该枚举地图。构建地图后,您应该枚举 string

#include <iostream>
#include <string>
#include <unordered_map>

int main()
{
    unordered_map <char, int> ElementMap;
    std::string S1;

    cout<<"Please enter your string"<<endl;
    if (cin >> S1)
    {
        for (std::string::iterator it = S1.begin(); it != S1.end(); ++it)
            ++ElementMap[*it];

        for (std::string::iterator it = S1.begin(); it != S1.end(); ++it)
        {
            if (ElementMap[*it] == 1)
            {
                std::cout << "First non-repeating character is " << *it << '\n';
                break;
            }
        }
    };

    return 0;
}

替代方案:查找表

如果输入数据的域是固定的并且small(在本例中是这样),另一种方法是使用简单的查找表。 char 数据类型最多有(1 &lt;&lt; CHAR_BIT) 元素,并且值本身可以用作表的直接索引。因此,您可以执行以下操作:

#include <iostream>
#include <string>
#include <climits>

int main()
{
    std::cout << "Please enter your string: ";

    std::string s;
    if (std::cin >> s)
    {
        unsigned int elems[ 1 << CHAR_BIT ]={};
        for (auto ch : s)
            ++elems[static_cast<unsigned char>(ch)];

        for (auto ch : s)
        {
            if (elems[static_cast<unsigned char>(ch)] == 1)
            {
                std::cout << "First non-repeating character is " << ch << '\n';
                break;
            }
        }
    };

    return 0;
}

好处是每个元素查找的复杂度为 O(1),无论是在初始“地图”人口中还是在查找第一个 1 的重复枚举中。总复杂度为 O(2N),即 O(N),其中 N 是字符串长度。对于在大型输入流中查找唯一字符,这将大大优于基于散列或基于顺序的动态映射。

但是有一个代价:不要尝试使用 32 位的 char 类型;一个 4GB 的自动阵列是无家可归的地方。

【讨论】:

  • 哦,太好了。这很好用,但是你能解释一下为什么迭代 map 会给出错误的结果吗? MAP 的哪些功能导致了这种错误行为?还有为什么我们总是为迭代器做 ++it 而不是 it++?
  • 我在一般评论中解释的第一个。第二个(++it)是一种效率习惯,只要知道它++如何生成一个临时副本,递增迭代器,然后返回临时值。在这种情况下,编译器优化可能会丢弃所有临时文件,但如果我没有使用“之前”值(在这种情况下,我没有),我总是使用 prefix-inc 来做。跨度>
【解决方案2】:

这看起来太复杂了。您所要做的就是检查 element[i] 和 element[i+1]。只要它们相等,您就增加一个计数。当它们不同时,您检查计数。如果计数没有增加,那么你有一个非重复元素。

在伪代码中:

* set count = 0
* for i = 0 to n-1
    if element[i] == element [i+1] then count++
    else
       if count == 0 then print element[i] and break
       else count = 0 (and continue)

【讨论】:

  • 我正在解决会产生输出的问题:(1) if input = aaaabbbbcccdddejj output e ,2) if input abbcdddj output = a 。基本上我需要找到在字符串中只出现一次的第一个元素。抱歉,问题陈述的措辞有误。
  • 是的,我明白了。你仍然不需要地图。我认为没有理由。
  • 什么是有效的方法?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-05
  • 2011-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多