coding test

[파이썬] 단어 퍼즐

잔망루피 2021. 3. 20. 11:36

문제 설명

단어 퍼즐은 주어진 단어 조각들을 이용해서 주어진 문장을 완성하는 퍼즐입니다. 이때, 주어진 각 단어 조각들은 각각 무한개씩 있다고 가정합니다. 예를 들어 주어진 단어 조각이 [“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 합니다.

 

 

✨ 나의 풀이

# 실패
def solution(strs, t):
    answer = -1
    length=len(t)
    dp=[set() for _ in range(100)]
    dp[0].update(strs)
    for i in range(1, 100) :
        for prev in dp[i-1] :
            for s in strs :
                new_s=prev + s
                if len(new_s) > length :
                    continue
                elif new_s[0] != t[0] :     # 첫 문자가 다름
                    continue
                dp[i].add(new_s)
                if new_s == t :
                    return i+1
    
    return answer

34.4점

 

 

# 실패
from collections import defaultdict

def solution(strs, t):
    answer = 0
    length = len(t)
    dic = defaultdict(list)

    for s in strs:
        dic[s[0]].append(s)

    idx = 0
    while idx < length:
        for val in dic[t[idx]]:
            len_val = len(val)  # 부분 문자열의 길이
            if t[idx: idx + len_val] == val:
                idx = max(idx, idx + len_val)
        answer += 1
    return answer

2번째 케이스의 경우 "app", "l", "e"가 되어 3이 나온다.

완전탐색을 해야할 것 같다.

 

 

🎀 다른 사람 풀이

# https://deok2kim.tistory.com/124
def solution(strs, t):
    n = len(t)		# 목표 문자열의 길이
    dp = [0] * (n + 1)
    strs = set(strs)  # set을 사용하면 탐색할 때 시간복잡도 O(1)

    for i in range(1, n + 1):
        dp[i] = float('inf')  # i번째 시작시 최댓값으로 바꿔줌(최솟값 비교를 위해)
        for k in range(1, 6):	# 단어 조각의 길이
            # 인덱스 범위 때문에..
            if i - k < 0:
                s = 0
            else:
                s = i - k
            if t[s:i] in strs:		# 단어 조각 검색
                dp[i] = min(dp[i], dp[i - k] + 1)
    if dp[-1] == float('inf'):		# 반복문이 끝난 후 무한대 값이 있으면
        answer = -1
    else:						
        answer = dp[-1]

    return answer

반복문을 통해 목표 문자열이 set에 있는지 검사한다.

있으면 작은 값을 dp[i]에 넣는다.

 

 

def solution(strs, t):
    n = len(t)
    memo=[float("inf")] * (n+1)
    memo[0]=0
    sizes=set(len(s) for s in strs)
    strs=set(strs)
    for i in range(n+1) :	# t의 시작 인덱스
        for size in sizes :
            if i + size < n + 1 and t[i : i + size] in strs :
                memo[i + size]=min(memo[i + size], memo[i] + 1)
    return memo[n] if memo[n] < float("inf") else -1

DP

위에보다 좀더 효율적인 게 사용 가능한 단어 조각의 길이를 이용한다.

없는 길이는 실행 안 하니까 효율적이다.

시작 인덱스 i에 단어 조각의 길이 size를 더한 i + size가 n+1보다 작고 슬라이싱한 문자열이 단어 조각 집합 strs에 있으면(if i+size < n+1 and t[i:i+size] in strs) 리스트에 기록한다.

 

 

문제 출처 : 프로그래머스

반응형

'coding test' 카테고리의 다른 글

[파이썬] 디스크 컨트롤러  (0) 2021.03.25
[파이썬, Java] 네트워크  (0) 2021.03.24
[파이썬] 스티커 모으기  (0) 2021.03.20
[파이썬] 땅따먹기  (0) 2021.03.19
[파이썬] 자릿수 더하기  (2) 2021.03.19