我尝试添加列表所代表的数字,例如:
0 = []
1 = [1]
2005 = [2005]
123456 = [3456; 12]
1234567890 = [7890; 3456; 12]
1000000001 = [1; 0; 10]
所以add [9999] [1] = [0;1]
我做到了这一点:
let rec add l1 l2 =
match l1, l2 with
| n::l1', m::l2' -> if n+m < 10000 then
(n+m)::(add l1' l2')
else
begin
match l1', l2' with
| p::l1'', q::l2'' -> ((n+m) - 10000)::(add ((1+p)::l1'') l2')
| p::l1'', [] -> ((n+m) - 10000)::(add ((1+p)::l1'') l2')
| [], q::l2'' -> ((n+m) - 10000)::(add l1' ((1+q)::l2''))
| [], [] -> ((n+m) - 10000)::[1]
end
| [], [] -> []
| m::l1', [] -> m::(add l1' [])
| [], m::l2' -> m::(add [] l2')
但它不适用于add [9999;9999] [1]
之类的内容
它提供[0; 10000]
而不是[0;0;1]
。
随身携带有问题,但我找不到。
适用于add [8500;6000] [5600;452]
。
答案 0 :(得分:4)
在我看来,你的情况假设数字总是小于或等于9999,但是当有进位时这不是真的。因此,即使其中一个列表为空,您也需要检查10000。
答案 1 :(得分:2)
问题在于你的非规范化表示,它可以暂时创建大于9999的数字,这是你在所有地方都不会想到的。这是一个带有显式进位的简单解决方案,可以避免这个问题:
let base = 10_000
let rec add' xs ys c =
match xs, ys with
| [], [] -> if c = 0 then [] else [c]
| [], zs | zs, [] -> add' [0] zs c
| x::xs', y::ys' -> (x + y + c) mod base :: add' xs' ys' ((x + y + c) / base)
let add xs ys = add' xs ys 0
答案 2 :(得分:0)
让我们看一下代码中的问题。我在评论中对问题进行了解释:
let rec add l1 l2 =
match l1, l2 with
| n::l1', m::l2' -> if n+m < 10000 then
(n+m)::(add l1' l2')
else
begin
(* in all these cases you don't check if 1+p is > base *)
match l1', l2' with
| p::l1'', q::l2'' -> ((n+m) - 10000)::(add ((1+p)::l1'') l2')
| p::l1'', [] -> ((n+m) - 10000)::(add ((1+p)::l1'') l2')
| [], q::l2'' -> ((n+m) - 10000)::(add l1' ((1+q)::l2''))
| [], [] -> ((n+m) - 10000)::[1]
end
| [], [] -> []
(* and the error above causes problem in these arms, since m can now be > base *)
| m::l1', [] -> m::(add l1' [])
| [], m::l2' -> m::(add [] l2')
让我们先把特殊情况放在一边,用一个值替换文字常量,重新设置多余的括号并修复进位错误。
let rec add l1 l2 base =
match l1, l2 with
| [], [] -> []
| m::l1', []
| [], m::l1' -> if m >= base then m-base::add l1' [1] base else m::l1'
| n::l1', m::l2' -> let r = n + m in
if r < base then
r::add l1' l2' base
else begin
match l1', l2' with
| [], [] -> [r-base ; 1]
| p::l1'', []
| [], p::l1'' -> r-base::add [] (1+q::l1'') base
| p::l1'', _ -> r-base::add (1+p::l1'') l2' base
end
现在我们可以看到可以提取一些代码并将其转换为专用函数:
let rec add l1 l2 base =
let rec carry = function
| [] -> []
| [x] when x >= base -> [x-base;1]
| x::y::l when x >= base -> x-base::carry (y+1::l)
| l -> l
in
match l1, l2 with
| [], [] -> []
| l1, []
| [], l1 -> carry l1
| n::l1', m::l2' -> let r = n + m in
if r < base then
r::add l1' l2' base
else begin
match l1', l2' with
| [], [] -> [r-base ; 1]
| l1'', []
| [] , l1'' -> carry (r::l1'')
| p::l1'', _ -> r-base::add (1+p::l1'') l2' base
end
现在您的代码应该与保留的进位一起使用,并且作为奖励可以使用任何自然基础。