Before attempting this problem, you should be comfortable with:
Stack Data Structure - The optimal solution uses a stack to evaluate nested expressions from right to left
String Manipulation - Parsing and substring extraction are fundamental to all approaches
Recursion - The recursive solution and binary tree approach rely on recursive expression evaluation
Binary Trees - One approach builds a tree structure from the ternary expression for evaluation
1. Find Rightmost Atomic Expression
Intuition
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.
Algorithm
Define a helper to check if a 5-character substring is a valid atomic expression (form B?X:Y where B is T or F, and X, Y are digits or T/F).
Define a helper to evaluate an atomic expression, returning X if B is T, otherwise Y.
While the expression has more than one character:
Scan from the right to find the rightmost valid atomic expression.
Replace that 5-character substring with its evaluated single character result.
classSolution:defparseTernary(self, expression:str)->str:# Checks if the string s is a valid atomic expressiondefisValidAtomic(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 expressiondefsolveAtomic(s):return s[2]if s[0]=='T'else s[4]# Reduce expression until we are left with a single characterwhilelen(expression)!=1:
j =len(expression)-1whilenot isValidAtomic(expression[j-4:j+1]):
j -=1
expression = expression[:j-4]+ \
solveAtomic(expression[j-4:j+1])+ expression[j+1:]# Return the final characterreturn expression
classSolution{publicStringparseTernary(String expression){// Checks if the string s is a valid atomic expressionPredicate<String> isValidAtomic = s ->(s.charAt(0)=='T'|| s.charAt(0)=='F')&& s.charAt(1)=='?'&&((s.charAt(2)>='0'&& s.charAt(2)<='9')|| s.charAt(2)=='T'|| s.charAt(2)=='F')&& s.charAt(3)==':'&&((s.charAt(4)>='0'&& s.charAt(4)<='9')|| s.charAt(4)=='T'|| s.charAt(4)=='F');// Returns the value of the atomic expressionFunction<String,String> solveAtomic = s -> s.charAt(0)=='T'? s.substring(2,3): s.substring(4,5);// Reduce expression until we are left with a single characterwhile(expression.length()!=1){int j = expression.length()-1;while(!isValidAtomic.test(expression.substring(j-4, j+1))){
j--;}
expression = expression.substring(0, j-4)+ solveAtomic.apply(expression.substring(j-4, j+1))+ expression.substring(j+1, expression.length());}// Return the final characterreturn expression;}}
classSolution{public:
string parseTernary(string expression){// Checks if the string s is a valid atomic expressionauto isValidAtomic =[](string s){return(s[0]=='T'|| s[0]=='F')&& s[1]=='?'&&((s[2]>='0'&& s[2]<='9')|| s[2]=='T'|| s[2]=='F')&& s[3]==':'&&((s[4]>='0'&& s[4]<='9')|| s[4]=='T'|| s[4]=='F');};// Returns the value of the atomic expressionauto solveAtomic =[](string s){return s[0]=='T'? s[2]: s[4];};// Reduce expression until we are left with a single characterwhile(expression.size()!=1){int j = expression.size()-1;while(!isValidAtomic(expression.substr(j-4,5))){
j--;}
expression = expression.substr(0, j-4)+solveAtomic(expression.substr(j-4,5))+ expression.substr(j+1);}// Return the final characterreturn expression;}};
classSolution{/**
* @param {string} expression
* @return {string}
*/parseTernary(expression){// Checks if the string s is a valid atomic expressionconstisValidAtomic=(s)=>{return s[0]&&(s[0]==='T'|| s[0]==='F')&&
s[1]==='?'&&
s[2]&&/[TF0-9]/.test(s[2])&&
s[3]===':'&&
s[4]&&/[TF0-9]/.test(s[4]);};// Returns the value of the atomic expressionconstsolveAtomic=(s)=>{return s[0]==='T'? s[2]: s[4];};// Reduce expression until we are left with a single characterwhile(expression.length !==1){let j = expression.length -1;while(!isValidAtomic(expression.substring(j -4, j +1))){
j--;}
expression = expression.substring(0, j -4)+solveAtomic(expression.substring(j -4, j +1))+
expression.substring(j +1);}// Return the final characterreturn expression;}}
publicclassSolution{publicstringParseTernary(string expression){// Checks if the string s is a valid atomic expressionFunc<string,bool> isValidAtomic = s =>{if(s.Length <5)returnfalse;return(s[0]=='T'|| s[0]=='F')&&
s[1]=='?'&&(char.IsDigit(s[2])|| s[2]=='T'|| s[2]=='F')&&
s[3]==':'&&(char.IsDigit(s[4])|| s[4]=='T'|| s[4]=='F');};// Returns the value of the atomic expressionFunc<string,char> solveAtomic = s => s[0]=='T'? s[2]: s[4];// Reduce expression until we are left with a single characterwhile(expression.Length !=1){int j = expression.Length -1;while(!isValidAtomic(expression.Substring(j -4,5))){
j--;}
expression = expression.Substring(0, j -4)+solveAtomic(expression.Substring(j -4,5))+
expression.Substring(j +1);}// Return the final characterreturn expression;}}
funcparseTernary(expression string)string{// Checks if the string s is a valid atomic expression
isValidAtomic :=func(s string)bool{iflen(s)<5{returnfalse}return(s[0]=='T'|| s[0]=='F')&&
s[1]=='?'&&(s[2]>='0'&& s[2]<='9'|| s[2]=='T'|| s[2]=='F')&&
s[3]==':'&&(s[4]>='0'&& s[4]<='9'|| s[4]=='T'|| s[4]=='F')}// Returns the value of the atomic expression
solveAtomic :=func(s string)byte{if s[0]=='T'{return s[2]}return s[4]}// Reduce expression until we are left with a single characterforlen(expression)!=1{
j :=len(expression)-1for!isValidAtomic(expression[j-4: j+1]){
j--}
expression = expression[:j-4]+string(solveAtomic(expression[j-4:j+1]))+ expression[j+1:]}// Return the final characterreturn expression
}
class Solution {funparseTernary(expression: String): String {var expr = expression
// Checks if the string s is a valid atomic expressionfunisValidAtomic(s: String): Boolean {if(s.length <5)returnfalsereturn(s[0]=='T'|| s[0]=='F')&&
s[1]=='?'&&(s[2].isDigit()|| s[2]=='T'|| s[2]=='F')&&
s[3]==':'&&(s[4].isDigit()|| s[4]=='T'|| s[4]=='F')}// Returns the value of the atomic expressionfunsolveAtomic(s: String): Char =if(s[0]=='T') s[2]else s[4]// Reduce expression until we are left with a single characterwhile(expr.length !=1){var j = expr.length -1while(!isValidAtomic(expr.substring(j -4, j +1))){
j--}
expr = expr.substring(0, j -4)+solveAtomic(expr.substring(j -4, j +1))+ expr.substring(j +1)}// Return the final characterreturn expr
}}
classSolution{funcparseTernary(_ expression:String)->String{var expr =Array(expression)// Checks if the string s is a valid atomic expressionfuncisValidAtomic(_ s:[Character])->Bool{if s.count <5{returnfalse}return(s[0]=="T"|| s[0]=="F")&&
s[1]=="?"&&(s[2].isNumber || s[2]=="T"|| s[2]=="F")&&
s[3]==":"&&(s[4].isNumber || s[4]=="T"|| s[4]=="F")}// Returns the value of the atomic expressionfuncsolveAtomic(_ s:[Character])->Character{return s[0]=="T"? s[2]: s[4]}// Reduce expression until we are left with a single characterwhile expr.count !=1{var j = expr.count -1while!isValidAtomic(Array(expr[(j-4)...(j)])){
j -=1}let result =solveAtomic(Array(expr[(j-4)...(j)]))
expr =Array(expr[0..<(j-4)])+[result]+Array(expr[(j+1)...])}// Return the final characterreturnString(expr)}}
Time & Space Complexity
Time complexity: O(N2)
Space complexity: O(N)
Where N is the length of expression
2. Reverse Polish Notation
Intuition
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.
Algorithm
While the expression has more than one character:
Find the index of the rightmost ? by scanning from the end.
The condition is at index questionMarkIndex - 1.
If the condition is T, take the character at questionMarkIndex + 1.
Otherwise, take the character at questionMarkIndex + 3.
Replace the 5-character ternary with the resulting single character.
classSolution:defparseTernary(self, expression:str)->str:# Reduce expression until we are left with a single characterwhilelen(expression)!=1:
questionMarkIndex =len(expression)-1while 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 characterreturn expression
classSolution{publicStringparseTernary(String expression){// Reduce expression until we are left with a single characterwhile(expression.length()!=1){int questionMarkIndex = expression.length()-1;while(expression.charAt(questionMarkIndex)!='?'){
questionMarkIndex--;}// Find the value of the expression.char value;if(expression.charAt(questionMarkIndex -1)=='T'){
value = expression.charAt(questionMarkIndex +1);}else{
value = expression.charAt(questionMarkIndex +3);}// Replace the expression with the value
expression = expression.substring(0, questionMarkIndex -1)+ value + expression.substring(questionMarkIndex +4);}// Return the final characterreturn expression;}}
classSolution{public:
string parseTernary(string expression){// Reduce expression until we are left with a single characterwhile(expression.size()!=1){int questionMarkIndex = expression.size()-1;while(expression[questionMarkIndex]!='?'){
questionMarkIndex--;}// Find the value of the expression.char value;if(expression[questionMarkIndex -1]=='T'){
value = expression[questionMarkIndex +1];}else{
value = expression[questionMarkIndex +3];}// Replace the expression with the value
expression = expression.substr(0, questionMarkIndex -1)+ value + expression.substr(questionMarkIndex +4);}// Return the final characterreturn expression;}};
classSolution{/**
* @param {string} expression
* @return {string}
*/parseTernary(expression){// Reduce expression until we are left with a single characterwhile(expression.length !==1){let questionMarkIndex = expression.length -1;while(expression[questionMarkIndex]!=='?'){
questionMarkIndex--;}// Find the value of the expression.let value;if(expression[questionMarkIndex -1]==='T'){
value = expression[questionMarkIndex +1];}else{
value = expression[questionMarkIndex +3];}// Replace the expression with the value
expression = expression.substring(0, questionMarkIndex -1)+ value +
expression.substring(questionMarkIndex +4);}// Return the final characterreturn expression;}}
publicclassSolution{publicstringParseTernary(string expression){// Reduce expression until we are left with a single characterwhile(expression.Length !=1){int questionMarkIndex = expression.Length -1;while(expression[questionMarkIndex]!='?'){
questionMarkIndex--;}// Find the value of the expression.charvalue;if(expression[questionMarkIndex -1]=='T'){value= expression[questionMarkIndex +1];}else{value= expression[questionMarkIndex +3];}// Replace the expression with the value
expression = expression.Substring(0, questionMarkIndex -1)+value+ expression.Substring(questionMarkIndex +4);}// Return the final characterreturn expression;}}
funcparseTernary(expression string)string{// Reduce expression until we are left with a single characterforlen(expression)!=1{
questionMarkIndex :=len(expression)-1for expression[questionMarkIndex]!='?'{
questionMarkIndex--}// Find the value of the expression.var value byteif expression[questionMarkIndex-1]=='T'{
value = expression[questionMarkIndex+1]}else{
value = expression[questionMarkIndex+3]}// Replace the expression with the value
expression = expression[:questionMarkIndex-1]+string(value)+ expression[questionMarkIndex+4:]}// Return the final characterreturn expression
}
class Solution {funparseTernary(expression: String): String {var expr = expression
// Reduce expression until we are left with a single characterwhile(expr.length !=1){var questionMarkIndex = expr.length -1while(expr[questionMarkIndex]!='?'){
questionMarkIndex--}// Find the value of the expression.val value =if(expr[questionMarkIndex -1]=='T'){
expr[questionMarkIndex +1]}else{
expr[questionMarkIndex +3]}// Replace the expression with the value
expr = expr.substring(0, questionMarkIndex -1)+ value + expr.substring(questionMarkIndex +4)}// Return the final characterreturn expr
}}
classSolution{funcparseTernary(_ expression:String)->String{var expr =Array(expression)// Reduce expression until we are left with a single characterwhile expr.count !=1{var questionMarkIndex = expr.count -1while expr[questionMarkIndex]!="?"{
questionMarkIndex -=1}// Find the value of the expression.let value:Characterif expr[questionMarkIndex -1]=="T"{
value = expr[questionMarkIndex +1]}else{
value = expr[questionMarkIndex +3]}// Replace the expression with the value
expr =Array(expr[0..<(questionMarkIndex -1)])+[value]+Array(expr[(questionMarkIndex +4)...])}// Return the final characterreturnString(expr)}}
Time & Space Complexity
Time complexity: O(N2)
Space complexity: O(N)
Where N is the length of expression
3. Reverse Polish Notation using Stack
Intuition
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.
Algorithm
Initialize an empty stack.
Traverse the expression from right to left:
If the stack's top is ?:
Pop ?, pop the true value, pop :, pop the false value.
Push the true value if the current character is T, otherwise push the false value.
Otherwise, push the current character onto the stack.
Return the single character remaining in the stack.
classSolution:defparseTernary(self, expression:str)->str:# Initialize a stack
stack =[]# Traverse the expression from right to leftfor char in expression[::-1]:# If stack top is ?, then replace next four characters# with E1 or E2 depending on the value of Bif 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 characterelse:
stack.append(char)# Return the final characterreturn stack[0]
classSolution{publicStringparseTernary(String expression){// Initialize a stackStack<Character> stack =newStack<>();// Traverse the expression from right to leftfor(int i = expression.length()-1; i >=0; i--){// If stack top is ?, then replace next four characters// with E1 or E2 depending on the value of Bif(!stack.isEmpty()&& stack.peek()=='?'){
stack.pop();char onTrue = stack.pop();
stack.pop();char onFalse = stack.pop();
stack.push(expression.charAt(i)=='T'? onTrue : onFalse);}// Otherwise, push this characterelse{
stack.push(expression.charAt(i));}}// Return the final characterreturnString.valueOf(stack.peek());}}
classSolution{public:
string parseTernary(string expression){// Initialize a stack
stack<char> stack;// Traverse the expression from right to leftfor(int i = expression.length()-1; i >=0; i--){// If stack top is ?, then replace next four characters// with E1 or E2 depending on the value of Bif(!stack.empty()&& stack.top()=='?'){
stack.pop();char onTrue = stack.top();
stack.pop();
stack.pop();char onFalse = stack.top();
stack.pop();
stack.push(expression[i]=='T'? onTrue : onFalse);}// Otherwise, push this characterelse{
stack.push(expression[i]);}}// Return the final characterreturnstring(1, stack.top());}};
classSolution{/**
* @param {string} expression
* @return {string}
*/parseTernary(expression){// Initialize a stackconst stack =[];// Traverse the expression from right to leftfor(let i = expression.length -1; i >=0; i--){const char = expression[i];// If stack top is ?, then replace next four characters// with E1 or E2 depending on the value of Bif(stack.length >0&& stack[stack.length -1]==='?'){
stack.pop();const onTrue = stack.pop();
stack.pop();const onFalse = stack.pop();
stack.push(char ==='T'? onTrue : onFalse);}// Otherwise, push this characterelse{
stack.push(char);}}// Return the final characterreturn stack[0];}}
publicclassSolution{publicstringParseTernary(string expression){// Initialize a stackStack<char> stack =newStack<char>();// Traverse the expression from right to leftfor(int i = expression.Length -1; i >=0; i--){char c = expression[i];// If stack top is ?, then replace next four characters// with E1 or E2 depending on the value of Bif(stack.Count >0&& stack.Peek()=='?'){
stack.Pop();char onTrue = stack.Pop();
stack.Pop();char onFalse = stack.Pop();
stack.Push(c =='T'? onTrue : onFalse);}// Otherwise, push this characterelse{
stack.Push(c);}}// Return the final characterreturn stack.Peek().ToString();}}
funcparseTernary(expression string)string{// Initialize a stack
stack :=[]byte{}// Traverse the expression from right to leftfor i :=len(expression)-1; i >=0; i--{
char := expression[i]// If stack top is ?, then replace next four characters// with E1 or E2 depending on the value of Biflen(stack)>0&& stack[len(stack)-1]=='?'{
stack = stack[:len(stack)-1]
onTrue := stack[len(stack)-1]
stack = stack[:len(stack)-1]
stack = stack[:len(stack)-1]
onFalse := stack[len(stack)-1]
stack = stack[:len(stack)-1]if char =='T'{
stack =append(stack, onTrue)}else{
stack =append(stack, onFalse)}}else{// Otherwise, push this character
stack =append(stack, char)}}// Return the final characterreturnstring(stack[0])}
class Solution {funparseTernary(expression: String): String {// Initialize a stackval stack = ArrayDeque<Char>()// Traverse the expression from right to leftfor(i in expression.length -1 downTo 0){val char = expression[i]// If stack top is ?, then replace next four characters// with E1 or E2 depending on the value of Bif(stack.isNotEmpty()&& stack.first()=='?'){
stack.removeFirst()val onTrue = stack.removeFirst()
stack.removeFirst()val onFalse = stack.removeFirst()
stack.addFirst(if(char =='T') onTrue else onFalse)}else{// Otherwise, push this character
stack.addFirst(char)}}// Return the final characterreturn stack.first().toString()}}
classSolution{funcparseTernary(_ expression:String)->String{// Initialize a stackvar stack =[Character]()// Traverse the expression from right to leftfor char in expression.reversed(){// If stack top is ?, then replace next four characters// with E1 or E2 depending on the value of Bif!stack.isEmpty && stack.last =="?"{
stack.removeLast()let onTrue = stack.removeLast()
stack.removeLast()let onFalse = stack.removeLast()
stack.append(char =="T"? onTrue : onFalse)}else{// Otherwise, push this character
stack.append(char)}}// Return the final characterreturnString(stack[0])}}
Time & Space Complexity
Time complexity: O(N)
Space complexity: O(N)
Where N is the length of expression
4. Binary Tree
Intuition
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.
Algorithm
Build the binary tree recursively:
Create a node for the current character.
If the next character is ?, recursively build the left subtree (true branch) and right subtree (false branch).
Use a global index to track position in the expression.
Traverse the tree from root:
If the current node is T, move to the left child.
If the current node is F, move to the right child.
classTreeNode:def__init__(self, val):
self.val = val
self.left =None
self.right =NoneclassSolution:defparseTernary(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 nodewhile root.left and root.right:if root.val =='T':
root = root.left
else:
root = root.right
return root.val
defconstructTree(self, expression):# Storing current character of expression
root = TreeNode(expression[self.index])# If the last character of expression, returnif self.index ==len(expression)-1:return root
# Check the next character
self.index +=1if expression[self.index]=='?':
self.index +=1
root.left = self.constructTree(expression)
self.index +=1
root.right = self.constructTree(expression)return root
classTreeNode{char val;TreeNode left;TreeNode right;TreeNode(char val){this.val = val;}}classSolution{int index =0;publicStringparseTernary(String expression){// Construct Binary TreeTreeNode root =constructTree(expression);// Parse the binary tree till we reach the leaf nodewhile(root.left !=null&& root.right !=null){if(root.val =='T'){
root = root.left;}else{
root = root.right;}}returnString.valueOf(root.val);}privateTreeNodeconstructTree(String expression){// Storing current character of expressionTreeNode root =newTreeNode(expression.charAt(index));// If last character of expression, returnif(index == expression.length()-1){return root;}// Check next character
index++;if(expression.charAt(index)=='?'){
index++;
root.left =constructTree(expression);
index++;
root.right =constructTree(expression);}return root;}}
structTreeNode{char val;
TreeNode* left;
TreeNode* right;TreeNode(char val):val(val),left(nullptr),right(nullptr){}};classSolution{private:int index =0;
TreeNode*constructTree(string& expression){// Storing current character of expression
TreeNode* root =newTreeNode(expression[index]);// If last character of expression, returnif(index == expression.length()-1){return root;}// Check next character
index++;if(expression[index]=='?'){
index++;
root->left =constructTree(expression);
index++;
root->right =constructTree(expression);}return root;}public:
string parseTernary(string expression){// Construct Binary Tree
TreeNode* root =constructTree(expression);// Parse the binary tree till we reach the leaf nodewhile(root->left !=nullptr&& root->right !=nullptr){if(root->val =='T'){
root = root->left;}else{
root = root->right;}}returnstring(1, root->val);}};
classTreeNode{constructor(val){this.val = val;this.left =null;this.right =null;}}classSolution{constructor(){this.index =0;}/**
* @param {string} expression
* @return {string}
*/parseTernary(expression){// Construct Binary Treelet root =this.constructTree(expression);// Parse the binary tree till we reach the leaf nodewhile(root.left !==null&& root.right !==null){if(root.val ==='T'){
root = root.left;}else{
root = root.right;}}return root.val;}constructTree(expression){// Storing current character of expressionconst root =newTreeNode(expression[this.index]);// If last character of expression, returnif(this.index === expression.length -1){return root;}// Check next characterthis.index++;if(expression[this.index]==='?'){this.index++;
root.left =this.constructTree(expression);this.index++;
root.right =this.constructTree(expression);}return root;}}
classTreeNode{publicchar val;publicTreeNode left;publicTreeNode right;publicTreeNode(char val){this.val = val;}}publicclassSolution{privateint index =0;publicstringParseTernary(string expression){
index =0;// Construct Binary TreeTreeNode root =ConstructTree(expression);// Parse the binary tree till we reach the leaf nodewhile(root.left !=null&& root.right !=null){if(root.val =='T'){
root = root.left;}else{
root = root.right;}}return root.val.ToString();}privateTreeNodeConstructTree(string expression){// Storing current character of expressionTreeNode root =newTreeNode(expression[index]);// If last character of expression, returnif(index == expression.Length -1){return root;}// Check next character
index++;if(expression[index]=='?'){
index++;
root.left =ConstructTree(expression);
index++;
root.right =ConstructTree(expression);}return root;}}
type TreeNode struct{
val byte
left *TreeNode
right *TreeNode
}funcparseTernary(expression string)string{
index :=0var constructTree func()*TreeNode
constructTree =func()*TreeNode {// Storing current character of expression
root :=&TreeNode{val: expression[index]}// If last character of expression, returnif index ==len(expression)-1{return root
}// Check next character
index++if expression[index]=='?'{
index++
root.left =constructTree()
index++
root.right =constructTree()}return root
}// Construct Binary Tree
root :=constructTree()// Parse the binary tree till we reach the leaf nodefor root.left !=nil&& root.right !=nil{if root.val =='T'{
root = root.left
}else{
root = root.right
}}returnstring(root.val)}
classTreeNode(var `val`: Char){var left: TreeNode?=nullvar right: TreeNode?=null}class Solution {privatevar index =0funparseTernary(expression: String): String {
index =0// Construct Binary Treevar root =constructTree(expression)// Parse the binary tree till we reach the leaf nodewhile(root?.left !=null&& root.right !=null){
root =if(root.`val` =='T') root.left else root.right
}return root?.`val`.toString()}privatefunconstructTree(expression: String): TreeNode {// Storing current character of expressionval root =TreeNode(expression[index])// If last character of expression, returnif(index == expression.length -1){return root
}// Check next character
index++if(expression[index]=='?'){
index++
root.left =constructTree(expression)
index++
root.right =constructTree(expression)}return root
}}
classTreeNode{var val:Charactervarleft:TreeNode?varright:TreeNode?init(_ val:Character){self.val = val
self.left=nilself.right=nil}}classSolution{privatevar index =0funcparseTernary(_ expression:String)->String{
index =0let chars =Array(expression)// Construct Binary Treevar root =constructTree(chars)// Parse the binary tree till we reach the leaf nodewhile root?.left!=nil&& root?.right!=nil{if root?.val =="T"{
root = root?.left}else{
root = root?.right}}returnString(root!.val)}privatefuncconstructTree(_ expression:[Character])->TreeNode{// Storing current character of expressionlet root =TreeNode(expression[index])// If last character of expression, returnif index == expression.count -1{return root
}// Check next character
index +=1if expression[index]=="?"{
index +=1
root.left=constructTree(expression)
index +=1
root.right=constructTree(expression)}return root
}}
Time & Space Complexity
Time complexity: O(N)
Space complexity: O(N)
Where N is the length of expression
5. Recursion
Intuition
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.
Algorithm
Define a recursive function solve(i, j) that evaluates the expression between indices i and j.
Base case: if i == j, return the single character.
Find the first ? after index i.
Find the matching : by tracking nested ternaries:
Start with count = 1 after the ?.
Increment count for each ?, decrement for each :.
Stop when count reaches 0.
If the condition at index i is T, recurse on the true branch.
Otherwise, recurse on the false branch.
Return the result of solve(0, len(expression) - 1).
classSolution:defparseTernary(self, expression:str)->str:# To analyze the expression between two indicesdefsolve(i, j):# If expression is a single character, return itif 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 =1while count !=0:if expression[aheadColonIndex]=='?':
count +=1elif expression[aheadColonIndex]==':':
count -=1
aheadColonIndex +=1# Check the value of B and recursively solveif expression[i]=='T':return solve(questionMarkIndex +1, aheadColonIndex -2)else:return solve(aheadColonIndex, j)# Solve for the entire expressionreturn solve(0,len(expression)-1)
classSolution{publicStringparseTernary(String expression){returnsolve(expression,0, expression.length()-1);}privateStringsolve(String expression,int i,int j){// If expression is a single character, return itif(i == j){return expression.substring(i, i +1);}// Find the index of ?int questionMarkIndex = i;while(expression.charAt(questionMarkIndex)!='?'){
questionMarkIndex++;}// Find one index after corresponding :int aheadColonIndex = questionMarkIndex +1;int count =1;while(count !=0){if(expression.charAt(aheadColonIndex)=='?'){
count++;}elseif(expression.charAt(aheadColonIndex)==':'){
count--;}
aheadColonIndex++;}// Check the value of B and recursively solveif(expression.charAt(i)=='T'){returnsolve(expression, questionMarkIndex +1, aheadColonIndex -2);}else{returnsolve(expression, aheadColonIndex, j);}}}
classSolution{private:
string expression;// To analyze the expression between two indices
string solve(int i,int j){// If expression is a single character, return itif(i == j){returnstring(1, expression[i]);}// Find the index of ?int questionMarkIndex = i;while(expression[questionMarkIndex]!='?'){
questionMarkIndex++;}// Find one index after corresponding :int aheadColonIndex = questionMarkIndex +1;int count =1;while(count !=0){if(expression[aheadColonIndex]=='?'){
count++;}elseif(expression[aheadColonIndex]==':'){
count--;}
aheadColonIndex++;}// Check the value of B and recursively solveif(expression[i]=='T'){returnsolve(questionMarkIndex +1, aheadColonIndex -2);}else{returnsolve(aheadColonIndex, j);}}public:
string parseTernary(string expr){
expression = expr;// Solve for the entire expressionreturnsolve(0, expression.length()-1);}};
classSolution{/**
* @param {string} expression
* @return {string}
*/parseTernary(expression){// To analyze the expression between two indicesconstsolve=(i, j)=>{// If expression is a single character, return itif(i === j){return expression[i];}// Find the index of ?let questionMarkIndex = i;while(expression[questionMarkIndex]!=='?'){
questionMarkIndex++;}// Find one index after corresponding :let aheadColonIndex = questionMarkIndex +1;let count =1;while(count !==0){if(expression[aheadColonIndex]==='?'){
count++;}elseif(expression[aheadColonIndex]===':'){
count--;}
aheadColonIndex++;}// Check the value of B and recursively solveif(expression[i]==='T'){returnsolve(questionMarkIndex +1, aheadColonIndex -2);}else{returnsolve(aheadColonIndex, j);}};// Solve for the entire expressionreturnsolve(0, expression.length -1);}}
publicclassSolution{publicstringParseTernary(string expression){returnSolve(expression,0, expression.Length -1);}privatestringSolve(string expression,int i,int j){// If expression is a single character, return itif(i == j){return expression[i].ToString();}// Find the index of ?int questionMarkIndex = i;while(expression[questionMarkIndex]!='?'){
questionMarkIndex++;}// Find one index after corresponding :int aheadColonIndex = questionMarkIndex +1;int count =1;while(count !=0){if(expression[aheadColonIndex]=='?'){
count++;}elseif(expression[aheadColonIndex]==':'){
count--;}
aheadColonIndex++;}// Check the value of B and recursively solveif(expression[i]=='T'){returnSolve(expression, questionMarkIndex +1, aheadColonIndex -2);}else{returnSolve(expression, aheadColonIndex, j);}}}
funcparseTernary(expression string)string{var solve func(i, j int)string
solve =func(i, j int)string{// If expression is a single character, return itif i == j {returnstring(expression[i])}// Find the index of ?
questionMarkIndex := i
for expression[questionMarkIndex]!='?'{
questionMarkIndex++}// Find one index after corresponding :
aheadColonIndex := questionMarkIndex +1
count :=1for count !=0{if expression[aheadColonIndex]=='?'{
count++}elseif expression[aheadColonIndex]==':'{
count--}
aheadColonIndex++}// Check the value of B and recursively solveif expression[i]=='T'{returnsolve(questionMarkIndex+1, aheadColonIndex-2)}else{returnsolve(aheadColonIndex, j)}}// Solve for the entire expressionreturnsolve(0,len(expression)-1)}
class Solution {funparseTernary(expression: String): String {returnsolve(expression,0, expression.length -1)}privatefunsolve(expression: String, i: Int, j: Int): String {// If expression is a single character, return itif(i == j){return expression[i].toString()}// Find the index of ?var questionMarkIndex = i
while(expression[questionMarkIndex]!='?'){
questionMarkIndex++}// Find one index after corresponding :var aheadColonIndex = questionMarkIndex +1var count =1while(count !=0){if(expression[aheadColonIndex]=='?'){
count++}elseif(expression[aheadColonIndex]==':'){
count--}
aheadColonIndex++}// Check the value of B and recursively solvereturnif(expression[i]=='T'){solve(expression, questionMarkIndex +1, aheadColonIndex -2)}else{solve(expression, aheadColonIndex, j)}}}
classSolution{funcparseTernary(_ expression:String)->String{let chars =Array(expression)returnsolve(chars,0, chars.count -1)}privatefuncsolve(_ expression:[Character],_ i:Int,_ j:Int)->String{// If expression is a single character, return itif i == j {returnString(expression[i])}// Find the index of ?var questionMarkIndex = i
while expression[questionMarkIndex]!="?"{
questionMarkIndex +=1}// Find one index after corresponding :var aheadColonIndex = questionMarkIndex +1var count =1while count !=0{if expression[aheadColonIndex]=="?"{
count +=1}elseif expression[aheadColonIndex]==":"{
count -=1}
aheadColonIndex +=1}// Check the value of B and recursively solveif expression[i]=="T"{returnsolve(expression, questionMarkIndex +1, aheadColonIndex -2)}else{returnsolve(expression, aheadColonIndex, j)}}}
Time & Space Complexity
Time complexity: O(N2)
Space complexity: O(N)
Where N is the length of expression
6. Constant Space Solution
Intuition
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.
Algorithm
Initialize index i = 0.
Loop while i is within bounds:
If the current character is not T or F, or we have reached the end, or the next character is :, we have found the result. Return it.
If the condition is T, skip to i + 2 (start of true branch).
If the condition is F:
Skip to i + 2 and use a counter starting at 1.
Increment counter for ?, decrement for :.
Stop when counter reaches 0; we are now at the false branch.
classSolution:defparseTernary(self, expression:str)->str:
i =0whileTrue:if expression[i]notin'TF'or i ==len(expression)-1\
or expression[i +1]==':':return expression[i]if expression[i]=='T':
i = i +2else:
count =1
i = i +2while count !=0:if expression[i]==':':
count -=1elif expression[i]=='?':
count +=1
i +=1
classSolution{publicStringparseTernary(String expression){int i =0;for(; i < expression.length();){if(expression.charAt(i)!='T'&& expression.charAt(i)!='F'|| i == expression.length()-1|| expression.charAt(i +1)==':'){break;}if(expression.charAt(i)=='T'){
i +=2;}else{int count;for(count =1, i +=2; count !=0; i++){if(expression.charAt(i)==':'){
count--;}elseif(expression.charAt(i)=='?'){
count++;}}}}return expression.substring(i, i +1);}}
classSolution{public:
string parseTernary(string expression){int i =0;for(; i < expression.length();){if(expression[i]!='T'&& expression[i]!='F'|| i == expression.length()-1|| expression[i +1]==':'){break;}if(expression[i]=='T'){
i +=2;}else{int count;for(count =1, i +=2; count !=0; i++){if(expression[i]==':'){
count--;}elseif(expression[i]=='?'){
count++;}}}}return expression.substr(i,1);}};
classSolution{/**
* @param {string} expression
* @return {string}
*/parseTernary(expression){let i =0;for(; i < expression.length;){if(expression[i]!='T'&& expression[i]!='F'|| i == expression.length -1|| expression[i +1]==':'){break;}if(expression[i]=='T'){
i +=2;}else{let count;for(count =1, i +=2; count !=0; i++){if(expression[i]==':'){
count--;}elseif(expression[i]=='?'){
count++;}}}}return expression.substring(i, i +1);}}
publicclassSolution{publicstringParseTernary(string expression){int i =0;while(i < expression.Length){if((expression[i]!='T'&& expression[i]!='F')|| i == expression.Length -1|| expression[i +1]==':'){break;}if(expression[i]=='T'){
i +=2;}else{int count =1;
i +=2;while(count !=0){if(expression[i]==':'){
count--;}elseif(expression[i]=='?'){
count++;}
i++;}}}return expression[i].ToString();}}
funcparseTernary(expression string)string{
i :=0for i <len(expression){if(expression[i]!='T'&& expression[i]!='F')||
i ==len(expression)-1|| expression[i+1]==':'{break}if expression[i]=='T'{
i +=2}else{
count :=1
i +=2for count !=0{if expression[i]==':'{
count--}elseif expression[i]=='?'{
count++}
i++}}}returnstring(expression[i])}
class Solution {funparseTernary(expression: String): String {var i =0while(i < expression.length){if((expression[i]!='T'&& expression[i]!='F')|| i == expression.length -1|| expression[i +1]==':'){break}if(expression[i]=='T'){
i +=2}else{var count =1
i +=2while(count !=0){if(expression[i]==':'){
count--}elseif(expression[i]=='?'){
count++}
i++}}}return expression[i].toString()}}
classSolution{funcparseTernary(_ expression:String)->String{let chars =Array(expression)var i =0while i < chars.count {if(chars[i]!="T"&& chars[i]!="F")|| i == chars.count -1|| chars[i +1]==":"{break}if chars[i]=="T"{
i +=2}else{var count =1
i +=2while count !=0{if chars[i]==":"{
count -=1}elseif chars[i]=="?"{
count +=1}
i +=1}}}returnString(chars[i])}}
Time & Space Complexity
Time complexity: O(N)
Space complexity: O(1)
Where N is the length of expression
Common Pitfalls
Evaluating Left-to-Right Instead of Right-to-Left
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.
Incorrectly Matching ? 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.
Off-by-One Errors in Substring Extraction
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.