在给定数组中查找整数序列

时间:2017-07-19 04:38:06

标签: arrays algorithm search go

我想知道是否有更好的方法(在我的实现是正确的情况下)在给定数组中找到整数的子序列。我已经使用golang实现了解决方案(如果这是审查的障碍,我可以使用不同的语言)。如果我没有弄错,波纹管的实现接近于O(b)。

package main

import "fmt"

func main() {
    a := []int{1, 2, 3}
    b := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
    r := match(a, b)

    fmt.Println("Match found for case 1: ", r)

    a = []int{1, 2, 3}
    b = []int{4, 5, 6, 7, 8, 9}
    r = match(a, b)

    fmt.Println("Match found for case 2: ", r)

    a = []int{1, 2, 3}
    b = []int{1, 5, 3, 7, 8, 9}
    r = match(a, b)

    fmt.Println("Match found for case 3: ", r)

    a = []int{1, 2, 3}
    b = []int{4, 5, 1, 7, 3, 9}
    r = match(a, b)

    fmt.Println("Match found for case 4: ", r)

    a = []int{1, 2, 3}
    b = []int{4, 5, 6, 1, 2, 3}
    r = match(a, b)

    fmt.Println("Match found for case 5: ", r)

    a = []int{1, 2, 3}
    b = []int{1, 2, 1, 2, 3}
    r = match(a, b)

    fmt.Println("Match found for case 6: ", r)

    a = []int{1, 2, 3, 4, 5}
    b = []int{4, 1, 5, 3, 6, 1, 2, 4, 4, 5, 7, 8, 1, 2, 2, 4, 1, 3, 3, 4}
    r = match(a, b)

    fmt.Println("Match found for case 7: ", r)

    a = []int{1, 2, 1, 2, 1}
    b = []int{1, 1, 2, 2, 1, 2, 1}
    r = match(a, b)

    fmt.Println("Match found for case 8: ", r)
}

func match(a []int, b []int) bool {
    if len(b) < len(a) {
        return false
    }

    lb := len(b) - 1
    la := len(a) - 1
    i := 0
    j := la
    k := 0
    counter := 0

    for {
        if i > lb || j > lb {
            break
        }

        if b[i] != a[k] || b[j] != a[la] {
            i++
            j++
            counter = 0
            continue
        } else {
            i++
            counter++
            if k < la {
                k++
            } else {
                k = 0
            }
        }

        if counter >= la+1 {
            return true
        }
    }

    return counter >= la+1
}

2 个答案:

答案 0 :(得分:1)

正确性

如评论部分所述,有一系列字符串匹配算法,通常分为单模式和多模式匹配算法。在您的情况下,它属于单一模式字符串匹配问题。

据我所知,最着名的算法是使用动态编程的KMP算法,以及使用滚动哈希技术来加速该过程的另一种名为Rabin-Karp的算法。两者都在O(max(a,b))中运行。

但是,您的代码与这些算法的正常实现不太相似,至少根据我的经验。因此,我首先怀疑代码的正确性。您可以尝试a = {1, 2, 1, 2, 1}, b { 1, 1, 2, 2, 1, 2, 1 }之类的案例,看看它没有给出正确的结果。

因此你可以

  1. 放弃当前算法并学习那些标准算法,实现它们
  2. 概述逻辑并勾勒出当前算法的证明,并将其与这些标准算法背后的逻辑进行比较,以验证其正确性
  3. 我会把这部分留给你

    复杂性

    直接回答您的OP:

    不,O(max(a,b))是您在此问题中可以实现的最佳选择,这也是上述标准已知算法的复杂性。

    我的理解是,它实际上是有意义的,因为在最坏的情况下,你必须至少读取一次较长字符串的每个字符。

    您当前的算法也明确O(b),因为您使用i从0循环到b的长度,无论您陷入i的哪个条件都会增加1,总计O(b)

    因此,复杂性实际上不是问题,正确性就是问题。

答案 1 :(得分:-1)

由于您只是在查找序列,我可能会将所有内容转换为字符串类型并使用标准字符串包。 Playground

package main

import (
    "fmt"
    "strings"
)

func main() {
    fmt.Println(strings.Contains("1, 2, 3, 4, 5, 6, 7, 8, 9", "1, 2, 3"))
    fmt.Println(strings.Contains("4, 5, 6, 7, 8, 9", "1, 2, 3"))
    fmt.Println(strings.Contains("1, 5, 3, 7, 8, 9", "1, 2, 3"))
    fmt.Println(strings.Contains("4, 5, 1, 7, 3, 9", "1, 2, 3"))
    fmt.Println(strings.Contains("4, 5, 6, 1, 2, 3", "1, 2, 3"))
    fmt.Println(strings.Contains("4, 5, 6, 1, 2, 3, 2", "1, 2, 2, 3"))
    fmt.Println(strings.Contains("1, 2, 1, 2, 3", "1, 2, 3"))
}