mediumGeeksforGeeksNot Started

Infix to Postfix

A curated StudyFlow practice problem with comprehensive editorial and multi-language solutions.

Solve on GeeksforGeeks
Lesson

Problem Statement

Given an infix expression exp in string form, convert it into a postfix expression.

Infix expression: The expression of the form a op b (e.g. a + b). Postfix expression: The expression of the form a b op (e.g. a b +).

Precedence & Associativity: 1. ^ (Power) : Precedence 3, Right-to-Left associative. 2. *, / (Multiplication & Division) : Precedence 2, Left-to-Right associative. 3. +, - (Addition & Subtraction) : Precedence 1, Left-to-Right associative.

Example 1 · Standard Precedence:

Input: exp = "a+b*(c^d-e)^(f+g*h)-i"
Output: "abcd^e-fgh*+^*+i-"
Explanation: Converted following standard operator precedence and parentheses nesting.

Example 2 · Parentheses Override:

Input: exp = "(A+B)*(C+D)"
Output: "AB+CD+*"
Explanation: Parentheses evaluated first: A B + and C D +, then multiplied.

Constraints:

  • 1 <= exp.length <= 105
  • exp contains alphanumeric characters, operators (+, -, *, /, ^), and parentheses (, ).

What You'll Learn

Key principles and algorithmic techniques you will master from this problem:

  • Master Dijkstra's Shunting Yard Algorithm.
  • Correctly model operator precedence and right-associativity for the exponent operator ^.
  • Handle multi-level parentheses grouping and operator stack cleanup.

Pattern Recognition Trigger

How to instantly recognize this algorithmic pattern when encountering unseen interview questions:

Algorithmic Decision Tree:

  • If alphanumeric operand -> append to output string.
  • If ( -> push to stack.
  • If ) -> pop and append to output until ( is popped.
  • If operator -> pop while prec(stack.top) > prec(curr) or (prec(stack.top) == prec(curr) and left-associative), then push.
  • At end -> pop all remaining operators to output.

Connected Patterns:

Postfix to InfixPrefix to InfixEvaluate Reverse Polish Notation

1. Expression Tree Construction and Post-Order Traversal

Intuition

Parse the infix string into a full binary expression tree by recursively splitting on the lowest precedence operator, then generate the postfix string via a post-order traversal (Left, Right, Root).

Algorithm

  1. Step 1: Find the main operator outside parentheses with lowest precedence.
  2. Step 2: Create a root tree node for this operator.
  3. Step 3: Recursively parse left substring as left child and right substring as right child.
  4. Step 4: Perform Post-Order traversal (left -> right -> root) to produce postfix string.
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <iostream>
2#include <string>
3#include <stack>
4
5class Solution {
6 int precedence(char c) {
7 if (c == '^') return 3;
8 if (c == '*' || c == '/') return 2;
9 if (c == '+' || c == '-') return 1;
10 return -1;
11 }
12public:
13 std::string infixToPostfix(std::string s) {
14 std::stack<char> st;
15 std::string result = "";
16 for (char c : s) {
17 if (isalnum(c)) {
18 result += c;
19 } else if (c == '(') {
20 st.push(c);
21 } else if (c == ')') {
22 while (!st.empty() && st.top() != '(') {
23 result += st.top();
24 st.pop();
25 }
26 if (!st.empty()) st.pop();
27 } else {
28 while (!st.empty() && (precedence(st.top()) > precedence(c) ||
29 (precedence(st.top()) == precedence(c) && c != '^'))) {
30 result += st.top();
31 st.pop();
32 }
33 st.push(c);
34 }
35 }
36 while (!st.empty()) {
37 result += st.top();
38 st.pop();
39 }
40 return result;
41 }
42};
43
44int main() {
45 Solution solver;
46 std::cout << "Postfix: " << solver.infixToPostfix("(A+B)*(C+D)") << std::endl;
47 return 0;
48}

Time & Space Complexity

  • Time complexity: O(N^2) — Building an explicit Abstract Syntax Tree by searching minimum precedence root operators requires O(N2) recursive splitting.
  • Space complexity: O(N) — O(N) tree nodes.

Why Brute Force Doesn't Scale:

A long flat expression like A+B+C+...+Z requires quadratic scans.

Shunting Yard algorithm processes 100,000 characters in <15ms.


2. Map-Driven Operator Stack

Intuition

Use an explicit precedence map and stack to process tokens left to right.

Algorithm

  1. Step 1: Define precedence map: ^: 3, *: 2, /: 2, +: 1, -: 1.
  2. Step 2: Traverse string character by character.
  3. Step 3: Route operands to result and operators through precedence resolution.
  4. Step 4: Drain stack.
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <iostream>
2#include <string>
3#include <stack>
4#include <unordered_map>
5
6class Solution {
7public:
8 std::string infixToPostfix(std::string s) {
9 std::unordered_map<char, int> prec = {{'^', 3}, {'*', 2}, {'/', 2}, {'+', 1}, {'-', 1}};
10 std::stack<char> st;
11 std::string res = "";
12 for (char c : s) {
13 if (isalnum(c)) res += c;
14 else if (c == '(') st.push(c);
15 else if (c == ')') {
16 while (!st.empty() && st.top() != '(') {
17 res += st.top();
18 st.pop();
19 }
20 if (!st.empty()) st.pop();
21 } else {
22 while (!st.empty() && st.top() != '(' &&
23 (prec[st.top()] > prec[c] || (prec[st.top()] == prec[c] && c != '^'))) {
24 res += st.top();
25 st.pop();
26 }
27 st.push(c);
28 }
29 }
30 while (!st.empty()) {
31 res += st.top();
32 st.pop();
33 }
34 return res;
35 }
36};
37
38int main() {
39 Solution solver;
40 std::cout << "Postfix: " << solver.infixToPostfix("(A+B)*(C+D)") << std::endl;
41 return 0;
42}

Time & Space Complexity

  • Time complexity: O(N) — Precedence table lookup in O(1) across single pass of N characters.
  • Space complexity: O(N) — O(N) space for stack.

3. Optimal Shunting Yard Algorithm

Intuition

Dijkstra's Shunting Yard algorithm parses linear expressions in strictly O(N) time by buffering pending operators on a stack ordered by precedence.

Algorithm

  1. Step 1: Initialize an empty operator stack st and output string buffer res.
  2. Step 2: Loop through each character c in exp.
  3. Step 3: If c is alphanumeric, append directly to res.
  4. Step 4: If c == '(', push to st.
  5. Step 5: If c == ')', pop operators from st and append to res until '(' is encountered; pop and discard '('.
  6. Step 6: If c is an operator, pop operators with higher precedence (or equal precedence if left-associative), then push c.
  7. Step 7: After the loop, pop all remaining operators from st to res and return.

Shunting Yard Stack Trace

2 of 2 questions left today
Step 1 / 8
Trace timeline13% explored
Current operationSTEP 1 OF 8
Stack: ['(']
Visual state
Values and pointers at this exact step
stack
TOP
'('
Push adds to the top · Pop removes from the top
Why this step matters

Stack: [(]

Step 1 / 8
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <iostream>
2#include <string>
3#include <stack>
4
5class Solution {
6 int getPrecedence(char ch) {
7 switch (ch) {
8 case '^': return 3;
9 case '*':
10 case '/': return 2;
11 case '+':
12 case '-': return 1;
13 default: return -1;
14 }
15 }
16public:
17 std::string infixToPostfix(std::string exp) {
18 std::stack<char> st;
19 std::string result = "";
20 for (char c : exp) {
21 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {
22 result += c;
23 } else if (c == '(') {
24 st.push(c);
25 } else if (c == ')') {
26 while (!st.empty() && st.top() != '(') {
27 result += st.top();
28 st.pop();
29 }
30 if (!st.empty()) st.pop(); // pop __SF_TOKEN_A__
31 } else {
32 while (!st.empty() && st.top() != '(' &&
33 (getPrecedence(st.top()) > getPrecedence(c) ||
34 (getPrecedence(st.top()) == getPrecedence(c) && c != '^'))) {
35 result += st.top();
36 st.pop();
37 }
38 st.push(c);
39 }
40 }
41 while (!st.empty()) {
42 result += st.top();
43 st.pop();
44 }
45 return result;
46 }
47};
48
49int main() {
50 Solution solver;
51 std::cout << "Postfix: " << solver.infixToPostfix("(A+B)*(C+D)") << std::endl;
52 return 0;
53}

Time & Space Complexity

  • Time complexity: O(N) — Each character is pushed and popped at most once in a single pass of length N.
  • Space complexity: O(N) — O(N) space for operator stack and result string.

Approach Comparison Matrix

Side-by-side comparison of time, space, and algorithmic trade-offs across each approach:

ApproachTimeSpaceCore IdeaTrade-off / Bottleneck
1.Expression Tree TraversalO(N^2)O(N)Build binary syntax tree and perform post-order traversal.Splitting strings across tree levels.
2.Map-Driven Operator StackO(N)O(N)Single pass with hash map precedence lookup.Map lookup.
3.Optimal Shunting Yard AlgorithmOptimalO(N)O(N)Switch-based precedence with associativity checks.None (Optimal).

Common Pitfalls & Crucial Edge Cases

Pitfall 1:

Popping equal precedence for ^ (breaking right-to-left associativity).

Pitfall 2:

Leaving ( or ) in the final output string.

Pitfall 3:

Not popping all remaining operators at the end of the string.

Crucial Edge Cases to Validate:

  • Single operand without operators `exp = 'A'` — Returns 'A'.
  • Right-associative power chain `exp = 'a^b^c'` — Returns 'abc^^'.
  • Nested redundant parentheses `exp = '((A+B))'` — Returns 'AB+'.

Interview Tips & Best Practices

How to communicate your thought process and address follow-ups in a live technical interview:

  1. Mention Dijkstra's Shunting Yard Algorithm by name to demonstrate classical CS knowledge.
  2. Explicitly detail the precedence ladder: ^ (3, right) > *, / (2, left) > +, - (1, left).
  3. State clearly why postfix expressions do not require parentheses.

Quick Comprehension Check

Test your intuitive understanding of the core concept in 30 seconds:

1.Why is the power operator ^ treated differently when comparing precedence against the stack top?

2.What happens to parentheses in the final postfix expression?