为什么这些算法有什么不同?

时间:2019-02-10 07:13:55

标签: swift algorithm reduce

出于个人启发,我摆弄了Swift的.reduce(),遇到了一种我无法理解的异常行为。

我花了很多意想不到的时间(至少6个小时)进行研究和实验,但我感到很沮丧。

我有两种算法(我写了第二种)。它们看起来做的完全一样,就是计算出现在无限字符串中且有重复模式的字符数(在本例中为“ a”) 。两种算法在大约50%的时间内表现相同。一种使用.reduce()两次,另一种-工作的一种-使用for循环。

在所有情况下均有效的算法是:

let str = readLine()!
let length = Int(readLine()!)!

let fullRepetitions = length / str.characters.count
let lengthLastRep = length % str.characters.count

var count = fullRepetitions * str.characters.reduce(0) { $1 == "a" ? $0 + 1 : $0 }

for i in 0..<lengthLastRep {
    if str[str.index(str.startIndex, offsetBy: i)] == "a" {
        count += 1
    }
}

print(count)

不是但应该的是:

let pattern = readLine()!
let length = Int(readLine()!)!
let fullyRepeatedPatterns = length / pattern.count
let lastPatternLength = pattern.count % length
var countOfAs = fullyRepeatedPatterns * pattern.reduce(0, { $1 == "a" ? $0 + 1 : $0 })
countOfAs += pattern
    .prefix(upTo: pattern.index(pattern.startIndex, offsetBy: lastPatternLength - 1))
    .reduce(0, { $1 == "a" ? $0 + 1 : $0 })
print(countOfAs)

至少从表面上看,它们看起来像它们应该做的完全一样。但是他们没有。

起初,我以为执行模运算以获取最后一个模式的长度时发现了我的问题, 但是,如果我将第二个算法更改为与第一个算法一样,它不仅会停止执行边缘情况,但存在严重的运行时错误。 就是说要更改此内容:

let lastPatternLength = pattern.count % length

对此:

let lastPatternLength = length % pattern.count

使第二个算法具有更多的.reduce()来打破(运行时错误), 所以我不认为模是导致错误的原因。

更有趣的是,错误不一致。输入内容为:

aab
882787

“ aab”重复了882787次,看起来像是一个错误的错误……或者似乎是一个错误的错误。但是...

let pattern = "aab"
let length = 882787

let fullyRepeatedPatterns = length / pattern.count
let lastPatternLength = pattern.count % length
var countOfAs = fullyRepeatedPatterns * pattern.reduce(0, { $1 == "a" ? $0 + 1 : $0 })
countOfAs += pattern
    .prefix(upTo: pattern.index(pattern.startIndex, offsetBy: lastPatternLength - 1))
    .reduce(0, { $1 == "a" ? $0 + 1 : $0 })
print("expected 588525 but got \(countOfAs)")

我提前知道了正确的答案,所以我可以说:

  

我期望588525,但得到588526。

但是输入时:

babbaabbabaababaaabbbbbbbababbbabbbababaabbbbaaaaabbaababaaabaabbabababaabaabbbababaabbabbbababbaabb
860622337747

27点起!

最后, 似乎是故意很烦人 ,输入以下内容:

ababa
3

关闭-1。

在很多情况下,两种算法都可以工作,例如:

aba
10

但是我不在乎那些。

有人可以解释一下我在这里缺少什么吗?

1 个答案:

答案 0 :(得分:2)

第一:

let lastPatternLength = pattern.count % length

应该是

let lastPatternLength = length % pattern.count

与原始算法相同。例如:

pattern = "abab"
length = 11

length / pattern.count = 11 / 4 = 2
length % pattern.count = 11 % 4 = 3

表示该模式需要两个副本以及三个附加字符才能达到11的总长度。

这有时在测试中导致运行时错误是由于第二个错误:In

.prefix(upTo: pattern.index(pattern.startIndex, offsetBy: lastPatternLength - 1))

您不能从lastPatternLength中减去一个,应该是

.prefix(upTo: pattern.index(pattern.startIndex, offsetBy: lastPatternLength))

因为prefix(upTo:)返回的子序列最多为 个给定索引。您也可以将其简化为

.prefix(lastPatternLength)