Nano Hash - криптовалюты, майнинг, программирование

Как узнать, равны ли две строки на основе появления одной конкретной буквы?

В этом проекте две строки считаются равными, если они обе имеют одинаковое количество вхождений символа «X» и если символ «X» находится в одной и той же позиции в каждой из строк. Обратите внимание, что это позволяет использовать строки разной длины, если в конце более длинной строки нет никаких «X» в дополнительных символах. Мне нужно реализовать эту функцию equals с прототипом функции bool equalsChar(const string& strA, const string& strB, char ch).

Примеры

  • equalsChar( "X", "X", 'X' ) верно
  • equalsChar( "aaaXaaaX", "abcXcbaX", 'X') верно
  • equalsChar( "XaXbXcX", "XtXoXpXdef", 'X') верно
  • equalsChar( "XaXbXcX", "XtXoXpXdXf", 'X') неверно
  • equalsChar( "XXXX", "XX", 'X') неверно
  • equalsChar( "aXaXbXcX", "XtXoXpX", 'X') неверно

Мы можем использовать вспомогательные функции, но нам не разрешено выделять дополнительную память (например, не использовать подстроку). Нам нужно работать с индексами при обработке строк.

Я попробовал знания, которые у меня были до сих пор, и искал похожие вопросы на разных веб-сайтах, но это кажется уникальным вопросом.

Вот код:

bool equalsChar(const string& strA, const string& strB, char ch){
   int low1=0;
   int low2=0;
   int high1=strA.length()-1;
   int high2=strB.length()-1;
   return equalsChar(strA, low1, high1, strB, low2, high2, ch);
}

Я использую перегруженную функцию:

bool equalsChar(const string& strA, int low1, int high1, const string& strB, int low2, int high2, char ch){
   int count1=0;
   int count2=0;
   for(int i=low1; i<=high1; i++){
      if(strA[i]==ch)
         count1++;
   }
   for(int j=low2; j<=high2; j++){
      if(strB[j]==ch)
         count2++;
   }
   if(count1==0 && count2==0)
      return false;
   else if(count1!=count2)
      return false;
   else{
      for(int i=low1; i<=high1; i++){
         if(strA[i]==ch){
            for(int j=low2; j<=high2; j++){
               if(strB[j]==ch){
                  if(i==j)
                     return true;
               }
            }
         }
      }
   }
   return false;
}

Есть две проблемы:
1. Мне нужно сделать этот код рекурсивно.
2. Я проверяю только первый символ, который равен ch из strA и strB, а затем сравниваю их индексы, а что мне нужно сделать заключается в сравнении всех X в обеих строках.

Он возвращает true для equalsChar( "aaaXaaXa", "abcXcbaX", 'X'), но должен возвращать false.

10.09.2019

  • Пожалуйста, покажите свои усилия. С какими проблемами вы столкнулись при попытке решить эту проблему? 11.09.2019
  • Привет, @Fureeish, я обновил свой код, основываясь на том, чего я добился до сих пор, пожалуйста, посмотрите сейчас. 11.09.2019
  • Поскольку вас просили о рекурсивности, самым простым способом было бы equalsChar сравнить один символ. Если равно, то рекурсивно вызывает себя с low1 и low2 увеличенными на единицу. Начните заставлять код работать со строками одинаковой длины, а затем, когда он заработает, улучшите его, чтобы он обрабатывал первую строку короче второй. Когда это работает, вы добавляете случай, когда вторая строка короче первой (аналогичный код) 11.09.2019
  • Вы сказали, что у вас есть две проблемы. С кем вам нужна помощь? Можете ли вы переформулировать свой вопрос, чтобы сосредоточиться именно на этой проблеме? В идеале вы должны быть в состоянии сформулировать вопрос достаточно абстрактно, чтобы не было необходимости описывать ваше задание более подробно, чем что-то вроде «Странные ограничения являются частью домашнего задания». 11.09.2019
  • ваши решения слишком сложны. Ваша задача — модифицированная функция strcmp, которую можно написать рекурсивно (хотя это крайне неэффективно), которая будет предполагать, что любые символы, отличные от ch. равны. 11.09.2019

Ответы:


1

Сначала убедитесь, что более длинная строка strB. Мы используем рекурсию для замены параметров, если это необходимо.

Затем проверьте общую длину. Мы проецируем каждую букву на bool с == ch и сравниваем эти bool.

Наконец, мы проверяем, происходит ли ch после strA.size().

bool equalsChar(const string& strA, const string& strB, char ch) {
    if (strA.size() > strB.size()) { return equalsChar(strB, strA, ch); }

    auto common = [ch](char a, char b) { return (a == ch) == (b == ch); };
    return std::equal(strA.begin(), strA.end(), strB.begin(), common)
        && (std::find(strB.begin() + strA.size(), strB.end(), ch) == strB.end());
}

Или с string_view С++ 17 и библиотекой диапазонов для очистки.

bool equalsChar(string_view strA, string_view strB, char ch) {
    if (strA.size() > strB.size()) { return equalsChar(strB, strA, ch); }

    auto common = [ch](char a, char b) { return (a == ch) == (b == ch); };
    string_view prefix = strB.substr(0, strA.size());
    string_view suffix = strB.substr(strA.size());

    return ranges::equal(strA, prefix, common)
        && !ranges::contains(suffix, ch);
}
11.09.2019
  • хм, похоже, это будет иметь более высокую сложность. также им может быть запрещено делать ярлыки через 'std::find' 11.09.2019
  • @Swift-FridayPie как так? он посещает каждый char ровно один раз 11.09.2019
  • справедливо, я потерялся в скобках. примечание об использовании «алгоритма» остается в силе. Это позволяет показать, как алгоритм должен работать, поэтому он хорош и проходит тест. 11.09.2019
  • Мы используем рекурсию для замены параметров Не совсем то, что я называю рекурсивной функцией. Даже если я не понимаю, зачем нужны рекурсивные решения для такой функции. 11.09.2019

  • 2

    В рекурсии я бы написал это:

    // Does s contains given char?
    bool hasChar(const char* s, char c)
    {
        if (*s == '\0') {
            return false;
        }
        if (*s == c) {
            return true;
        }
        return hasChar(s + 1, c);
    }
    
    bool equalsChar(const char* strA, const char* strB, char ch)
    {
        // one string is finished, check the other one.
        if (*strA == '\0') {
            return !hasChar(strB, ch);
        } else if (*strB == '\0') {
            return !hasChar(strA, ch);
        }
        // Are strings compare different?
        if (*strA != *strB && (*strA == ch || *strB == ch)) {
            return false;   
        }
        // next index
        return equalsChar(strA + 1, strB + 1, ch);
    }
    

    Демо

    11.09.2019

    3

    В идеале вы должны

    1. iterate through first string `str1` by i
    2. if you encounter `str1[i] == ch`,and 
    3    if `i <= str2.length()` 
    4.      check if `str2[i] == ch`.  
    5.           if false then  strings are not equal
    6.   else if `i > str2.length()` you would cut the iteration 
    7. else if `str2[i] == ch` then  strings are not equal
    
    8. continue to iterate through string str2 by i, 
    9.             if `str2[i] == ch` strings are not equal
    A. if end reached , strings are equal.  
    

    Обе итерации, конечно, могут быть рекурсивными, но, очевидно, вам нужен только один индекс. В качестве альтернативы, если это std::string, вы можете использовать итераторы вместо индексов и передачи строки\подстроки. Вы должны передать str.end(), чтобы итерация остановилась, когда итератор сравнялся с ним.

    Обратите внимание, что технически вызов перегруженных функций не является рекурсией. Это разные функции.

    Пусть первая функция итерации будет чем-то вроде

    bool equalsChar(string::const_iterator& at1, 
                    string::const_iterator& at2, 
                    const char& ch, 
                    const string::const_iterator& end1, 
                    const string::const_iterator& end2);
    

    называться так:

    bool equalsChar(const string& strA, const string& strB, char ch)
    {
         // maybe do checks if strings are empty to shortcut the function?
         auto it1 = strA.begin(), it2 = strB.begin();
         return equalsChar(it1, it2, ch, strA.end(), strB.end() );
    }
    

    и будет увеличивать итераторы при вызове самого себя.

    Второй был бы

    bool equalsChar(string::iterator& at, 
                    const char& ch, const string::iterator& end);
    

    и вызываться из хвостового регистра первого

    // assuming we checked that it2 not equal to end2 before
    if(it1 == end1) return equalsChar(it2 , ch, end2 );
    

    Теперь вишенка. По требуемому поведению это может быть та же функция с переставленными аргументами.

    if(it1 == end1) return equalsChar(it2 , it1, ch, end2, end1 );
    

    И мы можем сделать это с самого начала, проверяя, какая строка длиннее, вызывая ее так, чтобы первая всегда была длиннее.

    Неидеальная версия предполагает, что две строки, не содержащие X, равны)

    #include <iostream>
    #include <vector>
    #include <string>
    
    using std::string; 
    bool equalsChar(string::const_iterator& at1, 
                    string::const_iterator& at2, 
                    const char& ch, 
                    string::const_iterator& end1, 
                    string::const_iterator& end2)
    {    
        if(at2 == end2) {
            if(at1 == end1)
                return true; // two empty strings are equal, right?
            if(*at1 == ch)
                return false;    
        }
        else
        { 
            if((*at1 != *at2) && (*at1 == ch || *at2 == ch)) return false; 
            ++at2;
        }
    
        ++at1;    
        return equalsChar( at1, at2, ch, end1, end2);
    }
    
    bool equalsChar(const string& strA, const string& strB, char ch)
    {
         // maybe do checks if strings are empty to shortcut the function?
         auto it1 = strA.begin(), it2 = strB.begin();
         decltype(it1) end1 = strA.end(), end2 = strB.end();
    
         if(strA.length() < strB.length()) 
            std::swap(it1,it2), std::swap(end1,end2);
         return equalsChar(it1, it2, ch, end1, end2 );
    }
    
    int main()
    {
        std::vector<std::pair<string,string>> data= {
        { "X", "X" },
        { "aaaXaaaX", "abcXcbaX" },
        { "XaXbXcX", "XtXoXpXdef" },
        { "XaXbXcX", "XtXoXpXdXf" },
        { "XXXX", "XX" },
        { "aXaXbXcX", "XtXoXpX" }};
    
    
        for(auto& item : data)
            std::cout << "equalsChar( " << item.first << ", " << item.second  << " )" 
                  << string{ equalsChar(item.first,item.second,'X') ? " is true" : " is false"} << std::endl;
    }
    
    11.09.2019
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..