코딩 테스트 및 알고리즘/leetcode for google

leetcode : Binary Trees With Factors

띠리링구 2022. 10. 10. 23:18

https://leetcode.com/problems/binary-trees-with-factors/submissions/

 

Binary Trees With Factors - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

 

어려웠다.

여러가지 중요한 발상엔 성공했지만 정렬을 생각 못해서 못풀었다.

일단 naive하게 생각하면 O(N^3)이 나오는데 N이 최대 1000인걸 생각하면 1000000000 (10억)번의 연산이 필요하고 TLE가 뜰것이다. O(N^2)까지는 줄여야 한다. 기존 연산결과를 재활용 하는 방향으로 최적화를 시도해봐야 한다. DP를 살짝 의심

 

일단 맨 처음에 주어진 arr에서 숫자를 조합해서 트리를 새로 만들면

새로만든 트리의 루트노드랑 다른 숫자를 결합해 또 트리를 만들 수 있다.

그럼 기존 연산 결과를 활용해 새 트리를 계산할 수 있지 않을까 해서 여기서 DP임을 거의 확신했다.

 

근데 예를 들어 루트노드가 4인 서로다른 트리가 4개 있을 때 이를 2랑 조합해서 8이 루트가 되게하는 트리의 개수를 세려면 그냥 루트노드가 4인 트리의 개수만 알면 되지 않나 싶었다. 4 트리의 개수 * 2 트리의 개수 하면 4랑 2 조합해서 8 트리가 몇개 나올 수 있는지 알수있으니까.

 

정렬이 필요한 이유는 예를 들어 8 트리를 만든다고 쳤을 때 자기보다 작은 숫자만 검사하면 되기 때문이다. 8보다 큰 수를 곱셈연산해서 8을 만들 순 없다. 그래서 정렬은 불필요한 검사를 엄청 많이 줄여줌.

 

count라는 딕셔너리를 만들어서 각 숫자를 루트노드로 하는 트리의 개수가 몇 개인지 저장한다. 마지막에 count 딕셔너리의 value값을 다 더하면 그게 정답이 될것이다.

class Solution:
    def numFactoredBinaryTrees(self, arr: List[int]) -> int:  
        arr.sort()
        
        count = Counter(arr)
        
        for i in range(len(arr)):
            added = 0
            
            for j in range(i):
                if arr[i] % arr[j] == 0:
                    added += count[arr[j]] * count[arr[i]//arr[j]]
            
            count[arr[i]] += added
            
        return sum(count.values()) % (10**9 + 7)