0

我正在尝试获取数组中 4 个相邻数字的最大乘积,这就是我现在得到的:

let max4 line =
    let rec loop acc = function
        |a :: b :: c :: [] -> acc
        |a :: b :: c :: d :: tl -> loop (max(acc, a*b*c*d)) tl
        |_ -> 0
    loop 0 line

我得到一个关于这max(,)句话的编译错误:

错误 FS0001:类型不匹配。期望一个 'a 但给定一个 'a * 'b -> 'a * 'b 当统一 ''a' 和 ''a * 'b -> 'a * 'b' 时,结果类型将是无限的


有人知道这段代码有什么问题吗?(或其他解决方案)

4

3 回答 3

5

作为使用显式递归的替代方法,您还可以使用现有的 F# 库函数来解决此问题。这是大多数 F# 数据处理的编写方式,但学习如何手动编写递归函数总是好的(因为您有时需要它们)。

因此,为了完整起见,这里有一种使用现有函数更声明性地解决问题的方法:

let max4 line = 
  line |> Seq.windowed 4 
       |> Seq.map (Seq.reduce (*))
       |> Seq.max

第一行将列表转换为 4 元素数组(窗口)的序列。然后将其传递给Seq.map将窗口变成元素的产品。为此,我使用Seq.reduce指定的函数(这里是(*)运算符)来减少序列(在本例中为窗口)。最后,要找到产品的最大元素,可以使用Seq.max函数。

于 2012-05-31T17:04:49.423 回答
2

假设输入是一个整数列表:

let max4 line =
    let rec loop acc = function
        | x1::(x2::x3::x4::_ as xs) -> loop (max acc (x1*x2*x3*x4)) xs
        |_ -> acc
    loop System.Int32.MinValue line

你犯了一些错误:

  • 内置max函数采用 curry 形式max: 'a -> 'a -> 'a
  • 在你的函数中要解决的下一个案例应该是b::c::d::tltl不仅仅是。
  • 该产品可能是负面的,所以0不是一个好的起点。请注意可能会发生整数溢出(我还没有在我的函数中解决这个问题)。
于 2012-05-31T16:43:16.780 回答
1

其他两个答案都是滑动窗口的总和,但在你的问题中它们是连续的。如果你想要后者,你可以定义这样一个函数:

let groupsOf n items =
  if n <= 0 then invalidArg "n" "must be greater than zero"
  if List.isEmpty items then invalidArg "items" "empty list"
  let rec loop i acc items =
    seq {
      match i, items with
      | 0, [] -> yield List.rev acc
      | _, [] -> ()
      | 0, _ ->
        yield List.rev acc
        yield! loop n [] items
      | _, x::xs -> yield! loop (i - 1) (x::acc) xs
    }
  loop n [] items

然后使用类似于 Tomas 的代码:

let max4 line = 
  line |> groupsOf 4 
       |> Seq.map (Seq.reduce (*))
       |> Seq.max

groupsOf最后忽略任何部分组(就像您的代码一样)。

于 2012-05-31T18:36:10.043 回答