๐ณ ์ด๋ณด์ ์นํ ๊ฐ์ด๋ โMaximum Product of Splitted Binary Treeโ โ LeetCode 1339 (C++, Python, JavaScript)
Source: Dev.to

์ด์ง ํธ๋ฆฌ๋ ์ฌ๊ท์ ์ธ ํน์ฑ ๋๋ฌธ์ ์ข ์ข ์ํ์ ์ผ๋ก ๋๊ปด์ง๋๋ค. ํ์ง๋ง ๋ง์ ํธ๋ฆฌ ๋ฌธ์ ๋ ๋จ์ผ ๋ ธ๋๊ฐ ์ ์ฒด ๊ตฌ์กฐ์ ์ด๋ป๊ฒ ์ฐ๊ฒฐ๋๋์ง๋ฅผ ์ดํด๋ณด๋ ๊ฒ๋ง์ผ๋ก๋ ํด๊ฒฐํ ์ ์์ต๋๋ค. ์ด ๊ฐ์ด๋์์๋ ์ํ์ ๊ณฑ์ ์ต๋ํํ๊ธฐ ์ํด โ๊ฐ์ ํ๋๋ฅผ ์๋ฅด๋โ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด๊ฒ ์ต๋๋ค.
Problem Statement
๋น์ ์๊ฒ ์ฃผ์ด์ง ๊ฒ์:
- ๊ฐ ๋ ธ๋๊ฐ ์ ์ ๊ฐ์ ๊ฐ๋ ์ด์ง ํธ๋ฆฌ์ ๋ฃจํธ.
๋น์ ์ ๋ชฉํ:
- ์ ํํ ํ๋์ ๊ฐ์ ์ ์ ๊ฑฐํ์ฌ ํธ๋ฆฌ๋ฅผ ๋ ๊ฐ์ ๋ณ๋ ์๋ธํธ๋ฆฌ๋ก ๋๋๋ค.
- ๋ ๊ฐ์ ๊ฒฐ๊ณผ ํธ๋ฆฌ ๊ฐ๊ฐ์ ์๋ ๋ ธ๋๋ค์ ํฉ์ ๊ณ์ฐํ๋ค.
- ์ด ๋ ํฉ์ ๊ณฑ์ ์ต๋ํํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ (10^9 + 7) ๋ก mod ํ ๊ฐ์ ๋ฐํํ๋ค.
์ง๊ด
์ด ๋ฌธ์ ๋ ๋ ์๋ธํธ๋ฆฌ์ ํฉ์ ๊ณฑํ์ ๋ ๊ฐ๋ฅํ ํ ํฌ๊ฒ ๋ง๋ค ์ ์๋ ๋ ์๋ฅผ ์ฐพ๋ ๊ฒ์
๋๋ค.
ํธ๋ฆฌ์ ๋ชจ๋ ๋
ธ๋์ ์ดํฉ์ (S) ๋ผ๊ณ ํ๊ณ , ์ด๋ค ์๋ธํธ๋ฆฌ์ ํฉ์ (x) ๋ผ๊ณ ํ๋ฉด, ํธ๋ฆฌ์ ๋๋จธ์ง ๋ถ๋ถ์ ํฉ์ (S - x) ๊ฐ ๋ฉ๋๋ค.
์ต๋ ๊ณฑ์ ์ป๊ธฐ ์ํด์๋ ๋ค์๊ณผ ๊ฐ์ด ํ๋ฉด ๋ฉ๋๋ค:
- ์ ์ฒด ํฉ ๊ณ์ฐ โ ํธ๋ฆฌ๋ฅผ ํ ๋ฒ ์ ์ฒด ์ํํ์ฌ (S) ๋ฅผ ๊ตฌํฉ๋๋ค.
- ๊ฐ๋ฅํ ๋ชจ๋ ๋ถํ ํ๊ฐ โ ๊ฐ ๊ฐ์ ์ ๋ถ๋ชจ์ ์๋ธํธ๋ฆฌ๋ฅผ ์ฐ๊ฒฐํฉ๋๋ค. ๊ทธ ๊ฐ์ ์ ๋์ผ๋ฉด ์๋ธํธ๋ฆฌ ํฉ (x) ๊ฐ ์ป์ด์ง๋๋ค.
- ๊ณฑ ๊ณ์ฐ โ ๊ฐ ์๋ธํธ๋ฆฌ ํฉ์ ๋ํด (x \times (S - x)) ๋ฅผ ๊ณ์ฐํฉ๋๋ค.
- ์ต๋๊ฐ ์ถ์ โ ์ํํ๋ฉด์ ๊ฐ์ฅ ํฐ ๊ณฑ์ ๊ธฐ๋กํฉ๋๋ค.
ํ์ ์ํ(์ผ์ชฝ, ์ค๋ฅธ์ชฝ, ํ์ฌ ๋ ธ๋)๋ ๊ฐ ๋ ธ๋๊ฐ ์์ ์ ์์๋ค์ ํฉ์ ๋จผ์ ์ ์ ์๊ฒ ํด ์ฃผ๋ฏ๋ก ์ฌ๊ธฐ์ ์๋ฒฝํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค.
์ฝ๋
C++
class Solution {
public:
const long long MOD = 1e9 + 7;
long long total = 0; // total sum of all nodes
long long ans = 0; // best product found
// First pass โ compute total sum
void calculateTotal(TreeNode* root) {
if (!root) return;
total += root->val;
calculateTotal(root->left);
calculateTotal(root->right);
}
// Second pass โ postโorder, compute subtree sums and update answer
long long subTreeSum(TreeNode* root) {
if (!root) return 0;
long long leftSum = subTreeSum(root->left);
long long rightSum = subTreeSum(root->right);
// If we cut the edge to the left child
ans = max(ans, leftSum * (total - leftSum));
// If we cut the edge to the right child
ans = max(ans, rightSum * (total - rightSum));
return leftSum + rightSum + root->val;
}
int maxProduct(TreeNode* root) {
calculateTotal(root); // O(N)
subTreeSum(root); // O(N)
return ans % MOD;
}
};
ํ์ด์ฌ
class Solution:
def maxProduct(self, root: Optional[TreeNode]) -> int:
self.total = 0 # total sum of all nodes
self.ans = 0 # best product found
# First pass โ compute total sum
def get_total(node):
if not node:
return
self.total += node.val
get_total(node.left)
get_total(node.right)
# Second pass โ postโorder, compute subtree sums and update answer
def get_subtree_sum(node):
if not node:
return 0
left_sum = get_subtree_sum(node.left)
right_sum = get_subtree_sum(node.right)
cur_sum = left_sum + right_sum + node.val
# Update max product (do NOT mod yet)
self.ans = max(self.ans, cur_sum * (self.total - cur_sum))
return cur_sum
get_total(root) # O(N)
get_subtree_sum(root) # O(N)
return self.ans % (10**9 + 7)
์๋ฐ์คํฌ๋ฆฝํธ
/**
* @param {TreeNode} root
* @return {number}
*/
var maxProduct = function (root) {
let total = 0; // total sum of all nodes
let ans = 0; // best product found
// First pass โ compute total sum
const getTotal = (node) => {
if (!node) return;
total += node.val;
getTotal(node.left);
getTotal(node.right);
};
// Second pass โ postโorder, compute subtree sums and update answer
const getSubtreeSum = (node) => {
if (!node) return 0;
const leftSum = getSubtreeSum(node.left);
const rightSum = getSubtreeSum(node.right);
const curSum = leftSum + rightSum + node.val;
const product = curSum * (total - curSum);
if (product > ans) ans = product;
return curSum;
};
getTotal(root); // O(N)
getSubtreeSum(root); // O(N)
// Use BigInt for safety before applying modulo
return Number(BigInt(ans) % 1000000007n);
};
Key Takeaways
- Postโorder traversal ์ ๋ ธ๋์ ๊ณ์ฐ์ด ์์์ ์์กดํ ๋ ์ด์์ ์ด๋ค (์ฌ๊ธฐ์๋ ์๋ธํธ๋ฆฌ ํฉ์ด ํ์ํจ).
- Twoโpass strategy ๋ ๋ฌธ์ ๋ฅผ ๋จ์ํํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค: ๋จผ์ ์ ์ญ ์ ๋ณด(์ ์ฒด ํฉ)๋ฅผ ์์งํ๊ณ , ๊ทธ ๋ค์ ํต์ฌ ๋ก์ง(๊ณฑ ๊ณ์ฐ)์ ์ํํ๋ค.
- Maximize before modulo โ ๋ชจ๋๋ฌ ์ฐ์ฐ์ ๋๋ฌด ์ผ์ฐ ์ ์ฉํ๋ฉด ๊ณฑ์ ์์๊ฐ ๋ฐ๋์ด ์๋ชป๋ ๋ต์ด ๋์ฌ ์ ์๋ค.
์ต์ข ์๊ฐ
๋ฉํ ๋ก์ ์ ๋ ํ์๋ค์ด ํธ๋ฆฌ ๋ฌธ์ ์์ ๋ชจ๋ ๊ฐ๋ฅํ ๋ถํ ์ ํ ๋ฒ์ ์๊ฐํํ๋ ค๋ค ๋ณด๋ ์ด๋ ค์์ ๊ฒช๋ ๋ชจ์ต์ ์์ฃผ ๋ด ๋๋ค. ๋์ ์ด๋ค ๊ฐ์ ์ ์๋ฅด๋ฉด ์ ์ฒด ์๋ธํธ๋ฆฌ๊ฐ ๊ฒฉ๋ฆฌ๋๋ค๋ ํน์ฑ์ ์ง์คํ์ธ์. ๋ฌธ์ ๋ฅผ โ๊ฐ ์๋ธํธ๋ฆฌ์ ํฉ์ ๋ฌด์์ธ๊ฐ?โ ๋ก ์ถ์ํ๊ณ ๊ฐ๋จํ postโorder walk๋ฅผ ์ฌ์ฉํ๋ฉด ํด๊ฒฐ์ฑ ์ด ์ง๊ด์ ์ด๋ฉด์๋ ํจ์จ์ ์ด ๋ฉ๋๋ค. ์ฆ๊ฑฐ์ด ์ฝ๋ฉ ๋์ธ์! ๐
ํธ๋ฆฌ์์์ ์ฌ๊ท ํฉ
๋จ์ผ ๋ ธ๋:
โ๋ด ์๋ ๋ชจ๋ ๊ฒ์ ํฉ์ ์๋ฉด, ๋๋จธ์ง ํธ๋ฆฌ์ ํฉ์ ๊ฒฐ์ ํ ์ ์๋ค.โ
์ด ๋ ผ๋ฆฌ๋ ๋คํธ์ํฌ ๋ผ์ฐํ ์๊ณ ๋ฆฌ์ฆ์ ๊ธฐ๋ณธ์ด๋ฉฐ, ์์ง๋์ด๊ฐ ํธ๋ํฝ์ ๋ถํ ํ ์ต์ ์์น๋ฅผ ์ฐพ๊ฑฐ๋ ๋ณ๋ชฉ ๋ ธ๋๋ฅผ ์๋ณํด์ผ ํ ๋ ์ค์ํฉ๋๋ค. ๋ํ ๋ฐ์ดํฐ ๊ณผํ์์ ๊ณ์ธต์ ํด๋ฌ์คํฐ๋ง๊ณผ๋ ๋งค์ฐ ๊ด๋ จ์ด ์์ต๋๋ค.
์ด๋ฌํ ์ฌ๊ท ํจํด์ ๋ง์คํฐํ๋ฉด ํจ์ฌ ๋ ํจ์จ์ ์ธ ์ํํธ์จ์ด ์์ง๋์ด๊ฐ ๋ ์ ์์ต๋๋ค.