Напишите функцию, которая сравнивает две строки и возвращает третью строку, содержащую только буквы, которые появляются в обоих

Я получил эту домашнюю работу. И решили это следующим образом. Мне нужны ваши комментарии, будь то хороший подход или мне нужно использовать любую другую структуру данных, чтобы решить ее лучше.

    public string ReturnCommon(string firstString, string scndString)
    {
        StringBuilder newStb = new StringBuilder();
        if (firstString != null && scndString != null)
        {
            foreach (char ichar in firstString)
            {
                if (!newStb.ToString().Contains(ichar) && scndString.Contains(ichar))
                    newStb.Append(ichar);
            }
        }
        return newStb.ToString();
    }

Ответы

Ответ 1

Это хорошо для первого подхода, но вы можете сделать несколько улучшений, и там небольшая ошибка.

  • Если b содержит символ в a, который уже находится в c, вы повторите его.
  • Чтобы избежать повторений, вы можете использовать Set для хранения символов, так как a Set не будет повторять.
  • Сборка строк с конкатенацией += обычно неэффективна; рассмотрите возможность использования StringBuilder или аналогичного класса сборки строки.
  • Имена переменных не очень описательны.
  • Если a или b пустые, вам не нужно вообще ничего делать! Просто верните пустую строку.

Вы также можете подумать о некоторых более сложных усовершенствованиях, представляя, как ваш алгоритм масштабируется, если вы начали использовать огромные строки. Например, один подход может заключаться в том, что если одна строка намного длиннее другой, вы можете отсортировать ее дольше и удалить дубликаты. Затем вы можете быстро выполнить двоичный поиск по символам более короткой строки.

Ответ 2

Для альтернативного решения вы можете просмотреть строки как перечисляемые и использовать Intersect() следующим образом:

    public static string Common(string first, string second)
    {
        return new string((first.Intersect(second)).ToArray());
    }

Ответ 3

Чтобы улучшить последнее предложение Джона Фэминеллы, быстрее, чем двоичный поиск (для любой достаточно длинной строки), будет поиск в хешсе; или поиск в 256-элементном массиве логических значений, если это символы ASCII или UTF8 вместо символов UTF16.

  • Создавать пустую строку hashset или пустой массив логических элементов; назовите эту переменную found.
  • Для каждого char в первой строке либо добавьте char в hashset (но остерегайтесь дубликатов символов в первой строке), или установите соответствующий элемент в массиве found равным true; это приведет к линейному времени O (n).
  • Для каждой char во второй строке проверьте, существует ли char в hashset или соответствует ли соответствующий элемент в массиве "найденный": если он найден, добавьте символ в возвращаемую строку, а также удалите символ из hashset или очистить логический элемент в массиве, чтобы он больше не был найден (чтобы остерегаться дубликатов символов во второй строке); это приведет к линейному времени O (n).

Ответ 4

Кажется прекрасным. Вы можете сделать пару оптимизаций в зависимости от языка, который вы используете:

  • вы можете собирать буквы b в какую-то упорядоченную структуру (чтобы быстрее ее искать), и если она не повторяется... лучше (набор).
  • вы можете использовать какой-то StrignBuilder (если это Java или .Net), чтобы не воссоздавать строку с каждой конкатенацией внутри цикла

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

Ответ 5

Зависит от длины входных строк, , что является буквой и как вывод должен выглядеть (дубликаты), есть несколько других подходы.

Например:

Если буквы просто [AZ] символы и каждая буква должна отображаться только один раз в выходной строке, вы может построить отдельную строку (или таблицу символов) 'ABC... XZ' (пусть назовите ее letters) и запустите цикл for each через letters и проверьте обе строки ввода на каждую букву от letters.

Этот дает 26 итераций цикла и не более, а затем 52 вызывает метода Contains() для каждой строки ввода - независимо от того, как долго входные строки.

Ответ 6

Использование LINQ:

a.ToCharArray().Intersect<char>(b.ToCharArray())

Однако это чувствительно к регистру.

Ответ 7

FYI: Вот код C/С++:

/* Q: Write a function f(a, b) which takes two character string arguments
      and returns a string containing only the characters found in both
      strings in the order of a. */

#include <iostream>
#include <string>
#include <cstring>
#include <map>
using namespace std;

/* A: Unclear: repeated chars in string a? */
string CommonChars(const char* a, const char* b)
{
    string result("");

    if (!a || !b || !*a || !*b)
        return result;

    map<char, bool> hash;
    int len1 = strlen(a), len2 = strlen(b);

    for (int i = 0; i < len2; ++i)
        hash[b[i]] = true;

    for (int i = 0; i < len1; ++i)
    {
        map<char, bool>::iterator it = hash.find(a[i]);
        if (it != hash.end() && it->second)
        {
            result += a[i];
            hash[a[i]] = false; // OR:  hash.erase(it);
        }
    }

    return result;
}

int main()
{
    cout << CommonChars("abcdefgbx", "gcfcba") << endl;

    return 0;
}
/* Output:
abcfg
 */

Ответ 8

Здесь мое решение в python. Если я не ошибаюсь, это должно привести к линейному времени O (n).

# Write a function f(a, b) which takes two character string arguments
# and returns a string containing only the characters found in both
# strings in the order of a. 
first_string = "attempt"
secong_string="tmay"
result = []

#it O(n) operation
for char in first_string:
   if char in secong_string:
      if char not in result:
         result.append(char)

print result
Результаты

выглядят следующим образом:

['a', 't', 'm']

Ответ 9

Похоже на меня, но для бога - человек - используйте некоторые описательные имена переменных!!