Road to Google – Part 5 Longest Substring Without Repeating Characters: Brute Force and Optimal Solution

Brute force solution.

It has been a little while since I last updated my blog. But my coding and tech journey never stops, and I’ll keep searching for every possibility I can think of to grow not only as a programmer but also as a person.

Question:

Given a string, find the length of the longest substring without repeating characters.

This question asks you to find the longest substring within a string. Let’s say you’ve given this string shown in image 01.

image 01

The unique substrings you can find in the string are “abc” and “cab”. And the length of both is 3, so the answer to this question is 3.

image 02

Substring vs Subsequence:

Here, you may want to ask a question – is it contiguous? So what does it mean? Well, as you can see in the below image 03, a substring is a contiguous series of unique characters, while a subsequence contains a single character that doesn’t necessarily have to be a contiguous series of unique characters. This time, we’ll only focus on the substring.

image 03

Our test cases:

Here are our test cases and what needs your attention is the last one. There are two substrings, “abc” and “cbda”, where c overlaps both. In this case, the longest substring is the latter one.

image 04

Our brute force solution:

Here, you’ve given this string, and let’s think about how we can solve this problem.

image 05

We have the int variable that keeps track of the longest substring and we’ll start loop iteration from “a”.

image 06

Starting from a, ask your self “have you seen ‘a’ before?” – No. So, we’ll add ‘a’ to the cache and update the longest to 1.

image 07

And we’ll keep iterating through the string up to the first ‘c’ and at this point, the longest is 3 and chance has a, b, and c.

image 08

And when we raches the second ‘b’, ask yourself “have you seen ‘b’ before?” – Yes you did, and the first iteration ends here.

image 09

And the next iteration starts from ‘b’ and it ends up with the longest with 2.

image 10

The next iteration starts from ‘c’ and it ends up with the longest with 3.

image 11

The next iteration starts from ‘b’ and it ends up with the longest with 4. And sat this point, you already know that 4 is the longest number.

image 5

The rest of the iteration doesn’t need any description, so I’ll skip it. Now, let’s see how we can solve this problem with actual code.

Coding solution:

import java.util.Set;
import java.util.HashSet;

public class LongestSubstring {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int ans = 0;

        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j <= n; j++) {
                if (allUnique(s,i,j)) ans = Math.max(ans, j - i);
            }
        }
        return ans;
    }

    public boolean allUnique(String s, int start, int end) {
        Set<Character> set = new HashSet<>();
        for (int i = start; i < end; i++) {
            Character ch = s.charAt(i);
            if (set.contains(ch)) return false;
            set.add(ch);
        }
        return true;
    }
    
    public static void main(String[] args) {
        String v = "abccbda";
        LongestSubstring longestSubstring = new LongestSubstring();
        int answer = longestSubstring.lengthOfLongestSubstring(v);
        System.out.println("The answer is: " + answer);
    }
}

Let’s take a look at every line:

In the lengthOfLongestSubstring method, the length of the string s is calculated and stored in the variable n.

int n = s.length();

An integer variable ans is initialized to 0 to store the length of the longest substring without repeating characters.

int ans = 0;

The outer for loop iterates over the string s starting from index i = 0 to n-1 to explore all possible substrings of s.

*It’s n-1 because, in the programming world, an array always starts from 0.

The inner for loop iterates over the string s starting from i+1 to n to explore all substrings ending at index j.

For each pair of i and j, the allUnique method is called to check if the substring from start to end is unique.

for (int i = 0; i < n; i++) {
            for (int j = i + 1; j <= n; j++) {
                if (allUnique(s,i,j)) ans = Math.max(ans, j - i);
     }
}
return ans;

The allUnique method takes in a string s and two integer values start and end as parameters and returns a boolean value indicating whether the substring is unique or not.

The method creates a Set of Character objects named set and iterates over the substring from start to end-1.

For each character ch in the substring, the method checks if the character is already present in the set. If it is, then the method returns false indicating that the substring is not unique.

If the character ch is not present in the set, it is added to the set.

After the loop, the method returns true indicating that the substring is unique.

public boolean allUnique(String s, int start, int end) {
        Set<Character> set = new HashSet<>();
        for (int i = start; i < end; i++) {
            Character ch = s.charAt(i);
            if (set.contains(ch)) return false;
            set.add(ch);
        }
        return true;
    }

If the substring is unique, the length of the substring is calculated and stored in j-i. This value is compared with the current value of ans and if it is greater, ans is updated to the new value.

After the inner loop, the outer loop continues with the next value of i.

After both loops, the final value of ans is returned as the length of the longest substring without repeating characters.

for (int i = 0; i < n; i++) {
            for (int j = i + 1; j <= n; j++) {
                if (allUnique(s,i,j)) ans = Math.max(ans, j - i);
     }
}
return ans;

Executed result:

$ java LongestSubstring
The answer is: 4

Leave a Reply