Easy to understand solution in Java using sliding window.
ApproachWe maintain two pointers, left and right, to represent the sliding window's boundaries. left starts at 0, and right moves from 0 to the end of the strin
# Approach
We maintain two pointers, left and right, to represent the sliding window's boundaries. left starts at 0, and right moves from 0 to the end of the string.

We use a HashMap freq to track the frequency of characters in the current window. As right moves to the next character, we update the frequency of that character in the map.

**The key idea is that a window is valid if at least one character in the window appears at least k times. We use the helper function isValidWindow() to check if the window is valid based on the frequencies in the freq map.**

**For each valid window (when isValidWindow() returns true), all substrings from left to right, left to right+1, ..., left to n-1 are valid. We add (n - right) to the count of valid substrings because all those substrings starting from left and ending at positions right to n-1 are valid.**

After counting valid substrings, we move the left pointer forward to explore new possible windows, decreasing the frequency of the character at left.

This process continues until right reaches the end of the string. Finally, the count will store the total number of valid substrings.
 

- Time complexity:
O(n)

- Space complexity:
O(1)

# Code
```java []
class Solution {
    public int numberOfSubstrings(String s, int k) {
        int n = s.length();
        if (n < k) {
            return 0;
        }

        Map<Character, Integer> freq = new HashMap<>();
        int left = 0;
        int count = 0;

        for (int right = 0; right < n; right++) {
            char rightChar = s.charAt(right);
            freq.put(rightChar, freq.getOrDefault(rightChar, 0) + 1);

            while (isValidWindow(freq, k)) {
                count += (n - right);

                char leftChar = s.charAt(left);
                freq.put(leftChar, freq.get(leftChar) - 1);
                if (freq.get(leftChar) == 0) {
                    freq.remove(leftChar);
                }
                left++;
            }
        }
        return count;
    }

    private boolean isValidWindow(Map<Character, Integer> freq, int k) {
        for (int count : freq.values()) {
            if (count >= k) {
                return true;
            }
        }
        return false;
    }
}
```
['Java']