1

我正在学习一些 Erlang 并从书中做练习,所以我被困在其中一个上。如果我引用整个问题然后解释我到目前为止所做的事情会更好:“如果通过重复应用下面的过程达到数字 1,正数是快乐的。1. 将数字的每个数字平方2. 计算所有平方的总和 例如,如果你从 19 开始:

 1 * 1 + 9 * 9 = 1 + 81 = 82
 8 * 8 + 2 * 2 = 64 + 4 = 68
 6 * 6 + 8 * 8 = 36 + 64 = 100
 1 * 1 + 0 * 0 + 0 * 0 = 1 + 0 + 0 = 1 

(即 19 是一个快乐的数字)你怎么知道一个数字什么时候不快乐?事实上,每个不开心的数字最终都会到达循环 4、16、37、58、89、145、42、20、4,……因此,在该循环中寻找任何数字(比如 4)就足够了,并得出结论:原来的号码不开心。编写函数happy/1 和all_happy/2,它们分别返回一个数字是否快乐(真或假)以及N 和M 之间的所有快乐数字。(提示:使用函数 digitize 和 sum)。例子:

 happy(28) → true
 happy(15) → false
 happy(5, 25) → [7, 10, 13, 19, 23]"

因此,我创建了一个 digitizer/1,它给定一个正数 N 返回该数字中的数字列表:

digitize(N) -> digitize1(N, []).
digitize1(N, Acc) when N > 0 -> digitize1(N div 10, [N rem 10| Acc]);
digitize1(N, Acc) when N == 0 -> Acc.

和总和/1:

sum(N) when  N > 0 -> N + sum(N-1);
sum(0) ->   0.

因此,对于快乐的数字,我到目前为止所做的是:

happy(N) -> happy1(digitize(N), []).
happy1([], Acc) -> (Acc);
happy1([Head|Tail], Acc1) -> happy1(Tail, [Head * Head|Acc1]).

它对列表的元素进行平方,但我无法想出如何对它们求和并递归地再次执行,直到达到 1 或 4。有什么帮助或想法吗?对于第二部分(all_happy/2),在我不称职的意见中,我应该使用列表理解,但同样,我不太确定如何实现它。谢谢你的时间。

4

2 回答 2

2

我注意到的一件事是你的happy1循环可以直接计算总和,你不需要列出然后添加它们:

calculate([], Total)->
  Total;
calculate([First | Rest], Total) ->
  calculate(Rest, Total + (First * First)).

对于您的问题的要点,您可以使用模式匹配来检测您是否达到了不满意的数字或是否达到了 1。

我有一个可行的实现,但我猜你想自己弄清楚细节。如果你想让我发布它,请告诉我。


这是我的解决方案:

-module(happy).

-export([happy/1]).

happy(1) ->
  happy;
happy(4) ->
  not_happy;
happy(Num) ->
  io:format("Current loop: ~p~n", [Num]),
  Digits = digitize(Num),
  happy(calculate(Digits, 0)).


digitize(N) -> digitize1(N, []).
digitize1(N, Acc) when N > 0 -> digitize1(N div 10, [N rem 10| Acc]);
digitize1(N, Acc) when N == 0 -> Acc.

calculate([], Total)->
  Total;
calculate([First | Rest], Total) ->
  calculate(Rest, Total + (First * First)).

输出:

3> happy:happy(55).
Current loop: 55
Current loop: 50
Current loop: 25
Current loop: 29
Current loop: 85
Current loop: 89
Current loop: 145
Current loop: 42
Current loop: 20
not_happy
4> happy:happy(4). 
not_happy
5> happy:happy(19).
Current loop: 19
Current loop: 82
Current loop: 68
Current loop: 100
happy
6> happy:happy(20).
Current loop: 20
not_happy
7> happy:happy(21).
Current loop: 21
Current loop: 5
Current loop: 25
Current loop: 29
Current loop: 85
Current loop: 89
Current loop: 145
Current loop: 42
Current loop: 20
not_happy

如果您对如何使用列表推导感兴趣,这里的主要子句跳过了计算方法并将lists:sum函数与构建列表一起使用:

happy(Num) ->
  io:format("Current loop: ~p~n", [Num]),
  Digits = [ X * X || X <- digitize(Num)],
  happy(lists:sum(Digits)).
于 2013-09-24T23:31:14.770 回答
0

通过尾递归实现的另一种解决方案:

digitize(N) -> digitize1(N, [],N).
digitize1(N, Acc,M) when N > 0 -> digitize1(N div 10, [N rem 10| Acc],M);
digitize1(N, Acc,M) when N == 0 -> sum_digits(Acc,0,M).

sum_digits([],Acc,N) when Acc == 1 -> {happy,N,Acc};
sum_digits([], Acc,N) when Acc == 4 -> {unhappy,N,Acc};
sum_digits([],Acc,N) -> {digitize,Acc}, digitize1(Acc,[],N);
sum_digits([H|T],Acc,N)-> sum_digits(T,H*H+Acc,N).

使用:

1> c('test.erl').
test.erl:15: Warning: a term is constructed, but never used
{ok,test}
2> c('test.erl').
test.erl:15: Warning: a term is constructed, but never used
{ok,test}
3> c('test.erl').
test.erl:15: Warning: a term is constructed, but never used
{ok,test}
4> test:digitize(55).
{unhappy,55,4}
5> test:digitize(19).
{happy,19,1}
6> test:digitize(5). 
{unhappy,5,4}
7> test:digitize(20).
{unhappy,20,4}
8> test:digitize(21).
{unhappy,21,4}
于 2014-11-12T21:05:45.880 回答