문제
https://leetcode.com/problems/binary-trees-with-factors/
걸린 시간
- 실패
풀이
C++
typedef long long ll;
class Solution {
public:
int n;
int mod = 1e9+7;
map<int, int> cache;
int dp(int root, set<int>& s){
// 메모이제이션
int& ret = cache[root];
if(ret != 1) return ret;
// 재귀 호출
for(auto x : s){
if(root%x == 0 && s.find(root/x) != s.end()){
ret += (ll)dp(x, s)*dp(root/x, s)%mod;
ret %= mod;
}
}
return ret;
}
int numFactoredBinaryTrees(vector<int>& arr) {
n = arr.size();
set<int> s(arr.begin(), arr.end());
int ans = 0;
for(int x : s) cache[x] = 1;
for(int x : s){
ans += dp(x, s);
ans %= mod;
}
return ans;
}
};
주어진 배열의 고유한 원소를 제한 없이 사용하여, 자식노드 두개의 곱이 부모노드가 되는 이진트리의 총 개수를 찾아야한다.
문제의 조건을 보면 루트 노드만 있는 경우도 수에 포함된다고 한다. (= 가능한 자식 노드가 있지만 표현하지 않은 형태도 경우의 수에 포함된다.)
작은 예제의 모든 경우의 수를 풀어보면 중복되는 계산이 쉽게 보인다. 각 원소를 루트로 하는 경우의 수를 메모이제이션 하면 될 것 같다. 모든 원소는 적어도 자기 자신이 루트인 트리 하나가 존재하므로 초기값은 1 로 설정해 준다.
높이가 2 이상인 트리의 경우 좌, 우 서브트리별로 가능한 경우의 수는 각각 독립 사건이기 때문에 서로 곱해준 값이 해당 루트의 경우의 수가 된다.
dp 를 떠올리는 건 쉬웠지만, root 의 자식노드를 left, right 라고 할 때 곱이 루트노드가 되는 두 자식노드를 찾는 과정에서 left * right = root 인 쌍을 2중 for문으로 찾아 O(n2) 복잡도가 되어 시간초과가 발생했다.
다른 사람의 top-down dp 풀이를 보니 root / left = right 로 형태를 바꾸어 root 가 left 로 나누어 떨어지는지를 확인하고, 나머지 한 쌍(right = root / left)이 원소 배열에 존재하는지를 set 자료구조를 이용해 찾아 복잡도를 O(nlogn) 까지 줄일 수 있었다.
'LeetCode' 카테고리의 다른 글
LeetCode 5. Longest Palindromic Substring (0) | 2021.10.03 |
---|---|
LeetCode 714. Best Time to Buy and Sell Stock with Transaction Fee (0) | 2021.03.17 |
LeetCode 147. Insertion Sort List (0) | 2021.02.25 |
LeetCode 56. Merge Intervals (0) | 2021.02.24 |
LeetCode 208. Implement Trie (Prefix Tree) (0) | 2021.02.21 |
댓글