hyelie
hyelie
Hyeil Jeong
       
글쓰기    관리    수식입력
  • 전체보기 (495)
    • PS (283)
      • Algorithm (28)
      • PS Log (244)
      • Contest (6)
      • Tips (5)
    • Development (52)
      • Java (14)
      • Spring (23)
      • SQL (2)
      • Node.js (2)
      • Socket.io (3)
      • Study (4)
      • Utils (4)
    • DevOps (36)
      • Git (5)
      • Docker (4)
      • Kubernetes (2)
      • GCP (3)
      • Environment Set Up (8)
      • Tutorial (12)
      • Figma (2)
    • CS (74)
      • OOP (7)
      • OS (24)
      • DB (2)
      • Network (24)
      • Architecture (0)
      • Security (2)
      • Software Design (0)
      • Parallel Computing (15)
    • Project (15)
      • Project N2T (5)
      • Project ASG (0)
      • Project Meerkat (1)
      • Model Checking (7)
      • Ideas (2)
    • 내가 하고싶은 것! (34)
      • Plan (16)
      • Software Maestro (10)
      • 취준 (8)
hELLO · Designed By 정상우.
hyelie

hyelie

PS/PS Log

23.04.16. 풀었던 문제들

Leetcode 1639. Number of Ways to Form a Target String Given a Dictionary

 DP 문제. 처음에 이해를 잘못해서 어렵게 푼 문제...

 

 words가 [abbac, eabbc, abbbc]와 같이 주어졌을 때 아래처럼 정렬해 보자.

  • abaac
  • eabbc
  • abbbc

 

 이렇게 두고, 만약 words[1][1]의 a를 골랐다고 하면 모든 word에 대해 index 1 이하인 것은 사용할 수 없다.

  • ab / aac
  • ea / bbc
  • ab / bbc

 

 이렇게 생각하면 words의 어떤 column j을 이용해 target[i]를 만들 수 있는지 여부를 판단하면 될 것 같다. 따라서, dp[i][j] : substring j까지 ith col 이용해 만드는 경우의 수라고 두자. 그러면

  • ith col에 있는 char 사용하는 경우 : dp[i][j] * ith col의 target[j] 개수
  • ith col에 있는 char 사용하지 않는 경우 : dp[i][j+1]

가 된다. 구현의 편의성을 위해 j = 0인 col의 모든 값은 0으로 두고, i = 0인 row는 모두  1로 두자. (i=0은 곱 계수를 1로 만들기 위함). 추가로 ith col의 target[j] 개수를 따로 저장하자. 그러면 쉽게 풀린다!

// Runtime 332 ms Beats 47.42%
// Memory 79.1 MB Beats 31.90%

typedef long long ll;

class Solution {
public:
    int MOD = 1e9 + 7, T, W, S;
    int numWays(vector<string>& words, string target) {
        T = target.size(), W = words.size(), S = words[0].size();
        vector<vector<int>> cnt(S, vector<int>(26, 0)); // cnt[i] : 모든 words들의 ith index의 char 개수
        for(int i = 0; i<W; i++){
            for(int j = 0; j<S; j++){
                cnt[j][words[i][j] - 'a']++;
            }
        }

        vector<vector<ll>> dp(S+1, vector<ll>(T+1));
        // dp[i][j] : substring j까지 ith col 이용해 만드는 경우의 수
        // ith col에 있는 char 사용하는 경우 dp[i][j] * ith col의 target[j] 개수
        // ith col에 있는 char 사용하지 않는 경우 dp[i][j+1]

        for(int i = 0; i<S; i++){
            dp[i][0] = 1;
            for(int j = 0; j<T; j++){
                dp[i + 1][j + 1] = ((cnt[i][target[j] - 'a'] * dp[i][j]) % MOD + dp[i][j + 1]) % MOD;
            }
        }

        return dp[S][T];
    }
};

 

시간복잡도

 target size를 T, words size를 W, word size를 S로 했을 때 W * S를 한 번, S * T를 한 번 순회하므로 O(S(W + T))이다.

 

공간복잡도

 S size vector, S * T size dp vector를 만드므로 O(ST)

 

후기

 솔직이 이 문제는 내가 졌다. 어제 문제도 그렇고... DP 너무 약한 것 같다. DP 할 때 항상 고민되는 것

  • top-down vs bottom-up
  • 이전 state s-1, 현 state s, 다음 state s+1이 있을 때, s-1을 이용해 s를 계산할지 vs s를 이용해 s+1을 계산할지

가 항상 고민이다. 이거 한끗 차이로 코드가 짧아지고 길어지고 해서... 근데 문제마다 다른 설정값을 가지고 있어서 어떤 게 optimal인지 항상 너무 어렵다. 노력밖에 답이 없다... 많이 풀어보자. 자신감 많이 깎이는군.

 

 

 

 

저작자표시 (새창열림)

'PS > PS Log' 카테고리의 다른 글

23.04.18. 풀었던 문제들  (0) 2023.04.18
23.04.17. 풀었던 문제들  (0) 2023.04.17
23.04.14. 풀었둔 문제들  (0) 2023.04.14
23.04.13. 풀었던 문제들  (0) 2023.04.13
23.04.12. 풀었던 문제들  (0) 2023.04.12
    hyelie
    hyelie

    티스토리툴바