Algorithm/프로그래머스

[프로그래머스 : 코딩테스트 연습 - Swift] 원소들의 곱과 합

버스트 캐넌 2023. 10. 25. 07:24

글 작성에 앞서 본 블로그의 모든 게시글은 블로그 주인의 개발 일지(일기) 형태의 게시글입니다.

정보를 나누는 방식보단, 제가 했던 방식을 공유하는 식의 글이라 읽어도 제대로 이해를 못 하실 수 있거나 더 좋은 다른 방법이 존재할 수 있습니다.

이 점 양해해 주시며 본 블로그의 게시글을 읽어주시면 감사하겠습니다.

programmers

안녕하세요 버스트캐넌입니다.

 

오늘은 프로그래머스 LV0 원소들의 곱과 합을 풀어보겠습니다.

 

문제


문제 설명

  • 정수가 담긴 리스트 num_list가 주어질 때, 모든 원소들의 곱이 모든 원소들의 합의 제곱보다 작으면 1을 크면 0을 return 하도록 solution 함수를 완성해 주세요.

제한 사항

  • 2 ≤ num_list의 길이 ≤ 10
  • 1 ≤ num_list의 원소 ≤ 9

입출력 예

  • num_list = [3, 4, 5, 2, 1], return = 1
  • 모든 원소의 곱은 120, 합의 제곱은 225이므로 1을 return 합니다.

 

풀이


import Foundation

func solution(_ num_list:[Int]) -> Int {
    var sum = 0
    var mul = 1
    
    for i in 0...num_list.count-1{
        sum += num_list[i]
    }
    for i in 0...num_list.count-1{
        mul *= num_list[i]
    }
    
    return mul < sum*sum ? 1 : 0
}

기본 개념


알아야 할 개념이 있는데, 제 풀이에 쓰인 것이 아니고 다른 사람 풀이에 쓰인 것이라 뒤에서 개념 설명 하겠습니다.

 

코드 풀이


var sum = 0
var mul = 1

원소들의 합의 제곱이랑, 모든 원소의 곱을 저장해두기 위해 변수 두 개를 선언하였습니다.

 

여기서, 모든 원소의 곱도 처음에는 0으로 선언하였으나, 추후 문제 때문에 1로 선언하였습니다.

 

이건 뒤에서 설명드릴게요.

for i in 0...num_list.count-1{
        sum += num_list[i]
}

num_list의 배열을 처음부터 돌며, sum에 원소들의 합을 전부 넣었습니다.

 

여기서 쓰인 +=는 복합 할당 연산자로, 앞 뒤 값을 더한 후 앞에 할당해 주는 연산자입니다.

 

a += b를 예시로 들면 a = a + b입니다.

for i in 0...num_list.count-1{
        mul *= num_list[i]
}

원소의 곱셈도 마찬가지로, 복합 할당 연산자를 이용하여 전부 곱해주었습니다.

 

여기서, 아까 mul을 처음 선언할 때 1을 준 이유가 나타나는데, *= 의 경우는 앞 뒤값의 곱을 앞에 할당해 주는데,

 

mul을 0으로 선언해 버리면, 어떤 수가 나오던 결과가 0이 나와서 문제의 값과 달랐습니다.

 

그래서 곱셈에 영향을 전혀 주지 않는 1로 선언하였습니다.

 

return mul < sum*sum ? 1 : 0

 

그리고 마지막으로, 삼항연산자를 사용하여 모든 원소의 곱셈이 모든 원소의 덧셈의 제곱보다 작으면 1을, 크면 0을 반환하는 코드를 작성하였습니다.

무난하게 통과된 모습

다른 사람 코드 탐구


코드를 더 간단하게 하는 방법이 떠오를 랑말랑 했는데 결국엔 안 떠올라서 또 멍청한 코드를 작성해 버렸네요.

 

다른 사람 코드를 분석해 보죠.

 

import Foundation

func solution(_ num_list:[Int]) -> Int {
    return num_list.reduce(1, *) < num_list.reduce(0, +) * num_list.reduce(0, +) ? 1 : 0
}

... 아니!

 

reduce를 배운 지 얼마 되지도 않았는데 벌써 까먹어서 활용을 못했네요...

 

여기서 간단하게 이론 공부를 해봅시다.

 

reduce


reduce는 컨테이너(컬렉션) 내부의 콘텐츠(항목, 요소)를 하나로 합하는 기능을 실행하는 Swift의 고차함수 중 하나입니다.

 

reduce는 두 가지의 형태를 띠고 있습니다.

public func reduce<Result>(_ initialResult: Result,
        _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
  • 클로저가 각 요소를 전달받아 연산한 후 값을 다음 클로저 실행을 위해 반환하며 순환하는 형태
  • initialResult : 초깃값을 지정해 주고 nextPartialResult에 매개변수를 통해 클로저를 전달받음
  • nextPartialResult클로저의 첫 번째 매개변수를 initialResult 매개변수를 통해 전달받은 초깃값 또는 이전 클로저의 결괏값을 이용
public func reduce<Result>(into initialResult: Result,
        _ updateAccumulatingResult: (inout Result, Element) throws -> ()) rethrows ->
        Result
  • 컨테이너(컬렉션)를 순환하며 클로저가 실행되고, 따로 결괏값을 반환하지 않고 inout 매개변수를 이용하여 초깃값에 직접 연산을 실행
  • updateAccumulatingResult 클로저의 첫 번째 매개변수 Result는 초깃값으로 받은 값 또는 이전에 실행된 클로저 때문에 변경되어 있는 결괏값

 

저희는 여기서 첫 번째 형태를 참고해서 코드를 작성해 볼 수 있습니다.

 

var sum = num_list.reduce(0, { (result: Int, next: Int) -> Int in
    return result + next
} )

간단히 돌아가는 방식을 설명해 보자면, 초깃값 0 이 result, 그다음(첫 번째 매개변수) 3으로 시작하여 0과 3을 더해서 3을 반환하고,

 

다시 순환하여 이전 클로저의 결괏값(초깃값 + 첫 번째 매개변수)인 3과 그다음(두 번째 매개변수) 4를 더하여 7을 반환하고...

 

를 순환하는 고차함수 라고 할 수 있겠네요.

 

이 코드를 더 간단하게 축약할 수 있습니다.

// 축약 ver.1
sum = num_list.reduce(0, {
    return $0 + $1
} )
// 축약 ver.2
sum = num_list.reduce(0, { $0 + $1 } )
// 축약 ver.3
sum = num_list.reduce(0, +)

여기서는 ver.3의 축약 버전을 사용했네요.

 

곱셈도 마찬가지로 ver.3의 reduce 고차함수를 사용하여 간단하게 코드를 작성하였네요.

 

아... 고차함수에 익숙해져야 하는데 배워놓고 활용을 못했네요 ㅠㅠㅠ

 

이상 원소들의 곱과 합 문제를 풀어보았습니다.

 

포스팅 읽어주셔서 감사합니다.

 

좋은 하루 보내세요~

 

 

궁금한 점이나 지적해야 할 부분이 있으시면 댓글 남겨주세요. 블로그 주인의 상황에 따라 답변이 없을 수 있으나, 최대한 피드백해 드리겠습니다.