【问题标题】:How can I check if a vector is a subsequence (in the same order but not contiguous) of another vector?如何检查一个向量是否是另一个向量的子序列(顺序相同但不连续)?
【发布时间】:2020-04-01 07:55:55
【问题描述】:

如何检查vector_a 的所有元素是否也以与vector_b 相同的顺序出现?

vector_b 可能很长,不假设它已排序,但它没有重复元素。

我找不到为Vec 或在 itertools 中实现的方法,所以我尝试通过以下方式实现:

  1. vector_b 映射value -> index 创建一个hashmap
  2. 遍历vector_b 并检查:
    • 元素存在于 hashmap 中
    • 索引严格大于前一个元素的索引

我对此并不满意,因为由于创建了 hashmap,空间效率不高。

【问题讨论】:

  • 您可以简单地在vector_b 中对vector_a 的第一个元素进行线性搜索。找到后,搜索下一个,依此类推。由于vector_b 没有重复项,因此您永远不需要再次备份,因此这在vector_b 的长度上是线性的,只需要恒定的额外空间。
  • 一个简单的可能优化是,一旦vector_a 中的剩余元素多于vector_b 中的剩余元素,则退出循环,因为这样就不可能再找到所有元素了。
  • 这是否需要对向量元素是通用的,还是元素是特定类型?
  • @PeterHall 元素是派生自CopyEqPartialEq 的另一个结构。
  • @SvenMarnach 是的,感谢您的建议。我可以做这个。您会推荐这种方法:doc.rust-lang.org/std/iter/trait.Iterator.html#method.position 进行搜索吗?我的疑问是,对于未排序的vector_b,搜索可能会以非常低效的 WRT 时间结束?

标签: algorithm rust iterator


【解决方案1】:

按顺序搜索大海捞针中的每个元素。每次找到匹配元素时,只在大海捞针的剩余部分继续搜索。每次匹配一个元素时,您都可以通过从干草堆中提取一个新的子切片来很好地表达这一点。

fn is_subsequence<T: PartialEq>(needle: &[T], mut haystack: &[T]) -> bool {
    for search in needle {
        if let Some(index) = haystack.iter().position(|el| search == el) {
            haystack = &haystack[index + 1..];
        } else {
            return false;
        }
    }
    true
}

assert!(is_subsequence(b"", b"0123456789"));
assert!(is_subsequence(b"0", b"0123456789"));
assert!(is_subsequence(b"059", b"0123456789"));
assert!(is_subsequence(b"345", b"0123456789"));
assert!(is_subsequence(b"0123456789", b"0123456789"));

assert!(!is_subsequence(b"335", b"0123456789"));
assert!(!is_subsequence(b"543", b"0123456789"));

切片只是一个指针和一个大小,存储在堆栈中,因此不会进行新的分配。它在O(n) 时间运行,应该接近于最快的实现 - 或者至少在同一个球场。

【讨论】:

  • 感谢您的明确解释。将haystack 设为可变引用会产生什么后果?我相信如果这必须是库的一部分,那么允许不可变引用将是首选,对吧?
  • @user2774555 haystack 不是可变引用。只有局部变量是可变的(它被越来越小的子切片重新分配),但原始切片不能被改变:这需要参数是haystack: &amp;mut [T]
【解决方案2】:

最简单的方法是联合迭代两个向量:

fn contains<T: PartialEq>(needle: &[T], haystack: &[T]) -> bool {
    let mut idx = 0;
    for it in needle {
        while (idx < haystack.len()) && (&haystack[idx] != it) {
            idx += 1;
        }
        if idx == haystack.len() {
            return false;
        }
    }
    return true;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多