N으로 표현

태그: , ,

카테고리: ,


출처 프로그래머스 - N으로 표현

사용 언어 자바

입력

  • N
  • number

제한사항

  • N은 1 이상 9 이하입니다.
  • number는 1 이상 32,000 이하입니다.
  • 수식에는 괄호와 사칙연산만 가능하며 나누기 연산에서 나머지는 무시합니다.
  • 최솟값이 8보다 크면 -1을 return 합니다.

문제는 number를 최소한의 N을 써서 표현하는 것이 목적이다
N은 붙여서 쓰거나 괄호와 사칙연산을 이용해서 표현이 가능하다

예시

  • 12 = 5 + 5 + (5 / 5) + (5 / 5)
  • 12 = 55 / 5 + 5 / 5
  • 12 = (55 + 5) / 5

N = 5, number = 12 일 때, N은 각각 6,5,4번씩 사용했고
이 중 가장 작은 경우인 4를 반환하면 된다

풀이과정

처음에는 number 이하의 수 중에 최대한 큰 수를 만들어서 빼는 것을 반복했고
결과를 보고 나서 문제를 잘못 이해했다는 것을 깨달았다

number 보다 큰 수에서 더 작은 수를 빼서 number를 만들 수도 있었고
제곱수로 나누거나 빼는 것도 가능했다

너무 많은 이 모든 경우의 수를 하나하나 다 만들어 주는것은 너무 난해했다

첫번째 힌트

첫번째 힌트는 최솟값이 8이하라는 것에서 찾았다

모든 경우의 수는

int number(int N의 갯수) {
    return number(N의 갯수 - i) 사칙연산 number(i);
}

위의 형태로 만들어진다고 생각했다

두 번째 힌트

두 번째로 찾은 힌트는 2개의 N으로 만들 수 있는 수에는 제한이 있다는 점이었다

이것은 N 두 개로 만들 수 있는 모든 경우의 수다

NN, 2N, 0, N^2, 1

이것들의 재료는 N이다
정확히 말하자면 N 한개로 만들수 있는 수로 만들어졌다

즉, N 3개로 만들수 있는 수는 (N 2개 수) 사칙연산 (N 1개 수)이다
4개는 (3, 1), (2, 2)
5개는 (4, 1), (3, 2)
6개는 (5, 1), (4, 2), (3, 3)
…

피보나치 수처럼 N의 사용 횟수별 경우의 수들로
다음 횟수의 경우의 수를 만들 수 있었다

놓친점

앞 뒤 순서가 상관있는 사칙연산들( -, / )이 있다는 것을 생각 못했다

제출 답안

import java.util.*;

class Solution {
    public int solution(int N, int number) {
        Set<Integer>[] sets = new Set[8];
        for (int i = 0; i < 8; i++) {
            sets[i] = new HashSet<>();
            sets[i].add(repeatN(N, i));
            for (int j = 0; j < (i + 1) / 2; j++) {
                for (int iNum : sets[j]) {
                    for (int jNum : sets[i - 1 - j]) {
                        sets[i].add(iNum + jNum); // 순서영향 없는 연산
                        sets[i].add(iNum * jNum); // 순서영향 없는 연산
                        sets[i].add(iNum - jNum);
                        sets[i].add(jNum - iNum);
                        sets[i].add(iNum / jNum);
                        sets[i].add(jNum / iNum);
                    }
                }
            }
            sets[i].removeIf(num -> num <= 0);
            if (sets[i].contains(number)) return i + 1;
        }
        return -1;
    }

    public int repeatN(int N, int digit) {
        return digit <= 0 ? N : repeatN(N * 10, digit - 1) + N;
    }
}

댓글남기기