LeetCode 1807: Evaluate the Bracket Pairs of a String – Java Solution & Explanation

Replace bracketed keys with their corresponding values using a HashMap and a single pass through the string.

Krishna Shrivastava
1 views
LinkedInGithubX
0
0
LeetCode 1807: Evaluate the Bracket Pairs of a String – Java Solution & Explanation
Listen to articleAudio version

Introduction

LeetCode 1807, Evaluate the Bracket Pairs of a String, is a string-processing problem that combines two common techniques:

  1. Using a HashMap for fast key-value lookup
  2. Traversing a string while keeping track of whether the current characters belong to a bracket pair

The string contains ordinary characters as well as bracketed keys such as:

(name)
(age)
(city)

A separate knowledge list provides the value associated with each known key.

For every bracket pair:

  1. If the key exists in knowledge, replace the entire pair with its value.
  2. If the key is not present, replace the entire pair with ?.

For example:

s = "(name)is(age)yearsold"

with:

knowledge = [
["name", "bob"],
["age", "two"]
]

becomes:

bobistwoyearsold

The main challenge is identifying exactly which characters belong to a bracketed key while keeping the characters outside brackets unchanged.

Question Link

LeetCode 1807 – Evaluate the Bracket Pairs of a String

Understanding the Problem

Consider:

s = "(name)is(age)yearsold"

The bracket pairs are:

(name)
(age)

The text outside the brackets is:

is
yearsold

Suppose:

name → bob
age → two

Then the transformation is:

(name) → bob
(age) → two

So the final result becomes:

bobistwoyearsold

The characters outside brackets should not be interpreted as keys.

For example:

s = "(a)(a)aaa"

with:

a → yes

produces:

yesyesaaa

The final aaa remains unchanged because those characters are not inside brackets.

Approach

The solution can be divided into two parts.

Store the Knowledge in a HashMap

The knowledge array contains pairs such as:

["name", "bob"]
["age", "two"]

These pairs are stored in a HashMap:

HashMap<String, String> mp = new HashMap<>();

for(int i = 0; i < knowledge.size(); i++){
mp.put(
knowledge.get(i).get(0),
knowledge.get(i).get(1)
);
}

This gives direct access to a value using its key.

For example:

mp.get("name")

returns:

bob

And:

mp.containsKey("unknown")

can be used to determine whether a key exists.

Because each key appears at most once in knowledge, there is no need to handle duplicate key definitions.

Detecting a Bracketed Key

The solution uses a boolean variable:

boolean bo = false;

This represents whether the current position is inside a bracket pair.

When the character immediately before the current character is '(':

if(i > 0 && s.charAt(i - 1) == '('){
key = "";
bo = true;
}

the solution starts collecting a new key.

For example:

(name)
^

Once n is reached, the previous character is '(', so the solution begins collecting:

n
na
nam
name

When ')' is encountered:

if(s.charAt(i) == ')'){
bo = false;
}

the key is complete.

The solution can then look it up in the map.

Replacing the Key

When the closing bracket is found, the code checks whether the collected key exists:

if(mp.containsKey(key)){
an += mp.get(key);
key = "";
}
else{
an += "?";
key = "";
}

If the key is known:

(name) → bob

If the key is unknown:

(address) → ?

This directly follows the problem statement.

Keeping Characters Outside Brackets

Characters that are not part of a bracketed key are added directly to the result:

if(!bo && (s.charAt(i) != ')' && s.charAt(i) != '(')){
an += s.charAt(i);
}

This is important because ordinary characters must remain unchanged.

For:

hi(name)

the characters:

h
i

are outside the brackets and are therefore copied directly.

The key:

name

is evaluated separately.

Java Solution

Here is the submitted solution with comments explaining the important parts:

class Solution {

public String evaluate(String s, List<List<String>> knowledge) {

// Store key -> value mappings
HashMap<String, String> mp = new HashMap<>();

for(int i = 0; i < knowledge.size(); i++){
mp.put(
knowledge.get(i).get(0),
knowledge.get(i).get(1)
);
}

String key = "";

// true when we are currently reading a key
boolean bo = false;

String an = "";

for(int i = 0; i < s.length(); i++){

// The character after '(' starts a new key
if(i > 0 && s.charAt(i - 1) == '('){
key = "";
bo = true;
}

// ')' means the current key is complete
if(s.charAt(i) == ')'){
bo = false;
}

// Characters outside brackets are copied directly
if(!bo && s.charAt(i) != ')' && s.charAt(i) != '('){
an += s.charAt(i);
}

// Characters inside brackets are collected as the key
if(bo){
key += s.charAt(i);
}

// Evaluate the completed key
if(key.length() > 0 && s.charAt(i) == ')'){

if(mp.containsKey(key)){
an += mp.get(key);
key = "";
}
else{
an += "?";
key = "";
}
}
}

return an;
}
}

Dry Run

Consider:

s = "(name)is(age)"

and:

knowledge = [
["name", "bob"],
["age", "two"]
]

Initially:

an = ""

Reading (name)

The scanner encounters '('.

The next characters are collected as the key:

n
na
nam
name

When ')' is reached:

key = "name"

The map contains "name":

name → bob

So:

an = "bob"

Reading is

These characters are outside brackets:

i
s

They are copied directly:

an = "bobis"

Reading (age)

The key is collected:

a
ag
age

At the closing bracket:

key = "age"

The map contains:

age → two

So:

an = "bobistwo"

The final result is:

bobistwo

Handling an Unknown Key

Consider:

s = "hi(name)"

with:

knowledge = [["a", "b"]]

The map contains only:

a → b

When the scanner reaches:

(name)

the collected key is:

name

But:

mp.containsKey("name")

is false.

Therefore the entire bracket pair is replaced with:

?

The result becomes:

hi?

This is an important part of the problem because unknown keys should not remain in the output.

Why a HashMap Works Well

The knowledge list can contain up to 10^5 entries.

Searching through the entire list for every bracket pair would be unnecessarily expensive.

Instead, the solution converts it into:

key → value

using a HashMap.

Then a lookup is expected O(1).

This makes the solution efficient even when the knowledge list is large.

A Small Implementation Improvement

The submitted solution uses:

String an = "";

and repeatedly performs:

an += ...

Java String objects are immutable, so repeatedly concatenating strings can create many intermediate objects.

A StringBuilder is more appropriate when constructing a result character by character.

The same approach can therefore be written as:

class Solution {

public String evaluate(String s, List<List<String>> knowledge) {

HashMap<String, String> mp = new HashMap<>();

for(List<String> pair : knowledge){
mp.put(pair.get(0), pair.get(1));
}

StringBuilder ans = new StringBuilder();
StringBuilder key = new StringBuilder();

boolean inside = false;

for(int i = 0; i < s.length(); i++){

char ch = s.charAt(i);

if(ch == '('){
inside = true;
key.setLength(0);
}
else if(ch == ')'){

inside = false;

String k = key.toString();

if(mp.containsKey(k)){
ans.append(mp.get(k));
}
else{
ans.append('?');
}
}
else if(inside){
key.append(ch);
}
else{
ans.append(ch);
}
}

return ans.toString();
}
}

This version expresses the parsing states more directly:

'(' → start key
inside brackets → collect key
')' → evaluate key
outside brackets → copy character

Complexity Analysis

Let:

  1. n = length of s
  2. k = number of entries in knowledge

Building the HashMap requires:

Time: O(k)

The string is scanned once:

Time: O(n)

Therefore, the overall expected complexity is:

Time Complexity: O(n + k)

The HashMap stores all known keys and values.

Space Complexity: O(k + n)

The O(n) component accounts for the output and temporary string-building structures.

Interview Tip

This problem is a good example of a state-based string traversal.

Instead of trying to manipulate the entire string repeatedly, scan it once and maintain a small amount of state:

Outside brackets
↓
'('
↓
Inside bracket → collect key
↓
')'
↓
Look up key
↓
Append value / '?'
↓
Outside brackets

When a string contains delimiters such as:

(...)
[...]
{...}

a similar state-based approach can often simplify the implementation.

The second important pattern is recognizing when a HashMap is appropriate: whenever many lookups need to be performed using a unique key.

Conclusion

LeetCode 1807 is primarily a string parsing + HashMap lookup problem.

The solution first converts the knowledge list into a key-value map. It then scans the string and distinguishes between characters inside and outside brackets.

For every bracketed key:

known key → corresponding value
unknown key → ?

The important implementation ideas are:

  1. Use a HashMap for fast key lookup.
  2. Track whether the scanner is inside a bracket pair.
  3. Collect characters between '(' and ')'.
  4. Preserve characters outside brackets.
  5. Return the first available result after processing the complete string.

The submitted approach follows this logic correctly. For production-quality Java code, StringBuilder is preferable to repeated String concatenation when constructing the result.

Ai Assistant Kas
LeetCode 1807: Evaluate the Bracket Pairs of a String – Java Solution & Explanation | Kodesword | Kode$word