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;
    }
}

댓글남기기