Talentd
FleetCode
Make and follow sheets.Sign in

Sum of Beauty of All Substrings solution and explanation

MediumCountingHash TableString6 min read74.9% acceptanceUpdated 9 Apr 2026
7. Sum of Beauty of All Substrings | Strings - Medium | Leetcode 1781 | Learn DSAAyushi Sharma · 16:11 · 30K viewsWatch on YouTube
9 more videos on this problem
  1. 7. Sum of Beauty of All Substrings | Strings - Medium | Leetcode 1781 | Learn DSAAyushi Sharma · 16:11 · 30K views
  2. LeetCode 1781. Sum of Beauty of All Substrings | Medium | Biweekly Contest 47 | Algorithm ExplainedCherry Coding [IIT-G] · 8:09 · 22K views
  3. 5682. Sum of Beauty of All SubstringsFraz · 12:16 · 20K views
  4. LeetCode 1781 Sum of Beauty of All Substrings | String Series | Striver A2Z DSA | Crack TCS InfosysTakla Coder · 14:02 · 2K views
  5. 1781. Sum of Beauty of All Substrings (Leetcode Medium)Programming Live with Larry · 8:24 · 1K views
  6. LeetCode 1781 - Sum of Beauty of All Substrings - JavaScript SolutionWeb Coder Abhishek · 5:13 · 1K views
  7. LeetCode 1781. [Medium] Sum of Beauty of All SubstringsFrancesco Manicardi · 4:30 · 498 views
  8. DAY 69/365 Sum of Beauty of All Substrings(Leetcode 1781)CODE with TRIVENI · 6:02 · 398 views
  9. Leetcode 1781 : Sum of Beauty of All Substrings | C++ #day11 #100daysofcodingchallengeDev Garg · 7:48 · 275 views
  10. Leetcode 1781. Sum of Beauty of All Substrings (Counter)LetsCode · 2:31 · 245 views

The problem

The beauty of a string is the difference in frequencies between the most frequent and least frequent characters.

  • For example, the beauty of "abaacc" is 3 - 1 = 2.

Given a string s, return the sum of beauty of all of its substrings.

Example 1:

Input: s = "aabcb"
Output: 5
Explanation: The substrings with non-zero beauty are ["aab","aabc","aabcb","abcb","bcb"], each with beauty equal to 1.

Example 2:

Input: s = "aabcbaa"
Output: 17

Constraints:

  • 1 <= s.length <= 500
  • s consists of only lowercase English letters.

Approach overview

Problem Overview: You receive a string s. For every substring, compute its beauty, defined as the difference between the highest character frequency and the lowest non‑zero frequency in that substring. The goal is to sum this beauty value across all possible substrings.

Approach 1: Brute Force Frequency Recalculation (O(n^3) time, O(1) space)

The most direct method enumerates every substring using two indices i and j. For each substring s[i..j], rebuild a frequency array for the 26 lowercase characters, then compute the maximum and minimum non‑zero counts. The beauty value (maxFreq - minFreq) is added to the total. Because you recompute character counts for each substring, the inner operation scans the substring again, producing roughly O(n^3) time. Space stays O(1) since the alphabet size is constant. This approach is simple but inefficient for larger strings.

Approach 2: Optimized Expansion with Running Frequency (O(n^2) time, O(1) space)

A better approach fixes the starting index i and expands the substring one character at a time. Maintain a frequency array of size 26 while extending j. Each step updates the count of s[j], then recomputes the current maximum and minimum non‑zero frequencies by scanning the 26-element array. Since the alphabet is fixed, this scan is constant time. The substring frequencies are reused instead of rebuilt, reducing complexity to O(n^2). This technique relies on efficient character counting using a small array or hash table, combined with incremental substring growth from the string.

Approach 3: Prefix Frequency Precomputation (O(n^2) time, O(26n) space)

You can also build prefix frequency arrays where prefix[i][c] stores how many times character c appears up to index i. For any substring s[l..r], compute each character’s frequency using prefix[r] - prefix[l-1]. After retrieving counts, determine the max and min non‑zero frequencies to calculate the beauty. This avoids maintaining a mutable array while iterating but still requires scanning all 26 characters per substring. The complexity remains O(n^2), with extra memory for prefix storage. It’s a clean approach when working heavily with counting queries across ranges.

Recommended for interviews: The incremental frequency expansion approach is the expected solution. It demonstrates understanding of substring enumeration while avoiding redundant recomputation. Interviewers usually accept O(n^2) because the alphabet is fixed and scanning 26 characters is effectively constant time. Showing the brute force method first proves you understand the definition of beauty, then optimizing with running counts shows practical problem‑solving skill.

Approach 1: Brute Force Approach

This approach involves generating all possible substrings of the input string and calculating the beauty of each substring. The beauty is determined by the frequency difference between the most common and least common character within the substring.

Although straightforward, this approach may be inefficient for larger strings due to the high number of substrings.

def beauty_sum(s: str) -> int:
    def calc_beauty(freq):
        max_freq = max(freq.values())
        min_freq = min(v for v in freq.values() if v > 0)
        return max_freq - min_freq
    
    total_beauty = 0
    n = len(s)
    for i in range(n):
        freq = {}
        for j in range(i, n):
            freq[s[j]] = freq.get(s[j], 0) + 1
            total_beauty += calc_beauty(freq)
    return total_beauty
#include <string>
#include <unordered_map>
#include <algorithm>

int beautySum(const std::string& s) {
    auto calc_beauty = [](const std::unordered_map<char, int>& freq) {
        int max_freq = 0, min_freq = INT_MAX;
        for (const auto& [char, count] : freq) {
            if (count > 0) {
                max_freq = std::max(max_freq, count);
                min_freq = std::min(min_freq, count);
            }
        }
        return max_freq - min_freq;
    };

    int total_beauty = 0;
    int n = s.length();
    for (int i = 0; i < n; ++i) {
        std::unordered_map<char, int> freq;
        for (int j = i; j < n; ++j) {
            freq[s[j]]++;
            total_beauty += calc_beauty(freq);
        }
    }
    return total_beauty;
}

The function beauty_sum iterates over all possible substrings of s. For each substring, it maintains a frequency dictionary that is updated as characters are added to the substring. The calc_beauty function computes the beauty of the current substring using the max and min frequencies. The accumulated beauty is the result.

Complexity

Time complexity: O(n^3), where n is the length of the string, as it involves generating all substrings and calculating frequencies.

Space complexity: O(1) - as the frequency dictionary size is bounded by the constant number of lowercase letters.

Try this approach in the editor

Approach 2: Optimized Approach Using Prefix Frequency

This approach reduces repetitive work in calculating frequencies by utilizing prefix frequency arrays that allow efficient substring frequency calculations. For each possible starting point of a substring, update and compute the necessary frequency values from earlier calculations.

def beauty_sum(s: str) -> int:
    from collections import Counter

    def calc_beauty(counter):
        max_freq = max(counter.values())
        min_freq = min(v for v in counter.values() if v > 0)
        return max_freq - min_freq

    n = len(s)
    total_beauty = 0
    prefix_freq = [Counter() for _ in range(n + 1)]
    
    for i in range(1, n + 1):
        prefix_freq[i] = prefix_freq[i - 1].copy()
        prefix_freq[i][s[i - 1]] += 1

    for i in range(n):
        for j in range(i + 1, n + 1):
            counter = Counter({k: prefix_freq[j][k] - prefix_freq[i][k] for k in prefix_freq[j]})
            total_beauty += calc_beauty(counter)

    return total_beauty
using System;
using System.Collections.Generic;

public class Solution {
    public int BeautySum(string s) {
        int n = s.Length;
        int totalBeauty = 0;
        var prefix = new Dictionary<char, int>[n + 1];
        prefix[0] = new Dictionary<char, int>();

        for (int i = 1; i <= n; i++) {
            prefix[i] = new Dictionary<char, int>(prefix[i - 1]);
            if (!prefix[i].ContainsKey(s[i - 1]))
                prefix[i][s[i - 1]] = 0;
            prefix[i][s[i - 1]]++;
        }

        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j <= n; j++) {
                var freq = new Dictionary<char, int>();
                foreach (var key in prefix[j].Keys) {
                    freq[key] = prefix[j][key] - prefix[i].GetValueOrDefault(key, 0);
                }
                int maxFreq = 0, minFreq = n;
                foreach (var count in freq.Values) {
                    if (count > 0) {
                        maxFreq = Math.Max(maxFreq, count);
                        minFreq = Math.Min(minFreq, count);
                    }
                }
                totalBeauty += (maxFreq - minFreq);
            }
        }

        return totalBeauty;
    }
}

This optimized Python solution uses a list of prefix frequency counters. Each counter at index i represents the frequency of characters from the start of the string up to but not including index i. Frequency differences within substrings are obtained using these prefix frequencies. This allows frequency calculation in constant time for each substring.

Complexity

Time complexity: O(n^2), where n is the length of the string, as it reduces redundant frequency calculations.

Space complexity: O(n), due to storage of prefix frequency data.

Try this approach in the editor

Approach 3: Enumeration + Counting

Enumerate the starting position i of each substring, find all substrings with the character at this starting position as the left endpoint, then calculate the beauty value of each substring, and accumulate it to the answer.

The time complexity is O(n^2 times C), and the space complexity is O(C). Here, n is the length of the string, and C is the size of the character set. In this problem, C = 26.

class Solution {
    public int beautySum(String s) {
        int ans = 0;
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            int[] cnt = new int[26];
            for (int j = i; j < n; ++j) {
                ++cnt[s.charAt(j) - 'a'];
                int mi = 1000, mx = 0;
                for (int v : cnt) {
                    if (v > 0) {
                        mi = Math.min(mi, v);
                        mx = Math.max(mx, v);
                    }
                }
                ans += mx - mi;
            }
        }
        return ans;
    }
}
/**
 * @param {string} s
 * @return {number}
 */
var beautySum = function (s) {
    let ans = 0;
    for (let i = 0; i < s.length; ++i) {
        const cnt = new Map();
        for (let j = i; j < s.length; ++j) {
            cnt.set(s[j], (cnt.get(s[j]) || 0) + 1);
            const t = Array.from(cnt.values());
            ans += Math.max(...t) - Math.min(...t);
        }
    }
    return ans;
};
function beautySum(s: string): number {
    let ans = 0;
    for (let i = 0; i < s.length; ++i) {
        const cnt = new Map();
        for (let j = i; j < s.length; ++j) {
            cnt.set(s[j], (cnt.get(s[j]) || 0) + 1);
            const t = Array.from(cnt.values());
            ans += Math.max(...t) - Math.min(...t);
        }
    }
    return ans;
}
func beautySum(s string) (ans int) {
	for i := range s {
		cnt := [26]int{}
		for j := i; j < len(s); j++ {
			cnt[s[j]-'a']++
			mi, mx := 1000, 0
			for _, v := range cnt {
				if v > 0 {
					if mi > v {
						mi = v
					}
					if mx < v {
						mx = v
					}
				}
			}
			ans += mx - mi
		}
	}
	return
}
impl Solution {
    pub fn beauty_sum(s: String) -> i32 {
        let mut ans = 0;
        let n = s.len();
        let s: Vec<char> = s.chars().collect();

        for i in 0..n {
            let mut cnt = vec![0; 26];
            for j in i..n {
                cnt[s[j] as usize - 'a' as usize] += 1;
                let mut mi = 1000;
                let mut mx = 0;
                for &v in &cnt {
                    if v > 0 {
                        mi = mi.min(v);
                        mx = mx.max(v);
                    }
                }
                ans += mx - mi;
            }
        }
        ans
    }
}
Try this approach in the editor

Approach 4: Default Approach

class Solution {
    public int beautySum(String s) {
        int n = s.length();
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            int[] cnt = new int[26];
            Map<Integer, Integer> freq = new HashMap<>();
            int mi = 1, mx = 1;
            for (int j = i; j < n; ++j) {
                int k = s.charAt(j) - 'a';
                freq.merge(cnt[k], -1, Integer::sum);
                ++cnt[k];
                freq.merge(cnt[k], 1, Integer::sum);

                if (cnt[k] == 1) {
                    mi = 1;
                }
                if (freq.getOrDefault(mi, 0) == 0) {
                    ++mi;
                }
                if (cnt[k] > mx) {
                    mx = cnt[k];
                }
                ans += mx - mi;
            }
        }
        return ans;
    }
}
/**
 * @param {string} s
 * @return {number}
 */
var beautySum = function (s) {
    const n = s.length;
    let ans = 0;
    for (let i = 0; i < n; ++i) {
        const cnt = Array(26).fill(0);
        const freq = new Map();
        let [mi, mx] = [1, 1];
        for (let j = i; j < n; ++j) {
            const k = s[j].charCodeAt() - 97;
            freq.set(cnt[k], (freq.get(cnt[k]) || 0) - 1);
            ++cnt[k];
            freq.set(cnt[k], (freq.get(cnt[k]) || 0) + 1);
            if (cnt[k] === 1) {
                mi = 1;
            }
            if (freq.get(mi) === 0) {
                ++mi;
            }
            if (cnt[k] > mx) {
                mx = cnt[k];
            }
            ans += mx - mi;
        }
    }
    return ans;
};
func beautySum(s string) (ans int) {
	n := len(s)
	for i := 0; i < n; i++ {
		cnt := [26]int{}
		freq := map[int]int{}
		mi, mx := 1, 1
		for j := i; j < n; j++ {
			k := int(s[j] - 'a')
			freq[cnt[k]]--
			cnt[k]++
			freq[cnt[k]]++

			if cnt[k] == 1 {
				mi = 1
			}
			if freq[mi] == 0 {
				mi++
			}
			if cnt[k] > mx {
				mx = cnt[k]
			}
			ans += mx - mi
		}
	}
	return
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Brute Force Approach

Time complexity: O(n^3), where n is the length of the string, as it involves generating all substrings and calculating frequencies.

Space complexity: O(1) - as the frequency dictionary size is bounded by the constant number of lowercase letters.

Optimized Approach Using Prefix Frequency

Time complexity: O(n^2), where n is the length of the string, as it reduces redundant frequency calculations.

Space complexity: O(n), due to storage of prefix frequency data.

Enumeration + Counting–
Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Brute Force Frequency RecalculationO(n^3)O(1)Useful for understanding the definition of beauty or during early problem exploration
Incremental Frequency ExpansionO(n^2)O(1)Best practical solution for interviews and competitive programming
Prefix Frequency ArraysO(n^2)O(26n)Helpful when multiple substring frequency queries are required

Frequently asked questions

Is Sum of Beauty of All Substrings easy or hard?

The problem is rated Medium because the definition of beauty is straightforward but naive implementations are inefficient. The challenge is recognizing that substring frequencies can be updated incrementally to reduce complexity from O(n^3) to O(n^2).

Sum of Beauty of All Substrings Python/Java solution

Python solutions usually use a list of size 26 to store character frequencies while expanding substrings. Java implementations typically use an int array for the same purpose. Both follow the O(n^2) expansion approach and recompute max and min frequencies after each extension.

How to solve Sum of Beauty of All Substrings in O(n)?

A true O(n) algorithm is not known for this problem because every substring potentially contributes a different beauty value. At minimum, substring boundaries must be explored, which leads to O(n^2) enumeration. The commonly accepted optimal approach therefore runs in O(n^2) time.

What is the best approach for Sum of Beauty of All Substrings?

The best practical approach fixes a starting index and expands the substring while maintaining a running frequency array of 26 characters. After each expansion, compute the max and min non‑zero frequencies to calculate the beauty. This reduces redundant work and runs in O(n^2) time with O(1) extra space.

Is Sum of Beauty of All Substrings asked at Google/Amazon/Meta?

This problem represents a common interview pattern involving substring enumeration and frequency counting. Variations of this pattern appear in interviews at companies such as Amazon, Google, and Meta where candidates must efficiently track character frequencies in strings.

What data structure is used in Sum of Beauty of All Substrings?

The main data structure is a frequency counter for characters, typically implemented as a fixed array of size 26 or a hash table. This structure tracks how many times each character appears in the current substring so the maximum and minimum frequencies can be computed.

What is the time complexity of Sum of Beauty of All Substrings?

The optimized solution runs in O(n^2) time because it evaluates every substring starting point and expands the end index while maintaining character counts. Each step scans a constant-size frequency array of 26 letters. Space complexity is O(1).

Comments

Now write it yourselfClose this page and solve Sum of Beauty of All Substrings in the editor, without looking.
Practise Sum of Beauty of All Substrings