Skip to content

Commit 167ea00

Browse files
committed
풀이: 릿코드.756.Pyramid Transition Matrix
?: DFS & 메모이제이션 & 백트래킹을 이용해 풀이
1 parent 6298e2b commit 167ea00

3 files changed

Lines changed: 261 additions & 0 deletions

File tree

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# 756. Pyramid Transition Matrix
2+
3+
[링크](https://leetcode.com/problems/pyramid-transition-matrix/description/)
4+
5+
| 난이도 |
6+
| :----: |
7+
| Medium |
8+
9+
## 설계
10+
11+
### 시간 복잡도
12+
13+
알파벳의 갯수를 A, bottom의 길이를 N이라 하자.
14+
15+
가능한 방법들을 백트래킹과 메모이제이션을 통해 DFS로 탐색할 수 있다.
16+
17+
이에 O(A^N)의 시간 복잡도를 사용한다.
18+
19+
### 공간 복잡도
20+
21+
각 과정마다 다음 문자열을 생성하는데 O(N^2)의 공간 복잡도를 사용한다.
22+
23+
### DFS & 메모이제이션 & 백트래킹
24+
25+
| 내 코드 (ms) | 시간 복잡도 | 공간 복잡도 |
26+
| :----------: | :---------: | :---------: |
27+
| 58 | O(A^N) | O(N^2) |
28+
29+
현재 문자열에서 길이가 1 작은 다음 문자열을 생성하는 모든 방법들을 탐색하며, 길이가 1이 되는지 확인한다.
30+
31+
이 때 메모이제이션을 통해 이미 탐색한 문자열에 대해서는 다시 탐색하지 않도록 한다.
32+
33+
또한 현재 생성된 문자열에서 다음 단계로 생성이 불가능한 경우는 백트래킹을 통해 탐색하지 않는다.
34+
35+
```cpp
36+
unordered_map<string, vector<char>> um;
37+
unordered_map<string, bool> dp;
38+
39+
bool recursive(string& line) {
40+
int size = line.size();
41+
42+
if (size == 1) return true;
43+
if (dp.count(line)) return dp[line];
44+
45+
vector<vector<char>> ch(size - 1);
46+
47+
for (int i = 0; i < size - 1; i++) {
48+
string key = {line[i], line[i + 1]};
49+
50+
for (char& c : um[key]) {
51+
ch[i].push_back(c);
52+
}
53+
}
54+
55+
unordered_set<string> us;
56+
57+
function<void(int, string&)> dfs = [&](int i, string& cur) {
58+
if (i == size - 1) {
59+
us.insert(cur);
60+
return;
61+
}
62+
63+
for (char& c : ch[i]) {
64+
if (cur.size() > 0) {
65+
string key = {cur.back(), c};
66+
if (um.count(key) == 0) continue;
67+
}
68+
69+
cur.push_back(c);
70+
dfs(i + 1, cur);
71+
cur.pop_back();
72+
}
73+
};
74+
75+
string cur = "";
76+
dfs(0, cur);
77+
78+
bool ret = false;
79+
for (string next : us) {
80+
ret |= recursive(next);
81+
if (ret) break;
82+
}
83+
return dp[line] = ret;
84+
}
85+
86+
bool pyramidTransition(string bottom, vector<string>& allowed) {
87+
for (string& s : allowed) {
88+
string key = {s[0], s[1]};
89+
char c = s[2];
90+
91+
um[key].push_back(c);
92+
}
93+
94+
return recursive(bottom);
95+
}
96+
```
97+
98+
## 고생한 점
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#include <algorithm>
2+
#include <climits>
3+
#include <cmath>
4+
#include <functional>
5+
#include <iostream>
6+
#include <map>
7+
#include <numeric>
8+
#include <queue>
9+
#include <set>
10+
#include <stack>
11+
#include <string>
12+
#include <unordered_map>
13+
#include <unordered_set>
14+
#include <vector>
15+
16+
using namespace std;
17+
18+
// use DFS with memoization
19+
// time : O(A^N)
20+
// space : O(N^2)
21+
class Solution {
22+
private:
23+
unordered_map<string, vector<char>> um;
24+
unordered_map<string, bool> dp;
25+
26+
bool recursive(string& line) {
27+
int size = line.size();
28+
29+
if (size == 1) return true;
30+
if (dp.count(line)) return dp[line];
31+
32+
vector<vector<char>> ch(size - 1);
33+
34+
for (int i = 0; i < size - 1; i++) {
35+
string key = {line[i], line[i + 1]};
36+
37+
for (char& c : um[key]) {
38+
ch[i].push_back(c);
39+
}
40+
}
41+
42+
unordered_set<string> us;
43+
unordered_set<string> visited;
44+
45+
queue<string> q;
46+
q.push("");
47+
48+
while (!q.empty()) {
49+
string cur = q.front();
50+
q.pop();
51+
52+
if (cur.size() == size - 1) {
53+
us.insert(cur);
54+
continue;
55+
}
56+
57+
for (char& c : ch[cur.size()]) {
58+
string next = cur + c;
59+
if (visited.count(next)) continue;
60+
if (next.size() >= 2 &&
61+
um.count({next[next.size() - 2], next[next.size() - 1]}) == 0)
62+
continue;
63+
64+
visited.insert(next);
65+
q.push(next);
66+
}
67+
}
68+
69+
bool ret = false;
70+
for (string next : us) {
71+
ret |= recursive(next);
72+
if (ret) break;
73+
}
74+
return dp[line] = ret;
75+
}
76+
77+
public:
78+
bool pyramidTransition(string bottom, vector<string>& allowed) {
79+
for (string& s : allowed) {
80+
string key = {s[0], s[1]};
81+
char c = s[2];
82+
83+
um[key].push_back(c);
84+
}
85+
86+
return recursive(bottom);
87+
}
88+
};
89+
90+
// use DFS with memoization
91+
// time : O(A^N)
92+
// space : O(N^2)
93+
class Solution {
94+
private:
95+
unordered_map<string, vector<char>> um;
96+
unordered_map<string, bool> dp;
97+
98+
bool recursive(string& line) {
99+
int size = line.size();
100+
101+
if (size == 1) return true;
102+
if (dp.count(line)) return dp[line];
103+
104+
vector<vector<char>> ch(size - 1);
105+
106+
for (int i = 0; i < size - 1; i++) {
107+
string key = {line[i], line[i + 1]};
108+
109+
for (char& c : um[key]) {
110+
ch[i].push_back(c);
111+
}
112+
}
113+
114+
unordered_set<string> us;
115+
116+
function<void(int, string&)> dfs = [&](int i, string& cur) {
117+
if (i == size - 1) {
118+
us.insert(cur);
119+
return;
120+
}
121+
122+
for (char& c : ch[i]) {
123+
if (cur.size() > 0) {
124+
string key = {cur.back(), c};
125+
if (um.count(key) == 0) continue;
126+
}
127+
128+
cur.push_back(c);
129+
dfs(i + 1, cur);
130+
cur.pop_back();
131+
}
132+
};
133+
134+
string cur = "";
135+
dfs(0, cur);
136+
137+
bool ret = false;
138+
for (string next : us) {
139+
ret |= recursive(next);
140+
if (ret) break;
141+
}
142+
return dp[line] = ret;
143+
}
144+
145+
public:
146+
bool pyramidTransition(string bottom, vector<string>& allowed) {
147+
for (string& s : allowed) {
148+
string key = {s[0], s[1]};
149+
char c = s[2];
150+
151+
um[key].push_back(c);
152+
}
153+
154+
return recursive(bottom);
155+
}
156+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Input: bottom = "BCD", allowed = ["BCC","CDE","CEA","FFF"]
2+
Output: true
3+
4+
===
5+
6+
Input: bottom = "AAAA", allowed = ["AAB","AAC","BCD","BBE","DEF"]
7+
Output: false

0 commit comments

Comments
 (0)