Использование Java Stream для проверки, имеют ли 2 строки какой-либо общий символ в одном выражении - PullRequest
2 голосов
/ 01 марта 2020

Ниже код имеет s1 и s2. Эта функция будет возвращать «YES», если есть какой-либо совпадающий символ, в противном случае «NO».

    public String checkIfStringsHaveSubStrings(String s1, String s2) {
        boolean[] alphabets = new boolean[26];
        s1.chars().forEach(s -> alphabets[s - 97] = true);
        return s2.chars().filter(s -> alphabets[s - 97]).count() > 0 ? "YES" : "NO";
    }

Я ожидаю одного оператора, использующего поток, который не требует объявления дополнительной переменной, в отличие от моего case я использовал дополнительное пространство, как показано ниже.

boolean [] alphabets = new boolean [26];

Ожидается одна строка, короткий и эффективный оператор с использованием Поток.

Может быть несколько простых подходов, но я хотел использовать потоки в процессе обучения.

Ответы [ 3 ]

2 голосов
/ 01 марта 2020

Вот один из способов:

public static String checkIfStringsHaveSubStrings(String s1, String s2) {
    return s2.chars().anyMatch(c -> s1.indexOf((char) c) >= 0) ? "YES" : "NO";
}

Конечно, это не самый эффективный способ.

1 голос
/ 03 марта 2020

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

Одна вещь, которую вы должны улучшить, - это не подсчитывать все вхождения, когда вы хотите знать только, есть ли вхождения. Использование anyMatch выражает намерение и будет более эффективным, так как anyMatch может остановить поиск, как только будет найдено совпадение:

public String checkIfStringsHaveSubStrings(String s1, String s2) {
    boolean[] alphabets = new boolean['z' - 'a' + 1];
    s1.chars().forEach(s -> alphabets[s - 'a'] = true);
    return s2.chars().anyMatch(s -> alphabets[s - 'a'])? "YES": "NO";
}

Временный массив boolean[] с 26 элементами ничего не значит беспокоиться, но если вы настаиваете на сокращении потребления памяти, 26 значений истинности можно выразить как 26 битов, которые вписываются в одно значение int.

public String checkIfStringsHaveSubStrings(String s1, String s2) {
    int alphabets = s1.chars().map(c -> 1 << c - 'a').reduce(0, (a,b) -> a | b);
    return s2.chars().map(c -> 1 << c - 'a').anyMatch(i -> (i & alphabets) != 0)?"YES":"NO";
}

Если вы хотите express, это в качестве одного оператора любой ценой вы можете использовать

public String checkIfStringsHaveSubStrings(String s1, String s2) {
    return (s1.chars().map(c -> 1 << c - 'a').reduce(0, (a,b) -> a | b)
         &  s2.chars().map(c -> 1 << c - 'a').reduce(0, (a,b) -> a | b)) != 0? "YES": "NO";
}

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

0 голосов
/ 01 марта 2020

Попробуйте это.


    System.out.println(
            checkIfStringsHaveSubStrings("abcde", "xyz"));
    System.out.println(
            checkIfStringsHaveSubStrings("abcxde", "xyz"));



    public static String checkIfStringsHaveSubStrings(String s1,
            String s2) {
        return s1.chars().filter(c -> s2.contains((char) c + ""))
                .count() == 0L ? "NO" : "YES";
    }

А вот альтернатива, если у вас есть Java 11 (метод isEmpty()). Вероятно, лучший из двух, так как он перестает выглядеть, как только находит один.

    public static String checkIfStringsHaveSubStrings(String s1,
            String s2) {
        return s1.chars().filter(c -> s2.contains((char) c + ""))
              .findFirst().isEmpty() ? "NO" : "YES";
    }

...