问题是(source)......
1000位数字中具有最大值的四个相邻数字 产品为9×9×8×9 = 5832。
73167176531330624919225119674426574742355349194934 96983520312774506326239578318016984801869478851843 85861560789112949495459501737958331952853208805511 12540698747158523863050715693290963295227443043557 66896648950445244523161731856403098711121722383113 62229893423380308135336276614282806444486645238749 30358907296290491560440772390713810515859307960866 70172427121883998797908792274921901699720888093776 65727333001053367881220235421809751254540594752243 52584907711670556013604839586446706324415722155397 53697817977846174064955149290862569321978468622482 83972241375657056057490261407972968652414535100474 82166370484403199890008895243450658541227588666881 16427171479924442928230863465674813919123162824586 17866458359124566529476545682848912883142607690042 24219022671055626321111109370544217506941658960408 07198403850962455444362981230987879927244284909188 84580156166097919133875499200524063689912560717606 05886116467109405077541002256983155200055935729725 71636269561882670428252483600823257530420752963450
找到1000位数字中的13个相邻数字 最好的产品。这个产品有什么价值?
我有以下F#...
let largestProduct n (s : string) =
[ for i in [0..(s.Length - n)] do yield s.[i..(i + n - 1)]]
|> Seq.map (fun s -> s, s |> Seq.fold (fun p c -> p * (int (string c))) 1)
|> Seq.maxBy snd
您传递的位数和1000位数字作为字符串。第一行产生一系列n字符串,这些字符串通过管道输入到计算数字乘积的第二行。它包含在带有n个字符串的元组中,因此我可以看到哪个n个字符集产生了最高的产品。最后一行获得最大产品。
如果我按照以下方式运行......
largestProduct 4 nStr
...其中nStr是一个1000位数的字符串,它产生以下......
("9989", 5832)
......这是正确的。但是,如果我将数字更改为13,以解决实际问题,它会给我......
("9781797784617", 2091059712)
......显然是错的。
任何人都知道为什么我的代码不起作用?我已经尝试了n的各种小值,看起来它在那里工作。我也尝试过较短的琴弦,看起来效果很好。
答案 0 :(得分:6)
此练习会导致Int32溢出。任意长度类型bigint
解决了这个问题,通常有足够的输入范围。例如:
let digitsToProduct inp =
inp |> Seq.map (string >> bigint.Parse)
|> Seq.fold (*) 1I
let largestProduct n : (seq<char> -> bigint) =
Seq.windowed n >> Seq.map digitsToProduct >> Seq.max
编辑:请注意largestProduct
接受第二个参数:1000位数的字符串(或任何字符序列)。
这是一个值得思考的基本问题。根据经验,功能应该是正确的或失败的,至少对于合理的输入。我认为,在开发人员可能犯这样错误的任何情况下,仅使用64位整数的答案是临界错误的。毕竟,它仍然会在太大的输入上静默失败。
如果您想为这样的功能使用32位或64位整数,验证您的输入!
例如,粗略的验证可能是:
// 32b version
if n > 9 then invalidArg "n" "number of digits too large for Int32."
// 64b version
if n > 19L then invalidArg "n" "number of digits too large for Int64."
这会导致您的程序无法正常而不是默默地产生无意义的结果。
答案 1 :(得分:4)
正如您所知,使用int64
解决了问题。
我阅读作业的方式,您不必返回导致最大产品的数字;只需要产品本身。有了这个要求,实施很容易:
let largestProduct n : (string -> int64) =
Seq.map (string >> System.Int64.Parse)
>> Seq.windowed n
>> Seq.map (Array.fold (*) 1L)
>> Seq.max
如果你想要数字序列,这也很容易:
let largestProductAndTheDigitsThatProduceIt n : (string -> string * int64) =
Seq.map (string >> System.Int64.Parse)
>> Seq.windowed n
>> Seq.map (fun is -> System.String.Concat is , Array.fold (*) 1L is)
>> Seq.maxBy snd
FSI:
> largestProductAndTheDigitsThatProduceIt 4 nStr;;
val it : string * int64 = ("9989", 5832L)
> largestProductAndTheDigitsThatProduceIt 13 nStr;;
val it : string * int64 = ("5576689664895", 23514624000L)
答案 2 :(得分:3)
在寻找灵感时,我遇到了someone had the same problem的问题。
答案并不比乘法溢出32位整数的容量更复杂。当我将代码更改为使用int64时,它给出了正确答案......
let largestProductInt64 (n : int64) (s : string) =
[ for i in [0L..((int64 s.Length) - n)] do yield s.[(int i)..int(i + n - 1L)]]
|> Seq.map (fun s -> s, s |> Seq.fold (fun p c -> p * (int64 (int (string c)))) 1L)
|> Seq.maxBy snd
很遗憾,因为代码并不干净整洁,但它确实有效。
感谢@kvb在我有机会发表我自己的发现之前在评论中提出同样的观点。