如何在Rust中查找两个字符串是否具有公共字符

时间:2018-10-18 20:43:53

标签: rust

我是rust的新手,他试图找出两个字符串是否共享任何公共字符。我知道应该有一种不使用正则表达式的简单方法(我不反对正则表达式),也许可以通过使用my_str.chars().any()来实现,但是我不确定如何实现。

我以前在Python中通过比较集合来做到这一点。

if len(set(candidate) & set(required)) < 1: 

谢谢!

编辑

let result = candidate.chars().any(|c| required.contains(c));

因此,我能够找到使用any的解决方案。但是由于我不熟悉生锈,所以我不确定这是否是最好的方法。也许使用HashSets会更有效率?我的应用程序很小,因此效率不是一个很大的因素。最“乡村”的方式是什么?

2 个答案:

答案 0 :(得分:1)

您可以通过几种方式来实现它,这里有几个选择:

  • 构建第一个字符串的集合,并检查第二个字符串是否在该集合中包含字符[O(n + m)]
  • 反复检查第一个字符串的字符,并检查第二个字符串是否包含其中的任何一个[O(n * m)]

我决定使用HashSet,但如果您只关心ascii(因此限制为256种可能性),则可以使用基本数组。

use std::collections::HashSet;

fn share_char(a: &str, b: &str) -> bool {
    // get which one is shorter
    let (shorter, longer) = if a.len() > b.len() {
        (b, a)
    }  else {
        (a, b)
    };

    // fill the set with the characters from the shorter string
    let set: HashSet<char> = shorter.chars().collect();

    longer.chars().any(|c| set.contains(&c))
}

#[test]
fn test() {
    let str1 = "abcdef";
    let str2 = "the quick brown fox";
    let str3 = "hijk";

    assert!(share_char(str1, str2));
    assert!(!share_char(str1, str3));
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=76567b94d3bd15b37e33acb9a8d701d5

编辑:更改为使用收集

Edit2:我想解释一下为什么我进行了较短/较长的检查,以及为什么我不仅仅建造了两套。

插入HashSet的操作比仅遍历字符串的字符要昂贵得多。这意味着从长字符串构建集合与从短字符串构建集合之间存在差异。由于您的字符串长度可能相似,因此这种差异可以忽略不计。

这种费用差异也是为什么我不建造第二套的原因。我们不仅节省了插入成本,而且还节省了一些迭代,因为any如果找到匹配项就会短路。

Edit3:另一件事。如果只想检查字符串是否包含给定的一组字符,则应使用模式匹配。

str1.chars().any(|c| match c {
    'a' | 'd' | 'f' | 'e' => true,
    _ => false,
});

与使用静态Set相比,这将具有更高的性能。

答案 1 :(得分:0)

.any + .contains表示将一个字符串中的所有元素迭代为另一个字符串中的每个字符(复杂度O(nm));


相反,您可以使用哈希图并将每个 char 作为键存储,将 bool int 作为值存储:
在这种情况下,您将在第一次迭代中存储第一个字符串中的所有字符,然后迭代第二个字符串,尝试从hashmap中获取每个字符。
如果存在char,则立即返回true(最复杂的情​​况是O(n+m))。


出于性能方面的考虑,我建议在可能的情况下使用键而不是HashMap作为索引。

fn common_chars(s1: &str, s2: &str) -> bool {
   const ALPHABET_LEN: usize = 26;
   const CHAR_CODE: usize = 97; // a-97, z-122
   let mut alpahbet = [0; ALPHABET_LEN]; 
   for c in s1.chars() {
      alpahbet[c as usize - CHAR_CODE] += 1; // store each char from first string
   }
   for c in s2.chars() {
      if alpahbet[c as usize - CHAR_CODE] != 0 { // a stored char is found!
         return true;
      }
   }
   false
}
#[test]
fn test() {
   let str1 = "abcdef";
   let str2 = "the quick brown fox";
   let str3 = "hijk";
   assert!(common_chars(str1, str2));
   assert!(!common_chars(str1, str3));
}