안녕하세요, 여러분! 오늘은 코딩 테스트에서 자주 등장하는 문제 유형인 ‘수의 묶음으로 최댓값 만들기’에 대해 알아보겠습니다. 이 주제는 알고리즘적 사고를 기르고, 문제 해결 능력을 향상시키는데 큰 도움이 됩니다.
문제 설명
주어진 정수 배열에서 모든 수를 선택하여 최댓값을 만드는 문제입니다. 수를 묶어 곱할 수 있으며, 만약 두 수 A와 B를 묶는다면 새로운 수는 A * B가 됩니다. 최댓값을 만들기 위해서는 수를 어떻게 묶어야 할까요? 과연 최적의 방법은 무엇일까요?
문제 예시
입력: [1, 2, 3, 4, 5] 출력: 120 (1*2*3*4*5 = 120) 입력: [0, 0, 0, 1, 2] 출력: 2 (1*2 = 2, 나머지 0은 곱을 0으로 만들기 때문) 입력: [1, 2, 3, -1, -2] 출력: 6 (1*2*3 또는 -1*-2*3 가능)
문제 분석
이 문제는 선택한 숫자들을 어떻게 곱하는지가 중요한 관건입니다. 따라서 해결 방안으로는:
- 양수를 최대한 묶고, 음수도 상황에 따라 묶어야 합니다.
- 0이 포함된 경우, 0으로 곱해지는 상황은 피해야 합니다.
- 1은 다른 수와 곱했을 때 증가하지 않으므로 주의해야 합니다.
알고리즘 접근
알고리즘을 구성하는 주요 단계는 다음과 같습니다:
- 입력 배열에서 양수, 음수, 1을 분리합니다.
- 양수들은 가능한 최대한 곱합니다.
- 음수들도 짝을 지어 곱할 수 있습니다.
- 1은 따로 구분하여 양성 수의 곱에 더해주거나, 음수의 곱과 따로 관리합니다.
- 최종적으로 계산된 결과를 반환합니다.
구현
이제 파이썬으로 이를 구현해 보겠습니다:
def max_product(nums): positive = [] negative = [] zero_count = 0 product = 1 has_negative = False for num in nums: if num > 1: positive.append(num) elif num == 1: continue elif num < 0: negative.append(num) has_negative = True else: zero_count += 1 # 양수의 곱 for p in positive: product *= p # 음수의 짝지어 곱하기 negative.sort() if len(negative) % 2 == 1: negative.pop() # 홀수면 하나 제외 for n in negative: product *= n return product if product != 1 or (zero_count == 0 and not has_negative) else 0 # 테스트 print(max_product([1, 2, 3, 4, 5])) # 120 print(max_product([0, 0, 0, 1, 2])) # 2 print(max_product([1, 2, 3, -1, -2])) # 6
코드 설명
위의 코드는 배열을 순회하면서 각각의 숫자를 양수, 음수, 제로로 분류합니다. 이후, 양수는 무조건 곱하고, 음수는 짝이 지어진 것들만 곱하여 누적 결과를 만들어냅니다. 결과적으로, 생긴 값이 1이면, 특수한 경우(모든 수가 0 혹은 1로만 이루어진 배열)에 대해서 0 또는 1을 반환하도록 합니다.
복잡도 분석
이 알고리즘의 시간 복잡도는 O(N)입니다. 모든 수를 한 번씩만 확인하기 때문입니다. 공간 복잡도 또한 O(N)으로, 양수와 음수를 따로 배열에 저장하기 때문입니다.
결론
오늘은 ‘수의 묶음으로 최댓값 만들기’ 문제를 통해 알고리즘적 사고를 발전시키는 방법을 배웠습니다. 다양한 입력을 고려하여 최적의 결과를 도출해낼 수 있도록 유도하는 것이 중요한데, 이를 통해 본인의 코딩 실력을 한층 더 높일 수 있습니다. 다음 시간에는 다른 흥미로운 문제에 대해 다루도록 하겠습니다. 감사합니다!