Program to find longest nice substring using Python

A nice substring is one where every letter appears in both uppercase and lowercase. For example, "bBb" is nice because 'b' appears as both 'b' and 'B'. This tutorial shows how to find the longest nice substring in Python.

Problem Understanding

Given a string, we need to find the longest substring where every letter appears in both uppercase and lowercase forms. If multiple substrings have the same maximum length, return the one that appears first.

Algorithm Approach

We'll use a nested loop approach to check all possible substrings:

  • For each starting position, build a substring character by character

  • Track uppercase and lowercase letters using sets

  • Check if all letters appear in both forms

  • Keep track of the longest valid substring found

Implementation

def find_longest_nice_substring(s):
    cur_max = -1
    res = ""
    
    for i in range(len(s)):
        upper = set()
        lower = set()
        
        # Process first character
        c = s[i]
        if c.islower():
            lower.add(c)
        if c.isupper():
            upper.add(c.lower())
        
        # Extend substring from position i
        for j in range(i + 1, len(s)):
            c = s[j]
            if c.islower():
                lower.add(c)
            if c.isupper():
                upper.add(c.lower())
            
            # Check if current substring is nice
            if upper == lower and len(upper) > 0:
                if j - i > cur_max:
                    cur_max = j - i
                    res = s[i:j+1]
    
    return res

# Test the function
s = "ZbybBbz"
result = find_longest_nice_substring(s)
print(f"Input: {s}")
print(f"Longest nice substring: '{result}'")
Input: ZbybBbz
Longest nice substring: 'bBb'

How It Works

Let's trace through the example "ZbybBbz":

  1. Starting at index 0 ('Z'): Only uppercase 'Z', no lowercase 'z' in subsequent characters

  2. Starting at index 1 ('b'): When we reach index 3 ('B'), we have both 'b' and 'B' ? nice substring "byb" isn't valid because 'y' appears only in lowercase

  3. Starting at index 2 ('y'): When we reach "bB", we get a nice substring "bBb" of length 3

Alternative Approaches

Here's a more optimized version using divide and conquer:

def find_longest_nice_optimized(s):
    if len(s) < 2:
        return ""
    
    # Find all unique characters
    chars = set(s)
    
    # Find characters that don't have both cases
    for i, c in enumerate(s):
        if c.swapcase() not in chars:
            # Split at this character and recurse
            left = find_longest_nice_optimized(s[:i])
            right = find_longest_nice_optimized(s[i+1:])
            return left if len(left) >= len(right) else right
    
    # All characters have both cases
    return s

# Test both approaches
s = "ZbybBbz"
print(f"Brute force: '{find_longest_nice_substring(s)}'")
print(f"Optimized: '{find_longest_nice_optimized(s)}'")
Brute force: 'bBb'
Optimized: 'bBb'

Comparison

Approach Time Complexity Space Complexity Best For
Brute Force O(n³) O(1) Simple understanding
Divide & Conquer O(n²) O(n) Better performance

Conclusion

The brute force approach checks all substrings systematically, while the divide and conquer method optimizes by splitting at invalid characters. Both methods effectively find the longest nice substring where every letter appears in both uppercase and lowercase forms.

Updated on: 2026-03-25T20:49:42+05:30

654 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements