C++ 检查一个字符串是否是另一个字符串的排列

C++ 检查一个字符串是否是另一个字符串的排列,c++,string,algorithm,C++,String,Algorithm,我一直在练习编程问题,遇到了这个问题 给定字符串A和B,检查字符串B是否是字符串A的置换 我写下了我的答案,并将其与书本上的答案进行了比较,但我的答案完全不同。然后我研究了StackOverflow,没有看到任何人用我的解决方案回答这个问题 我看到了两种解决方案 对两个字符串进行排序,然后比较它们。这需要O(nlogn)时间,根据排序算法,它将占用O(n)、O(logn)或O(1)内存 创建一个哈希映射,并将键设置为字符串的字符,将值设置为ints初始化为0。当看到字符串a中的字符时,将值增加1

我一直在练习编程问题,遇到了这个问题

给定字符串A和B,检查字符串B是否是字符串A的置换

我写下了我的答案,并将其与书本上的答案进行了比较,但我的答案完全不同。然后我研究了StackOverflow,没有看到任何人用我的解决方案回答这个问题

我看到了两种解决方案

  • 对两个字符串进行排序,然后比较它们。这需要O(nlogn)时间,根据排序算法,它将占用O(n)、O(logn)或O(1)内存

  • 创建一个哈希映射,并将键设置为字符串的字符,将值设置为ints初始化为0。当看到字符串a中的字符时,将值增加1。当您看到字符串B中的字符时,将其减量1。最后,如果是置换,则所有值都应为0。这需要O(n)时间和O(n)内存

  • 我的解决方案是对字符串进行散列,然后比较散列值,如果它们相等,则字符串必须是排列

    我的C++解决方案

    bool isPerm(string a, string b) {
        if(a.length() != b.length()) return false;
        return hashString(a) == hashString(b);
    }
    
    long hashString(string a) {
        long hashed = 0;
        for(int i = 0; i < a.length(); i++) { 
            hashed += a[i] * 7; // Timed by a prime to make the hash more unique?
        } 
        return hashed;
    }
    
    bool isPerm(字符串a、字符串b){
    如果(a.length()!=b.length())返回false;
    返回hashString(a)=hashString(b);
    }
    长哈希字符串(字符串a){
    长散列=0;
    对于(inti=0;i
    此解决方案在O(n)时间和O(1)内存中运行

    问题

  • 这是一个有效的答案吗
  • 如果哈希值不够唯一,有没有办法使其唯一
  • 编辑

    正如每个人都指出的那样,我的解决方案无法使用。As
    ad
    将散列到
    bc
    ,这些不是排列

  • 您建议的散列无效,因为多个字符串可以散列为相同的值,这些值不一定是彼此的排列(例如“14”和“23”);实际上,您只是将字符串的ascii值乘以
    7
    ,因此哈希是检查字符串的总和是否相同,而不是它们是否是彼此的排列
  • 要使散列唯一,可以将字符串表示为字母表底部的数字;i、 e.
    hash=sum(c[i]*alpha^(i-1))
    ,其中
    c
    是您的字符串,
    alpha
    是字母表中的字母数;但是,由于散列现在是唯一的,
    hash(a)==hash(b)
    意味着
    a==b
    这不是您想要的;(这也有其自身的其他问题,例如溢出,相当复杂的计算)
  • 我会坚持选择1:对于固定的字母表大小
    a
    ,您可以使用
    O(n)
    time
    O(a)
    空间计数排序,例如,这显然是这个问题的最佳解决方案(恒定空间,由输入时间限定)


    选项2对我来说似乎也是错误的,但也许我只是不明白:如果输入是
    aa
    bb
    ,翻转
    a
    b
    两次,一切都是错误的,它们看起来不像是排列。当然,您可以为每个字符串保留一个字符出现图,这将需要
    O(a)
    内存和
    O(n)
    时间来处理大小为
    a
    的字母表,这与计数排序基本相同:)

    一种方法是比较每个字符串的唯一字符计数:

    #include <unordered_map>
    #include <string>
    
    using namespace std;
    
    bool checkPermutation(string a, string b) {
      unordered_map<char, int> aCounts;
      for (auto c : a) {
        aCounts[c]++;
      }
    
      unordered_map<char, int> bCounts;
      for (auto c : b) {
        bCounts[c]++;
      }
    
      if (aCounts.size() != bCounts.size()) {
        return false;
      }
    
      for (auto p : aCounts) {
        char c = p.first;
        if (bCounts.count(c)) {
          if (aCounts.at(c) != bCounts.at(c)) {
            return false;
          }
        } else {
          return false;
        }
      }
    
      return true;
    }
    
    #包括
    #包括
    使用名称空间std;
    布尔校验置换(字符串a、字符串b){
    无序的地图数量;
    用于(自动c:a){
    A计数[c]++;
    }
    无序的地图计数;
    用于(自动c:b){
    b计数[c]++;
    }
    如果(accounts.size()!=b counts.size()){
    返回false;
    }
    用于(自动p:A计数){
    char c=p.first;
    如果(b计数(c)){
    如果(c)处的计数!=c(c)处的计数){
    返回false;
    }
    }否则{
    返回false;
    }
    }
    返回true;
    }
    
    检查
    isPerm(“ad”,“bc”)
    。您的问题:给定两个大小为n的数组,如果数组的总和相等,您能否确保它们具有相同的元素?这就是您在散列比较中假设的情况。顺便说一句,
    *7
    没有什么好处。请注意,通常两个包含相同字母且顺序不同的字符串会产生不同的哈希值:这个问题在Java世界中有重复的吗?什么时候你可以在C++中自由使用java?你说的对2是正确的,我错了。假设使用int作为值,并在看到的每个字母上增加值。然后在另一个字符串上,为您看到的每个字母减小值。最后的值应该是0。