avatarSantal Tech

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

3288

Abstract

er, I can’t select any of those nodes.</p><h1 id="2108">Intuition</h1><p id="8ca9">It’s not immediately obvious to me what the best way to play the game is. Let’s study the example given:</p><ul><li>The first move is to color node 3 red.</li><li>If I pick node 6 or 7, I’m stuck, because I can’t color any other nodes in this game after this move.</li><li>Node 1 looks like a good move though. I’m forcing the red player to only pick nodes 6 or 7 after.</li></ul><p id="63fb">Aha! So maybe it is pretty straightforward — I’ll want to always pick an adjacent node to the first red node, to “block” them off from picking any other nodes that are connected to my selected node.</p><p id="597a">What are my options for the second move? I could select the left child, right child, or parent of the first selected red node for my second move. And, that’s really the only decision I’m making in this game; I can’t “cross” over to any of the red node’s territory.</p><p id="77aa">So I want to select the node out of [left child, right child, parent] that has the most nodes in its “subtree.”</p><h1 id="10ed">But how do I know it’s a winning move?</h1><p id="cbc1">This takes some thought. Let’s play with a simpler example:</p><figure id="b473"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*SlwmfD3cOhXCqwpl7zwdGw.png"><figcaption></figcaption></figure><p id="ffca">What are some possible first moves? The first player can color the following nodes red:</p><ul><li>Node 4: Then we can color node 2 blue, and red can only capture 1 node.</li><li>Node 5: Same reasoning as node 4 above.</li><li>Node 2: We can color node 1 blue, and red will only have 3 nodes.</li><li>Node 1: We can color node 2 or 3 blue, and red will win with 4 nodes captured compared to 3 blue nodes.</li><li>Nodes 3, 6, and 7 are symmetrical to nodes 2, 4, and 5 (respectively), so the same logic holds.</li></ul><p id="97e4">So the <b>best</b> that red can do is take <code>n/2 + 1</code> nodes (our problem statement says there is an odd number of nodes). So we can check that the number of nodes that are part of the subtree that we (blue) select is greater than <code>n/2</code>.</p><p id="9684">How do we implement the logic for the <b>parent</b> though? Well, if <i>n</i> is the total number of nodes, then <code>n - 1 - count_left - count_right</code> is the number of nodes in the parent subtree. Stare at that expression for a bit— does it make sense?</p><ul><li>We subtract 1 for the selected red node.</li><li><code>count_left</code> is the number nodes in the left subtree of the red node.</li><li><code>count_right</code> is the number of nodes in the right subtree of the right node.</li></ul><p id="c8c9">Our psuedocode might look like:</p><div id="1265"><pre><span class="hljs-built_in">n</span> = number of nodes (this is given to us) <span class="hljs-built_in">if</span> (<span class="hljs-built_in">count</span> of nodes in <span class="hljs-built_in">left</span> subtree) > <span class="hljs-built_in">n</span>/<span class="hljs-number">2</span> <span class="hljs-built_in">or</span> (<span class="hljs-built_in">count</span> of nodes in <span class="hljs-built_in">right</span> subtree) > <span class="hljs-built_in">n</span>/<span class="hljs-number">2</span> <span class="

Options

hljs-built_in">or</span> <span class="hljs-built_in">n</span> - <span class="hljs-number">1</span> - count_left - count_right > <span class="hljs-built_in">n</span>/<span class="hljs-symbol">2:</span> return <span class="hljs-built_in">True</span></pre></div><h1 id="411b">The code</h1><div id="341e"><pre><span class="hljs-keyword">class</span> <span class="hljs-title class_">Solution</span>(<span class="hljs-title class_ inherited__">object</span>): <span class="hljs-keyword">def</span> <span class="hljs-title function_">btreeGameWinningMove</span>(<span class="hljs-params">self, root, n, x</span>): <span class="hljs-string">""" :type root: TreeNode :type n: int :type x: int :rtype: bool """</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_count_nodes_in_subtree</span>(<span class="hljs-params">node</span>): <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> node: <span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">return</span> <span class="hljs-number">1</span> + get_count_nodes_in_subtree(node.left) + get_count_nodes_in_subtree(node.right)

    <span class="hljs-comment"># find the number of nodes in each subtree of the first selected node's neighbors.</span>
    self.l, self.r = <span class="hljs-number">0</span>,<span class="hljs-number">0</span>
    <span class="hljs-keyword">def</span> <span class="hljs-title function_">traverse</span>(<span class="hljs-params">node</span>):
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> node:
            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>
        <span class="hljs-keyword">if</span> node.val != x: <span class="hljs-comment"># we haven't found the target node, so check left and right</span>
            traverse(node.left)
            traverse(node.right)
        <span class="hljs-keyword">else</span>: <span class="hljs-comment"># we found our target node, so do the counting</span>
            self.l = get_count_nodes_in_subtree(node.left)
            self.r = get_count_nodes_in_subtree(node.right)

    traverse(root)
    <span class="hljs-keyword">if</span> self.l &gt; n/<span class="hljs-number">2</span> <span class="hljs-keyword">or</span> self.r &gt; n/<span class="hljs-number">2</span>: <span class="hljs-comment"># we could select the left or right node</span>
        <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
    <span class="hljs-keyword">if</span> n - <span class="hljs-number">1</span> - self.l - self.r &gt; n/<span class="hljs-number">2</span>: <span class="hljs-comment"># we select the parent node</span>
        <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
    <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span></pre></div><h1 id="f80c">Time and space complexity</h1><p id="d4b0">Time complexity: O(N), since we traverse the tree once.</p><p id="054b">Space complexity: O(N), for the recursive call stack.</p></article></body>

Can you beat this game? Google Interview Question: Binary Tree Coloring Game

Here’s a question that Google asked in its interview process. I’ve pasted the problem statement below.

Two players play a turn based game on a binary tree. We are given the root of this binary tree, and the number of nodes n in the tree. n is odd, and each node has a distinct value from 1 to n.

Initially, the first player names a value x with 1 <= x <= n, and the second player names a value y with 1 <= y <= n and y != x. The first player colors the node with value x red, and the second player colors the node with value y blue.

Then, the players take turns starting with the first player. In each turn, that player chooses a node of their color (red if player 1, blue if player 2) and colors an uncolored neighbor of the chosen node (either the left child, right child, or parent of the chosen node.)

If (and only if) a player cannot choose such a node in this way, they must pass their turn. If both players pass their turn, the game ends, and the winner is the player that colored more nodes.

You are the second player. If it is possible to choose such a y to ensure you win the game, return true. If it is not possible, return false.

Input: root = [1,2,3,4,5,6,7,8,9,10,11], n = 11, x = 3
Output: true
Explanation: The second player can choose the node with value 2.

Clarifying the Question

Let’s be explicit about what the question is asking for:

  • The first player selects which node to color red, which is their color.
  • We (blue) always make the second move and select which node to color blue, which is our color.
  • Is there a move to guarantee that we (blue) win?

Note that a player can only color an uncolored node that’s a neighbor of the chosen node. So in the picture above, on the next turn, the red player can only select 1, 6, or 7. As the blue player, I can’t select any of those nodes.

Intuition

It’s not immediately obvious to me what the best way to play the game is. Let’s study the example given:

  • The first move is to color node 3 red.
  • If I pick node 6 or 7, I’m stuck, because I can’t color any other nodes in this game after this move.
  • Node 1 looks like a good move though. I’m forcing the red player to only pick nodes 6 or 7 after.

Aha! So maybe it is pretty straightforward — I’ll want to always pick an adjacent node to the first red node, to “block” them off from picking any other nodes that are connected to my selected node.

What are my options for the second move? I could select the left child, right child, or parent of the first selected red node for my second move. And, that’s really the only decision I’m making in this game; I can’t “cross” over to any of the red node’s territory.

So I want to select the node out of [left child, right child, parent] that has the most nodes in its “subtree.”

But how do I know it’s a winning move?

This takes some thought. Let’s play with a simpler example:

What are some possible first moves? The first player can color the following nodes red:

  • Node 4: Then we can color node 2 blue, and red can only capture 1 node.
  • Node 5: Same reasoning as node 4 above.
  • Node 2: We can color node 1 blue, and red will only have 3 nodes.
  • Node 1: We can color node 2 or 3 blue, and red will win with 4 nodes captured compared to 3 blue nodes.
  • Nodes 3, 6, and 7 are symmetrical to nodes 2, 4, and 5 (respectively), so the same logic holds.

So the best that red can do is take n/2 + 1 nodes (our problem statement says there is an odd number of nodes). So we can check that the number of nodes that are part of the subtree that we (blue) select is greater than n/2.

How do we implement the logic for the parent though? Well, if n is the total number of nodes, then n - 1 - count_left - count_right is the number of nodes in the parent subtree. Stare at that expression for a bit— does it make sense?

  • We subtract 1 for the selected red node.
  • count_left is the number nodes in the left subtree of the red node.
  • count_right is the number of nodes in the right subtree of the right node.

Our psuedocode might look like:

n = number of nodes (this is given to us)
if (count of nodes in left subtree) > n/2 or 
  (count of nodes in right subtree) > n/2 or 
  n - 1 - count_left - count_right > n/2:
  return True

The code

class Solution(object):
    def btreeGameWinningMove(self, root, n, x):
        """
        :type root: TreeNode
        :type n: int
        :type x: int
        :rtype: bool
        """
        def get_count_nodes_in_subtree(node):
            if not node:
                return 0
            return 1 + get_count_nodes_in_subtree(node.left) + get_count_nodes_in_subtree(node.right)
    
        # find the number of nodes in each subtree of the first selected node's neighbors.
        self.l, self.r = 0,0
        def traverse(node):
            if not node:
                return 0
            if node.val != x: # we haven't found the target node, so check left and right
                traverse(node.left)
                traverse(node.right)
            else: # we found our target node, so do the counting
                self.l = get_count_nodes_in_subtree(node.left)
                self.r = get_count_nodes_in_subtree(node.right)

        traverse(root)
        if self.l > n/2 or self.r > n/2: # we could select the left or right node
            return True
        if n - 1 - self.l - self.r > n/2: # we select the parent node
            return True
        return False

Time and space complexity

Time complexity: O(N), since we traverse the tree once.

Space complexity: O(N), for the recursive call stack.

Binary Tree
Leetcode
Google
Software Engineering
Technical Interview
Recommended from ReadMedium