15. Substrings with Same First and Last Characters

The problem can be found at the following link: ๐Ÿ”— Question Link

๐Ÿงฉ Problem Description

Given a string s consisting of lowercase English letters, count all substrings in which the first and last characters are the same.

A substring is a contiguous sequence of characters within the string. Single-character substrings are always valid.

๐Ÿ“˜ Examples

Example 1:

Input:

s = "abcab"

Output:

7

Explanation:

The valid substrings are "a", "b", "c", "a", "b", "abca", and "bcab".

Example 2:

Input:

s = "aba"

Output:

4

Explanation:

The valid substrings are "a", "b", "a", and "aba".

๐Ÿ”’ Constraints

  • $1 \leq |s| \leq 10^4$

  • s contains only lowercase English alphabets ('a' to 'z')

โœ… My Approach

Frequency Count using Combinatorics

A substring starts and ends with the same character if we consider all positions where a character appears. For a character appearing f times, the number of such substrings is:

count=fร—(f+1)2\text{count} = \frac{f \times (f + 1)}{2}

This accounts for:

  • f single-character substrings

  • fC2 substrings where both ends are the same character

We use a frequency array of size 256 (or 26 if lowercase only) to count characters, then sum this formula over all counts.

๐Ÿงฎ Time and Auxiliary Space Complexity

  • Expected Time Complexity: O(n), as we scan the string once to count character frequencies and once more to sum results.

  • Expected Auxiliary Space Complexity: O(1), as we use a fixed-size array of length 256 regardless of input size.

๐Ÿง  Code (C++)

class Solution {
  public:
    int countSubstring(string &s) {
        long long cnt[256]={}, ans=0;
        for(char c:s) cnt[(unsigned char)c]++;
        for(int i=0;i<256;i++)
            ans += cnt[i]*(cnt[i]+1)/2;
        return (int)ans;
    }
};
โšก Alternative Approaches

๐Ÿ“Š 2๏ธโƒฃ HashMap-Based Frequency Count

๐Ÿ’ก Algorithm Steps:

  1. Initialize a unordered_map<char, int>.

  2. Traverse the string s, incrementing count for each character.

  3. For each (char, freq) in the map, add freq * (freq + 1) / 2 to result.

class Solution {
  public:
    int countSubstring(string &s) {
        unordered_map<char, int> freq;
        for (char c : s) freq[c]++;
        long long ans = 0;
        for (auto &[ch, f] : freq) ans += 1LL * f * (f + 1) / 2;
        return (int)ans;
    }
};

โœ… Why This Approach?

  • Reduces unnecessary storage compared to fixed-size array (good for limited character sets).

๐Ÿ“ Complexity Analysis:

  • Time: O(n)

  • Auxiliary Space: O(k), where k is the number of unique characters

๐Ÿ“Š 3๏ธโƒฃ Using C++ STL map or array<int, 26> (If Input is Lowercase Only)

๐Ÿ’ก Algorithm Steps:

  1. Initialize an array of size 26 for lowercase letter counts.

  2. Traverse string and increment count.

  3. Compute total using same formula.

class Solution {
  public:
    int countSubstring(string &s) {
        array<int, 26> cnt = {};
        for (char c : s) cnt[c - 'a']++;
        long long ans = 0;
        for (int f : cnt) ans += 1LL * f * (f + 1) / 2;
        return (int)ans;
    }
};

โœ… Why This Approach?

  • Fast and space-efficient when you know the character set (aโ€“z).

  • Constant-size array is faster than unordered_map.

๐Ÿ“ Complexity Analysis:

  • Time: O(n)

  • Auxiliary Space: O(1) (since 26 is constant)

๐Ÿ†š Comparison of Approaches

Approach

โฑ๏ธ Time

๐Ÿ’พ Space

โœ… Pros

โš ๏ธ Cons

Frequency array (main)

๐ŸŸข O(n)

๐ŸŸข O(ฮฃ=256)

Fastest, simplest

Wastes space for small charsets

unordered_map count

๐ŸŸข O(n)

๐Ÿ”ธ O(k)

Efficient for limited unique chars

Slightly longer code

array<int, 26>

๐ŸŸข O(n)

๐Ÿ”ธ O(1)

Best for lowercase-only strings

Only works with known charsets

โœ… Best Choice by Scenario

Scenario

Recommended Approach

Performance-critical, any charset

๐Ÿฅ‡ Fixed-size array of 256

Lowercase input (aโ€“z)

๐Ÿฅˆ 26-letter frequency array

Space-aware and clean design

๐Ÿฅ‰ HashMap

๐Ÿง‘โ€๐Ÿ’ป Code (Java)

class Solution {
    public int countSubstring(String s) {
        int[] cnt = new int[256];
        long ans = 0;
        for (char c : s.toCharArray()) cnt[c]++;
        for (int x : cnt) ans += (long)x * (x + 1) / 2;
        return (int)ans;
    }
}

๐Ÿ Code (Python)

class Solution:
    def countSubstring(self, s):
        from collections import Counter
        return sum(v * (v + 1) // 2 for v in Counter(s).values())

๐Ÿง  Contribution and Support

For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: ๐Ÿ“ฌ Any Questions?. Letโ€™s make this learning journey more collaborative!

โญ If you find this helpful, please give this repository a star! โญ


๐Ÿ“Visitor Count

Last updated