# Solving Leetcode Interviews in Seconds with AI: Frequencies of Shortest Supersequences


	# Introduction
	In this blog post, we will explore how to solve the LeetCode problem "3435" using AI. LeetCode is a popular platform for preparing for coding interviews, and with the help of AI tools like [Chatmagic](https://www.chatmagic.app), we can generate solutions quickly and efficiently - helping you pass the interviews and get the job offer without having to study for months.

	# Problem Statement
	> You are given an array of strings words. Find all shortest common supersequences (SCS) of words that are not permutations of each other. A shortest common supersequence is a string of minimum length that contains each string in words as a subsequence. Return a 2D array of integers freqs that represent all the SCSs. Each freqs[i] is an array of size 26, representing the frequency of each letter in the lowercase English alphabet for a single SCS. You may return the frequency arrays in any order.   Example 1:  Input: words = ["ab","ba"] Output: [[1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]] Explanation: The two SCSs are "aba" and "bab". The output is the letter frequencies for each one.  Example 2:  Input: words = ["aa","ac"] Output: [[2,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]] Explanation: The two SCSs are "aac" and "aca". Since they are permutations of each other, keep only "aac".  Example 3:  Input: words = ["aa","bb","cc"] Output: [[2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]] Explanation: "aabbcc" and all its permutations are SCSs.    Constraints:  1 <= words.length <= 256 words[i].length == 2 All strings in words will altogether be composed of no more than 16 unique lowercase letters. All strings in words are unique.  

	# Explanation
	*   **Core Idea:** Dynamic programming is used to explore all possible supersequences. A bitmask is employed to track which words have been covered as subsequences. The DP state includes the last character added and the mask of covered words.
*   **Optimization:** The code avoids adding SCS permutations using the `check_permutation` function. It only adds frequencies if no existing frequency vector is a permutation of the current frequency vector.
*   **Frequency Counting:** Efficiently counts character frequencies for each SCS, creating a 26-element array for each.

*   **Runtime Complexity:** O(2<sup>n</sup> * m * L), where n is the number of words, m is the number of unique characters (up to 16), and L is the average length of the supersequences. Storage Complexity: O(2<sup>n</sup> * m).

```python
def solve():
    words = ["ab", "ba"]
    # words = ["aa", "ac"]
    # words = ["aa", "bb", "cc"]
    # words = ["abc", "bca", "cab"]
    # words = ["abcd", "bcda", "cdab", "dabc"]

    def find_scs_freqs(words):
        n = len(words)
        unique_chars = set()
        for word in words:
            unique_chars.update(set(word))
        unique_chars = sorted(list(unique_chars))
        char_to_index = {char: i for i, char in enumerate(unique_chars)}

        memo = {}  # (mask, last_char) -> (length, set of frequencies)

        def get_freq(s):
            freq = [0] * 26
            for char in s:
                freq[ord(char) - ord('a')] += 1
            return freq
            
        def check_permutation(freq1, freq2):
            return sorted(freq1) == sorted(freq2)

        def dp(mask, last_char):
            if mask == (1 << n) - 1:
                return 0, {tuple()}  # Base case: all words are subsequences

            if (mask, last_char) in memo:
                return memo[(mask, last_char)]

            min_len = float('inf')
            freqs = set()

            for char in unique_chars:
                new_mask = mask
                for i in range(n):
                    if (mask >> i) & 1 == 0:  # If word i is not yet a subsequence
                        if char in words[i] and is_subsequence_after_char(char, words[i], last_char):
                            new_mask |= (1 << i)

                len_without_char, freqs_without_char = dp(new_mask, char)
                curr_len = len_without_char + 1

                if curr_len < min_len:
                    min_len = curr_len
                    freqs = set()
                    for freq_tuple in freqs_without_char:
                        new_freq = [0] * 26
                        if len(freq_tuple) != 0:
                          new_freq = list(freq_tuple)
                        new_freq[ord(char) - ord('a')] += 1

                        is_permutation_present = False
                        for existing_freq in freqs:
                            if check_permutation(new_freq, list(existing_freq)):
                                is_permutation_present = True
                                break

                        if not is_permutation_present:
                          freqs.add(tuple(new_freq))


                elif curr_len == min_len:
                     for freq_tuple in freqs_without_char:
                        new_freq = [0] * 26
                        if len(freq_tuple) != 0:
                          new_freq = list(freq_tuple)
                        new_freq[ord(char) - ord('a')] += 1

                        is_permutation_present = False
                        for existing_freq in freqs:
                            if check_permutation(new_freq, list(existing_freq)):
                                is_permutation_present = True
                                break
                        if not is_permutation_present:
                          freqs.add(tuple(new_freq))

            memo[(mask, last_char)] = (min_len, freqs)
            return min_len, freqs

        def is_subsequence_after_char(char, word, last_char):
            if last_char is None:
                return True
            last_char_index = -1
            for i, c in enumerate(word):
                if c == last_char:
                    last_char_index = i
            if last_char_index == -1:
                return True
            for i in range(last_char_index + 1, len(word)):
                if word[i] == char:
                    return True
            return False
            

        _, all_freqs = dp(0, None)
        result = [list(freq) for freq in all_freqs]

        return result

    result = find_scs_freqs(words)
    print(result)

	
	# Code
	```python
	def solve():    words = ["ab", "ba"]
    # words = ["aa", "ac"]
    # words = ["aa", "bb", "cc"]
    # words = ["abc", "bca", "cab"]
    # words = ["abcd", "bcda", "cdab", "dabc"]

    def find_scs_freqs(words):
        n = len(words)
        unique_chars = set()
        for word in words:
            unique_chars.update(set(word))
        unique_chars = sorted(list(unique_chars))
        char_to_index = {char: i for i, char in enumerate(unique_chars)}

        memo = {}  # (mask, last_char) -> (length, set of frequencies)

        def get_freq(s):
            freq = [0] * 26
            for char in s:
                freq[ord(char) - ord('a')] += 1
            return freq
            
        def check_permutation(freq1, freq2):
            return sorted(freq1) == sorted(freq2)

        def dp(mask, last_char):
            if mask == (1 << n) - 1:
                return 0, {tuple()}  # Base case: all words are subsequences

            if (mask, last_char) in memo:
                return memo[(mask, last_char)]

            min_len = float('inf')
            freqs = set()

            for char in unique_chars:
                new_mask = mask
                for i in range(n):
                    if (mask >> i) & 1 == 0:  # If word i is not yet a subsequence
                        if char in words[i] and is_subsequence_after_char(char, words[i], last_char):
                            new_mask |= (1 << i)

                len_without_char, freqs_without_char = dp(new_mask, char)
                curr_len = len_without_char + 1

                if curr_len < min_len:
                    min_len = curr_len
                    freqs = set()
                    for freq_tuple in freqs_without_char:
                        new_freq = [0] * 26
                        if len(freq_tuple) != 0:
                          new_freq = list(freq_tuple)
                        new_freq[ord(char) - ord('a')] += 1

                        is_permutation_present = False
                        for existing_freq in freqs:
                            if check_permutation(new_freq, list(existing_freq)):
                                is_permutation_present = True
                                break

                        if not is_permutation_present:
                          freqs.add(tuple(new_freq))


                elif curr_len == min_len:
                     for freq_tuple in freqs_without_char:
                        new_freq = [0] * 26
                        if len(freq_tuple) != 0:
                          new_freq = list(freq_tuple)
                        new_freq[ord(char) - ord('a')] += 1

                        is_permutation_present = False
                        for existing_freq in freqs:
                            if check_permutation(new_freq, list(existing_freq)):
                                is_permutation_present = True
                                break
                        if not is_permutation_present:
                          freqs.add(tuple(new_freq))

            memo[(mask, last_char)] = (min_len, freqs)
            return min_len, freqs

        def is_subsequence_after_char(char, word, last_char):
            if last_char is None:
                return True
            last_char_index = -1
            for i, c in enumerate(word):
                if c == last_char:
                    last_char_index = i
            if last_char_index == -1:
                return True
            for i in range(last_char_index + 1, len(word)):
                if word[i] == char:
                    return True
            return False
            

        _, all_freqs = dp(0, None)
        result = [list(freq) for freq in all_freqs]

        return result

    result = find_scs_freqs(words)
    print(result)
	```
			
