A ternary expression like T?a:b consists of a condition (T or F), followed by ?, then the true branch, :, and the false branch. When expressions are nested, we can evaluate from the inside out.
The key insight is that the rightmost atomic expression (a simple B?E1:E2 where both E1 and E2 are single characters) can always be evaluated first without affecting the rest. By repeatedly finding and reducing these atomic expressions from right to left, we eventually collapse the entire expression to a single result.
B?X:Y where B is T or F, and X, Y are digits or T/F).X if B is T, otherwise Y.class Solution:
def parseTernary(self, expression: str) -> str:
# Checks if the string s is a valid atomic expression
def isValidAtomic(s):
return s[0] in 'TF' and s[1] == '?' and s[2] in 'TF0123456789'\
and s[3] == ':' and s[4] in 'TF0123456789'
# Returns the value of the atomic expression
def solveAtomic(s):
return s[2] if s[0] == 'T' else s[4]
# Reduce expression until we are left with a single character
while len(expression) != 1:
j = len(expression) - 1
while not isValidAtomic(expression[j-4:j+1]):
j -= 1
expression = expression[:j-4] + \
solveAtomic(expression[j-4:j+1]) + expression[j+1:]
# Return the final character
return expressionWhere is the length of
expression
Instead of validating the full atomic expression pattern, we can simplify by just finding the rightmost ? operator. The character immediately before ? is the condition, and the characters at positions +1 and +3 relative to ? are the true and false values respectively.
This works because the rightmost ? is always part of the innermost (deepest nested) ternary that can be evaluated. After each reduction, the next rightmost ? becomes evaluable.
? by scanning from the end.questionMarkIndex - 1.T, take the character at questionMarkIndex + 1.questionMarkIndex + 3.class Solution:
def parseTernary(self, expression: str) -> str:
# Reduce expression until we are left with a single character
while len(expression) != 1:
questionMarkIndex = len(expression) - 1
while expression[questionMarkIndex] != '?':
questionMarkIndex -= 1
# Find the value of the expression.
if expression[questionMarkIndex - 1] == 'T':
value = expression[questionMarkIndex + 1]
else:
value = expression[questionMarkIndex + 3]
# Replace the expression with the value
expression = expression[:questionMarkIndex - 1] + value\
+ expression[questionMarkIndex + 4:]
# Return the final character
return expressionWhere is the length of
expression
Processing from right to left with a stack eliminates the need for string manipulation. When we encounter a ?, we know the stack contains the true value, :, and false value (in that order from top). The current character is the condition, so we can immediately resolve which value to keep.
This approach processes each character exactly once and avoids expensive substring operations, achieving linear time complexity.
?:?, pop the true value, pop :, pop the false value.T, otherwise push the false value.class Solution:
def parseTernary(self, expression: str) -> str:
# Initialize a stack
stack = []
# Traverse the expression from right to left
for char in expression[::-1]:
# If stack top is ?, then replace next four characters
# with E1 or E2 depending on the value of B
if stack and stack[-1] == '?':
stack.pop()
onTrue = stack.pop()
stack.pop()
onFalse = stack.pop()
stack.append(onTrue if char == 'T' else onFalse)
# Otherwise, push this character
else:
stack.append(char)
# Return the final character
return stack[0]Where is the length of
expression
A ternary expression naturally maps to a binary tree structure. Each condition becomes a node, with its true branch as the left child and false branch as the right child. Leaf nodes hold the final values (digits or T/F).
Once the tree is built, evaluating the expression is straightforward: start at the root and traverse left for T conditions, right for F conditions, until reaching a leaf.
?, recursively build the left subtree (true branch) and right subtree (false branch).T, move to the left child.F, move to the right child.class TreeNode:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
class Solution:
def parseTernary(self, expression: str) -> str:
# Global Index to Construct Binary Tree
self.index = 0
root = self.constructTree(expression)
# Parse the binary tree till we reach the leaf node
while root.left and root.right:
if root.val == 'T':
root = root.left
else:
root = root.right
return root.val
def constructTree(self, expression):
# Storing current character of expression
root = TreeNode(expression[self.index])
# If the last character of expression, return
if self.index == len(expression) - 1:
return root
# Check the next character
self.index += 1
if expression[self.index] == '?':
self.index += 1
root.left = self.constructTree(expression)
self.index += 1
root.right = self.constructTree(expression)
return rootWhere is the length of
expression
We can evaluate the expression top-down by recursively processing subexpressions. The key challenge is finding where the true branch ends and the false branch begins, since branches can contain nested ternaries.
By counting ? and : characters, we can find the matching : for any given ?. Each ? increments a counter, each : decrements it. When the counter reaches zero, we have found the boundary between the true and false branches.
solve(i, j) that evaluates the expression between indices i and j.i == j, return the single character.? after index i.: by tracking nested ternaries:count = 1 after the ?.count for each ?, decrement for each :.count reaches 0.i is T, recurse on the true branch.solve(0, len(expression) - 1).class Solution:
def parseTernary(self, expression: str) -> str:
# To analyze the expression between two indices
def solve(i, j):
# If expression is a single character, return it
if i == j:
return expression[i]
# Find the index of ?
questionMarkIndex = i
while expression[questionMarkIndex] != '?':
questionMarkIndex += 1
# Find one index after corresponding :
aheadColonIndex = questionMarkIndex + 1
count = 1
while count != 0:
if expression[aheadColonIndex] == '?':
count += 1
elif expression[aheadColonIndex] == ':':
count -= 1
aheadColonIndex += 1
# Check the value of B and recursively solve
if expression[i] == 'T':
return solve(questionMarkIndex + 1, aheadColonIndex - 2)
else:
return solve(aheadColonIndex, j)
# Solve for the entire expression
return solve(0, len(expression) - 1)Where is the length of
expression
We can evaluate the expression iteratively without recursion or extra space by simulating the evaluation process directly. Starting from the beginning, we repeatedly decide whether to take the true or false branch based on each condition.
When the condition is T, we simply skip past the ? to the true branch. When it is F, we must skip the entire true branch (which may contain nested ternaries) by counting ? and : to find where the false branch starts.
i = 0.i is within bounds:T or F, or we have reached the end, or the next character is :, we have found the result. Return it.T, skip to i + 2 (start of true branch).F:i + 2 and use a counter starting at 1.counter for ?, decrement for :.counter reaches 0; we are now at the false branch.i.class Solution:
def parseTernary(self, expression: str) -> str:
i = 0
while True:
if expression[i] not in 'TF' or i == len(expression) - 1\
or expression[i + 1] == ':':
return expression[i]
if expression[i] == 'T':
i = i + 2
else:
count = 1
i = i + 2
while count != 0:
if expression[i] == ':':
count -= 1
elif expression[i] == '?':
count += 1
i += 1Where is the length of
expression
A common mistake is trying to evaluate the expression from left to right. Ternary expressions are right-associative, meaning T?T?1:2:3 should be parsed as T?(T?1:2):3, not (T?T?1:2):3. Processing from the right ensures nested expressions are resolved correctly before their parent expressions.
? with :When expressions are deeply nested, finding the matching : for a given ? is tricky. Each ? must pair with exactly one :, but nested ternaries introduce additional ? and : characters. Use a counter that increments for ? and decrements for : to find the correct boundary between true and false branches.
The atomic expression pattern is exactly 5 characters (B?X:Y), and miscounting indices when extracting or replacing substrings leads to incorrect results. Be careful with inclusive vs exclusive bounds in substring operations, especially when the expression shrinks after each reduction.