2024. 3. 7. 09:23ㆍIT/TIL
오늘의 TIL은 N으로 표현이라는 프로그래머스의 문제에 대한 내용이다.
문제 링크
https://school.programmers.co.kr/learn/courses/30/lessons/42895
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
문제 설명
아래와 같이 5와 사칙연산만으로 12를 표현할 수 있다.
12 = 5 + 5 + (5 / 5) + (5 / 5)
12 = 55 / 5 + 5 / 5
12 = (55 + 5) / 5
위의 경우에서 5를 사용한 횟수는 각각 6회, 5회, 4회이다. 이 중 가장 작은 경우는 4회이다.
이처럼 숫자 N과 number가 주어질 때, N과 사칙연산만을 사용해서 표현할 수 있는 방법 중
N의 사용횟수의 최솟값을 return 하시오.
제한 조건
N은 1 이상 9 이하이다.
number는 1 이상 32,000 이하이다.
수식에는 괄호와 사칙연산만 가능하며 나누기 연산에서 나머지는 무시한다.
최솟값이 8보다 크면 -1을 return한다.
해결 방안
동적 계획법(Dynamic Programming)을 사용하여 접근.
N과 number가 같다면 1을 return
N의 사용 횟수가 8을 초과하면 -1을 return -> 최대 시행 횟수가 8회가 되도록 설계
모든 가능한 조합을 고려하면서 중복을 최소화 -> HashSet 사용
조합에 사용할 수 있는 숫자들 N, NN, NNN, ... , NNNNNNNN을
미리 만들어두고 이를 사용하면서 number를 만들 수 있는지 확인.
나눗셈을 하는 경우에는 0이 나오지 않게 주의
통과한 답안
using System;
using System.Collections.Generic;
public class Solution {
public int solution(int N, int number) {
if (N == number)
{
return 1;
}
List<HashSet<int>> dp = new List<HashSet<int>>();
for (int i = 0; i <= 8; i ++)
{
dp.Add(new HashSet<int>());
}
int baseNum = 0;
for (int i = 1; i <= 8; i++)
{
baseNum = 10 * baseNum + N;
dp[i].Add(baseNum);
}
for (int i = 2; i <= 8; i++)
{
for (int j = 1; j < i; j++)
{
foreach (int a in dp[j])
{
foreach (int b in dp[i - j])
{
dp[i].Add(a + b);
dp[i].Add(a - b);
dp[i].Add(a * b);
if (b != 0)
{
dp[i].Add(a / b);
}
}
}
}
if (dp[i].Contains(number))
{
return i;
}
}
return -1;
}
}
초기화 및 DP 구현
if (N == number)
{
return 1;
}
List<HashSet<int>> dp = new List<HashSet<int>>();
for (int i = 0; i <= 8; i ++)
{
dp.Add(new HashSet<int>());
}
우선 처음 생각했던대로 N과 number가 같다면 사용하는 N의 개수는 1개가 되므로 1을 return한다.
이후에 각 단계별로 가능한 모든 결과값을 저장하는 dp를 HashSet을 이용하여 만든다.
BaseNum의 초기화
int baseNum = 0;
for (int i = 1; i <= 8; i++)
{
baseNum = 10 * baseNum + N;
dp[i].Add(baseNum);
}
N을 사용하는 경우 N을 연결하여 사용하는 NN, NNN을 미리 baseNum으로 초기화한다.
문제 풀이
for (int i = 2; i <= 8; i++)
{
for (int j = 1; j < i; j++)
{
foreach (int a in dp[j])
{
foreach (int b in dp[i - j])
{
dp[i].Add(a + b);
dp[i].Add(a - b);
dp[i].Add(a * b);
if (b != 0)
{
dp[i].Add(a / b);
}
}
}
}
if (dp[i].Contains(number))
{
return i;
}
}
return -1;
N을 2회부터 8회 사용하는 경우에 대해서 두 개의 수를 이용하여 만들 수 있는 조합들을 만들고
해당 조합들을 사용한 N의 개수의 인덱스에 추가한다.
이 방법들을 반복하면서 점차 많은 조합수들을 dp에 추가하고,
이 조합수들 중에서 number에 해당하는 수가 있는지 확인하고,
해당하는 수가 있다면 그 인덱스(N을 사용한 횟수)를 return한다.
오늘은 프로그래머스의 N으로 표현하기 라는 문제를 해결했는데
다이나믹 프로그래밍이라고 불리는 개념을 알고리즘 문제에서 사용한다고 들었고,
이를 사용하는 문제들을 접했지만 다른 방식으로 문제를 해결했었는데
오늘을 기회 삼아 DP를 좀 더 자세히 공부하고 이를 응용하여 문제를 풀이하였다.
문제 풀이만으로는 약간 부족한 부분이 느껴져서 이를 좀 더 자세히 정리하는 시간을 가지려고 한다.
'IT > TIL' 카테고리의 다른 글
20240308_조이스틱(프로그래머스) (0) | 2024.03.09 |
---|---|
20240307_동적 계획법 (0) | 2024.03.07 |
20240305_인사고과(프로그래머스) (1) | 2024.03.05 |
20240304_가장 긴 팰린드롬(프로그래머스) (0) | 2024.03.04 |
20240229_베스트앨범(프로그래머스) (2) | 2024.02.29 |