ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

Find All Anagrams in a String

SQL PostgreSQL

Goal -- WPM

Ready
Exercise Algorithm Area
1CREATE OR REPLACE FUNCTION find_all_anagrams(s TEXT, p TEXT)
2RETURNS SETOF INTEGER
3AS $$
4DECLARE
5s_len INT := LENGTH(s);
6p_len INT := LENGTH(p);
7s_chars INT[26]; -- Frequency map for characters in s (window)
8p_chars INT[26]; -- Frequency map for characters in p (pattern)
9i INT;
10start_index INT;
11end_index INT;
12char_code INT;
13result_indices INT[];
14BEGIN
15-- Handle edge cases: if pattern is longer than string, no anagrams possible.
16IF p_len > s_len THEN
17RETURN NEXT;
18END IF;
19
20-- Initialize frequency maps for pattern and the first window of string.
21-- Assuming lowercase English letters 'a' through 'z'.
22FOR i IN 1..26 LOOP
23s_chars[i] := 0;
24p_chars[i] := 0;
25END LOOP;
26
27-- Populate frequency map for the pattern string 'p'.
28FOR i IN 1..p_len LOOP
29char_code := ASCII(SUBSTRING(p FROM i FOR 1)) - ASCII('a') + 1;
30IF char_code >= 1 AND char_code <= 26 THEN
31p_chars[char_code] := p_chars[char_code] + 1;
32END IF;
33END LOOP;
34
35-- Populate frequency map for the first window of string 's'.
36FOR i IN 1..p_len LOOP
37char_code := ASCII(SUBSTRING(s FROM i FOR 1)) - ASCII('a') + 1;
38IF char_code >= 1 AND char_code <= 26 THEN
39s_chars[char_code] := s_chars[char_code] + 1;
40END IF;
41END LOOP;
42
43-- Check if the first window is an anagram.
44IF s_chars = p_chars THEN
45result_indices := array_append(result_indices, 1);
46END IF;
47
48-- Slide the window across the string 's'.
49start_index := 2;
50end_index := p_len + 1;
51
52WHILE end_index <= s_len LOOP
53-- Add the new character entering the window.
54char_code := ASCII(SUBSTRING(s FROM end_index FOR 1)) - ASCII('a') + 1;
55IF char_code >= 1 AND char_code <= 26 THEN
56s_chars[char_code] := s_chars[char_code] + 1;
57END IF;
58
59-- Remove the character leaving the window.
60char_code := ASCII(SUBSTRING(s FROM start_index - 1 FOR 1)) - ASCII('a') + 1;
61IF char_code >= 1 AND char_code <= 26 THEN
62s_chars[char_code] := s_chars[char_code] - 1;
63END IF;
64
65-- Check if the current window is an anagram.
66IF s_chars = p_chars THEN
67result_indices := array_append(result_indices, start_index);
68END IF;
69
70-- Move the window forward.
71start_index := start_index + 1;
72end_index := end_index + 1;
73END LOOP;
74
75-- Return all found indices.
76RETURN QUERY SELECT UNNEST(result_indices);
77END;
78$$ LANGUAGE plpgsql;
Algorithm description viewbox

Find All Anagrams in a String

Algorithm description:

This PostgreSQL function, `find_all_anagrams`, efficiently finds all starting indices of substrings in a larger string (`s`) that are anagrams of a given pattern string (`p`). It employs a sliding window approach, maintaining character frequency counts for both the pattern and the current window in `s`. This is a common problem in string manipulation and pattern matching, with applications in text analysis, bioinformatics, and code searching.

Algorithm explanation:

The algorithm uses two frequency maps (arrays of size 26 for lowercase English letters) to store character counts: one for the pattern `p` (`p_chars`) and one for the current sliding window in `s` (`s_chars`). The time complexity is O(N), where N is the length of string `s`, because we iterate through `s` once to slide the window. The space complexity is O(1) as the frequency maps have a fixed size (26), independent of the input string lengths. Edge cases like `p` being longer than `s` are handled. The core logic involves updating `s_chars` by adding the new character entering the window and subtracting the character leaving, then comparing `s_chars` with `p_chars` at each step. The invariant maintained is that `s_chars` always reflects the character counts of the current window of size `p_len` starting at `start_index`.

Pseudocode:

FUNCTION find_all_anagrams(s, p):
  IF length(p) > length(s) THEN
    RETURN empty list
  END IF

  CREATE frequency map `p_chars` for pattern p.
  CREATE frequency map `s_chars` for the first window of s (size length(p)).
  CREATE an empty list `result_indices`.

  IF `s_chars` equals `p_chars` THEN
    ADD 1 to `result_indices`.
  END IF

  FOR `i` from 2 to length(s) - length(p) + 1:
    ADD character `s[i + length(p) - 1]` to `s_chars`.
    REMOVE character `s[i - 1]` from `s_chars`.
    IF `s_chars` equals `p_chars` THEN
      ADD `i` to `result_indices`.
    END IF
  END FOR

  RETURN `result_indices`.