레이블이 Self Number인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Self Number인 게시물을 표시합니다. 모든 게시물 표시

2007년 8월 19일 일요일

Erlang 공부 - 넥슨 입사 시험 문제 1 번 풀이

지난 번에 Common Lisp으로 풀어 본 넥슨 입사 시험 문제 1 번에 대해서 이번에는 Erlang으로 다시 한번 시도해봤습니다.

상세한 문제 내용은 이전 글을 참고해주시고, 간단히 요약을 하면 다음과 같습니다.
1부터 5000 사이의 Self Number들의 합을 구하시오.

풀이 내용은 다음과 같습니다.
-module(selfnum).
-export([sum_of_digits/1,
generate/1,
get_self_numbers/2,
get_sum_of_self_numbers/2]).

sum_of_digits(N) ->
Digits = integer_to_list(N),
sum_of_digits1(Digits).

sum_of_digits1(Digits) ->
Nums = lists:map(fun(D) ->
D - $0 end,
Digits),
lists:sum(Nums).

generate(N) when N > 0 ->
N + sum_of_digits(N).

get_self_numbers(M, N) when M =< N ->
Range_Nums = lists:seq(M, N),
Gen_Nums = lists:map(fun generate/1, Range_Nums),
lists:subtract(Range_Nums, Gen_Nums).

get_sum_of_self_numbers(M, N) when M =< N ->
Self_Nums = get_self_numbers(M, N),
lists:sum(Self_Nums).

sum_of_digits 메서드(method)를 다르게 구현해봤습니다.
-module(selfnum).
-export([sum_of_digits/1,
generate/1,
get_self_numbers/2,
get_sum_of_self_numbers/2]).

sum_of_digits(N) ->
Digits = integer_to_list(N),
sum_of_digits(Digits, 0).

%%---------------------------------------
%% Tail-recursion 방식으로 구현
sum_of_digits([D|Rest], Acc) ->
I = D - $0,
sum_of_digits(Rest, Acc + I);
sum_of_digits([], Acc) ->
Acc.
%%---------------------------------------

generate(N) when N > 0 ->
N + sum_of_digits(N).

get_self_numbers(M, N) when M =< N ->
Range_Nums = lists:seq(M, N),
Gen_Nums = lists:map(fun generate/1, Range_Nums),
lists:subtract(Range_Nums, Gen_Nums).

get_sum_of_self_numbers(M, N) when M =< N ->
Self_Nums = get_self_numbers(M, N),
lists:sum(Self_Nums).

compile하고 각 메서드에 대해 실행한 결과는 다음과 같습니다.


[그림 1] 실행 결과

Erlang도 예전부터 관심은 있었는데, 계속 공부를 미루다 최근에 와서야 마음 먹고 집중해보고 있습니다. 오랫동안 C/C++, Java 관련 일만 해와서인지 패러다임이 다른 프로그래밍 언어에 익숙해지는 것이 쉽지 않습니다. 하지만, 재미있습니다. 모르고 있던 새로운 것을 알게 된다는 것은 그 자체만으로도 충분히 기쁨입니다. :)

2007년 1월 7일 일요일

Common Lisp 공부 - 넥슨 입사 문제 1 번 풀이

요즘 공부 좀 해보려고 이것 저것 찔러보고 있는 중입니다. 아무 것도 하지 않고 계속 시간만 보내다가는 정말 머리가 굳어버릴 것만 같은 위기감을 느꼈기 때문이죠. 새해도 되고 했으니 설사 '작심삼일(作心三日)'이 될지언정 시도조차 하지 않아서야 사람이라고 하겠습니까.. 쩝..

아무튼, 찔러보는 것 중에서 Common Lisp이 있는데, 애자일 이야기에서 우연히 접하게 된 넥슨 입사 문제 중 1 번을 시험 삼아 구현해보았습니다. 공부를 막 시작한지라 구현 내용이 다소 비효율적이고 어눌할 수도 있으니 너그러이 이해해주세요. ;-)

문제 내용은 다음과 같습니다.
어떤 자연수 n이 있을 때, d(n)을 n의 각 자릿수 숫자들과 n 자신을 더한 숫자라고 정의하자. 예를 들어 d(91) = 9 + 1 + 91 = 101 이다. 이 때, n을 d(n)의 제네레이터(generator)라고 한다. 위의 예에서 91은 101의 제네레이터이다. 어떤 숫자들은 하나 이상의 제네레이터를 가지고 있는데, 101의 제네레이터는 91 뿐 아니라 100도 있다. 그런데 반대로, 제네레이터가 없는 숫자들도 있으며, 이런 숫자를 인도의 수학자 Kaprekar가 셀프 넘버(self-number)라 이름 붙였다. 예를 들어 1,3,5,7,9,20,31 은 셀프 넘버 들이다.

1 이상이고 5000 보다 작은 모든 셀프 넘버들의 합을 구하라.

풀이 내용은 다음과 같습니다.
;; 주어진 수의 각 자리수의 합을 구한다.
;; (예, 352 -> 3 + 5 + 2)
(defun sum-of-each-digit (x)
(if (< x 10)
x
(+ (mod x 10)
(sum-of-each-digit (truncate (/ x 10))))))

;; 주어진 수의 generated number를 구한다.
(defun get-generated-number (x)
(+ x (sum-of-each-digit x)))

;; 주어진 범위 내에 존재하는 generated number의 list를 구한다.
;; 범위: (x <= r < y)
(defun get-generated-number-list (x y)
(do ((i x (1+ i))
(gnum (get-generated-number x)
(get-generated-number i))
(gnums ()))
((or (>= gnum y) (>= i y))
(remove-duplicates (sort gnums #'<)))
(push gnum gnums)))

;; 주어진 범위 내의 정수 list를 구한다.
;; 범위: (x <= r < y)
(defun make-number-range-list (x y)
(do ((i x (1+ i))
(rnums ()))
((>= i y) (reverse rnums))
(push i rnums)))

;; 주어진 범위 내에 존재하는 Self Number의 list를 구한다.
;; 범위: (x <= r < y)
(defun get-self-number-list (x y)
(set-difference
(make-number-range-list x y)
(get-generated-number-list x y)))

;; 주어진 범위 내에 존재하는 Self Number의 합을 구한다.
;; 범위: (x <= r < y)
(defun sum-of-self-number-list (x y)
(apply #'+ (get-self-number-list x y)))

;; 1부터 5000 사이에 존재하는 Self Number들의 합을 구한다.
(sum-of-self-number-list 1 5000)

결과: 1227365