[프로그래머스] 단어 퍼즐

Jhanoo·2024년 10월 15일

알고리즘 스터디

목록 보기
62/80

[level 4] 단어 퍼즐 - 12983

문제 링크

성능 요약

메모리: 75.4 MB, 시간: 23.67 ms

구분

코딩테스트 연습 > 2017 팁스타운

채점결과

정확성: 59.4
효율성: 40.6
합계: 100.0 / 100.0

제출 일자

2024년 10월 15일 15:13:07

문제 설명

단어 퍼즐은 주어진 단어 조각들을 이용해서 주어진 문장을 완성하는 퍼즐입니다. 이때, 주어진 각 단어 조각들은 각각 무한개씩 있다고 가정합니다. 예를 들어 주어진 단어 조각이 [“ba”, “na”, “n”, “a”]인 경우 "ba", "na", "n", "a" 단어 조각이 각각 무한개씩 있습니다. 이때, 만들어야 하는 문장이 “banana”라면 “ba”, “na”, “n”, “a”의 4개를 사용하여 문장을 완성할 수 있지만, “ba”, “na”, “na”의 3개만을 사용해도 “banana”를 완성할 수 있습니다. 사용 가능한 단어 조각들을 담고 있는 배열 strs와 완성해야 하는 문자열 t가 매개변수로 주어질 때, 주어진 문장을 완성하기 위해 사용해야 하는 단어조각 개수의 최솟값을 return 하도록 solution 함수를 완성해 주세요. 만약 주어진 문장을 완성하는 것이 불가능하면 -1을 return 하세요.

제한사항
  • strs는 사용 가능한 단어 조각들이 들어있는 배열로, 길이는 1 이상 100 이하입니다.
  • strs의 각 원소는 사용 가능한 단어조각들이 중복 없이 들어있습니다.
  • 사용 가능한 단어 조각들은 문자열 형태이며, 모든 단어 조각의 길이는 1 이상 5 이하입니다.
  • t는 완성해야 하는 문자열이며 길이는 1 이상 20,000 이하입니다.
  • 모든 문자열은 알파벳 소문자로만 이루어져 있습니다.

입출력 예
strs t result
["ba","na","n","a"] "banana" 3
["app","ap","p","l","e","ple","pp"] "apple" 2
["ba","an","nan","ban","n"] "banana" -1
입출력 예 설명

입출력 예 #1
문제의 예시와 같습니다.

입출력 예 #2
"ap" 1개, "ple" 1개의 총 2개로 "apple"을 만들 수 있으므로 필요한 단어 개수의 최솟값은 2를 return 합니다.

입출력 예 #3
주어진 단어로는 "banana"를 만들 수 없으므로 -1을 return 합니다.

출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges


풀이

  • DP로 접근
  • dp[i] = t의 0~i 번째 문자열까지의 최소 조각 개수
  • 조각의 길이는 1~5 이므로 for문에서 dp[i]를 갱신할 때 dp[i-5] ~ dp[i-1] 까지만 체크한다.
    체크할 때, t.substring(j, i)가 set에 있는지(조각 인지) 확인한다.
  • 처음엔 안에 있는 for문을 5개 까지만 하지 않고 0~(i-1)번 돌렸다가 효율성 테스트에서 시간초과가 났었다...
    하지만 단어 조각 길이가 1~5이므로 많아봤자 5번만 돌리면 되는 문제
  • 시간복잡도를 계산하면
    DP배열 초기화 비용: O(N+1) = O(N) = (최대 20001)
    HashSet에 단어 조각 삽입 비용: O(strs.length()) = (최대 100)
    조각 확인 비용: O(N*M) (단, 1<=M<=5) = O(5N) = O(N)
    따라서 시간 복잡도는 O(N) 이 나온다.

코드

import java.util.Arrays;
import java.util.Set;
import java.util.HashSet;

class Solution {
    
    public int solution(String[] strs, String t) {
		int n = t.length();
		int[] dp = new int[n + 1];
		Arrays.fill(dp, 987654321);
		dp[0] = 0;

		// HashSet에 단어 조각 삽입
		Set<String> set = new HashSet<>(Arrays.asList(strs));

		// dp[i]는 t의 0부터 i까지의 최소 조각 수
		for (int i = 1; i <= n; i++) {
			// 최대 5글자까지 조각을 확인 (조각 길이는 최대 5)
			for (int j = Math.max(0, i - 5); j < i; j++) {
				// j에서 i까지의 부분 문자열이 유효한지 확인
				if (set.contains(t.substring(j, i))) {
					dp[i] = Math.min(dp[i], dp[j] + 1);
				}
			}
		}

		// t의 끝까지 완성할 수 없다면 -1을 반환
		return dp[n] > 20000 ? -1 : dp[n];
	}
}
profile
어떻게든 해내는 사람

2개의 댓글

comment-user-thumbnail
2024년 10월 17일

신 찬 우

1개의 답글