Number Squares

Last Updated : 18 Jul, 2026

Given an array arr[] of n unique numeric strings, all of the same length, find all possible arrangements of these strings that form a number square. Strings from the list can be reused any number of times within a square. A number square is a special grid, where every row reads the same as the corresponding column. Return all valid arrangements in any order, but the order of strings within each arrangement matters.

Examples:

Input: arr[] = ["221", "211", "212", "121"]
Output: [["121", "212", "121"], ["212", "121", "211"], ["212", "121", "212"], ["221", "212", "121"]]
Explanation: There are 4 valid arrangements. For example in ["221", "212", "121"] -> row 0 = "221", col 0 = "221", row 1 = "212", col 1 = "212", row 2 = "121", col 2 = "121".

8


Input: arr[] = ["1111", "1222"]
Output: [["1111", "1111", "1111", "1111"], ["1111", "1222", "1222", "1222"]]
Explanation: There are 2 valid arrangements. In ["1111", "1222", "1222", "1222"] - row 0 = "1111", col 0 = "1111", rows 1-3 = "1222", cols 1-3 = "1222".

9

[Naive Approach] Generate All Possible Arrangements and Validate - O(n ^ L * L ^ 2) Time and O(L) Space

The idea is to generate every possible arrangement of L strings using recursion. For each completed arrangement, check whether every row matches its corresponding column. If it does, store the arrangement as a valid number square.

Working of Approach:

  • Generate all possible arrangements of L rows by choosing any string from arr for each row using recursion.
  • After forming a complete square, check whether every row is equal to its corresponding column.
  • If the condition is satisfied, store the arrangement in the result list.
  • Finally, return all valid number square arrangements.
C++
#include <iostream>
#include <vector>
#include <string>
using namespace std;

vector<vector<string>> res;
int len;

// Check whether current arrangement is a valid number square.
bool isValid(vector<string> &curr)
{

    for (int i = 0; i < len; i++)
    {
        for (int j = 0; j < len; j++)
        {

            if (curr[i][j] != curr[j][i])
                return false;
        }
    }

    return true;
}

// Generate all possible arrangements.
void solve(vector<string> &arr, vector<string> &curr, int row)
{

    if (row == len)
    {

        if (isValid(curr))
            res.push_back(curr);

        return;
    }

    // Try every string for the current row.
    for (string &s : arr)
    {
        curr.push_back(s);
        solve(arr, curr, row + 1);
        curr.pop_back();
    }
}

vector<vector<string>> numberSquares(vector<string> &arr)
{

    len = arr[0].size();

    vector<string> curr;
    solve(arr, curr, 0);

    return res;
}

int main()
{

    vector<string> arr = {"1111", "1222"};

    vector<vector<string>> res = numberSquares(arr);

    cout << "[";

    for (int i = 0; i < res.size(); i++)
    {

        cout << "[";

        for (int j = 0; j < res[i].size(); j++)
        {

            cout << "\"" << res[i][j] << "\"";

            if (j != res[i].size() - 1)
                cout << ", ";
        }

        cout << "]";

        if (i != res.size() - 1)
            cout << ", ";
    }

    cout << "]";

    return 0;
}
Java
import java.util.*;

class GFG {

    static ArrayList<ArrayList<String>> res = new ArrayList<>();
    static int len;

    // Check whether current arrangement is a valid number square.
    static boolean isValid(ArrayList<String> curr) {

        for (int i = 0; i < len; i++) {
            for (int j = 0; j < len; j++) {

                if (curr.get(i).charAt(j) != curr.get(j).charAt(i))
                    return false;
            }
        }

        return true;
    }

    // Generate all possible arrangements.
    static void solve(String[] arr, ArrayList<String> curr, int row) {

        if (row == len) {

            if (isValid(curr))
                res.add(new ArrayList<>(curr));

            return;
        }

        // Try every string for the current row.
        for (String s : arr) {
            curr.add(s);
            solve(arr, curr, row + 1);
            curr.remove(curr.size() - 1);
        }
    }

    public static ArrayList<ArrayList<String>> numberSquares(String[] arr) {

        res.clear();

        len = arr[0].length();

        ArrayList<String> curr = new ArrayList<>();

        solve(arr, curr, 0);

        return res;
    }

    public static void main(String[] args) {

        String[] arr = { "1111", "1222" };

        ArrayList<ArrayList<String>> res = numberSquares(arr);

        System.out.print("[");

        for (int i = 0; i < res.size(); i++) {

            System.out.print("[");

            for (int j = 0; j < res.get(i).size(); j++) {

                System.out.print("\"" + res.get(i).get(j) + "\"");

                if (j != res.get(i).size() - 1)
                    System.out.print(", ");
            }

            System.out.print("]");

            if (i != res.size() - 1)
                System.out.print(", ");
        }

        System.out.print("]");
    }
}
Python
# Python Program to generate all possible arrangements
# and validate each arrangement as a number square.
res = []
length = 0

# Check whether current arrangement is a valid number square.
def isValid(curr):
    for i in range(length):
        for j in range(length):

            if curr[i][j] != curr[j][i]:
                return False

    return True

# Generate all possible arrangements.
def solve(arr, curr, row):

    if row == length:

        if isValid(curr):
            res.append(curr.copy())

        return

    # Try every string for the current row.
    for s in arr:
        curr.append(s)
        solve(arr, curr, row + 1)
        curr.pop()


def numberSquares(arr):

    global length, res

    res = []
    length = len(arr[0])

    curr = []

    solve(arr, curr, 0)

    return res


if __name__ == "__main__":

    arr = ["1111", "1222"]

    res = numberSquares(arr)

    print("[", end="")

    for i in range(len(res)):

        print("[", end="")

        for j in range(len(res[i])):

            print("\"" + res[i][j] + "\"", end="")

            if j != len(res[i]) - 1:
                print(", ", end="")

        print("]", end="")

        if i != len(res) - 1:
            print(", ", end="")

    print("]")
C#
using System;
using System.Collections.Generic;

class GFG {

    static List<List<string> > res
        = new List<List<string> >();
    static int len;

    // Check whether current arrangement is a valid number
    // square.
    static bool isValid(List<string> curr)
    {

        for (int i = 0; i < len; i++) {
            for (int j = 0; j < len; j++) {

                if (curr[i][j] != curr[j][i])
                    return false;
            }
        }

        return true;
    }

    // Generate all possible arrangements.
    static void solve(string[] arr, List<string> curr,
                      int row)
    {

        if (row == len) {

            if (isValid(curr))
                res.Add(new List<string>(curr));

            return;
        }

        // Try every string for the current row.
        foreach(string s in arr)
        {

            curr.Add(s);
            solve(arr, curr, row + 1);
            curr.RemoveAt(curr.Count - 1);
        }
    }

    public List<List<string>> numberSquares(string[] arr)
    {

        res.Clear();

        len = arr[0].Length;

        List<string> curr = new List<string>();

        solve(arr, curr, 0);

        return res;
    }

    public static void Main()
    {

        string[] arr = { "1111", "1222" };

        GFG obj = new GFG();
        List<List<string>> res = obj.numberSquares(arr);

        Console.Write("[");

        for (int i = 0; i < res.Count; i++) {

            Console.Write("[");

            for (int j = 0; j < res[i].Count; j++) {

                Console.Write("\"" + res[i][j] + "\"");

                if (j != res[i].Count - 1)
                    Console.Write(", ");
            }

            Console.Write("]");

            if (i != res.Count - 1)
                Console.Write(", ");
        }

        Console.Write("]");
    }
}
JavaScript
let res = [];
let len = 0;

// Check whether current arrangement is a valid number
// square.
function isValid(curr)
{

    for (let i = 0; i < len; i++) {
        for (let j = 0; j < len; j++) {

            if (curr[i][j] !== curr[j][i])
                return false;
        }
    }

    return true;
}

// Generate all possible arrangements.
function solve(arr, curr, row)
{

    if (row === len) {

        if (isValid(curr))
            res.push([...curr ]);

        return;
    }

    // Try every string for the current row.
    for (let s of arr) {
        curr.push(s);
        solve(arr, curr, row + 1);
        curr.pop();
    }
}

function numberSquares(arr)
{

    len = arr[0].length;
    res = [];
    let curr = [];
    solve(arr, curr, 0);

    return res;
}

// Driver Code
let arr = [ "1111", "1222" ];
let result = numberSquares(arr);
console.log(JSON.stringify(result));

Output
[["1111", "1111", "1111", "1111"], ["1111", "1222", "1222", "1222"]]

Time Complexity: O(n ^ L × L ^ 2) - Generates all possible arrangements and validates each square by comparing rows and columns.
Space Complexity: O(L) - Stores the current arrangement during recursion.

[Better Approach] Using Hash Map with Backtracking - O(n * L + Ans × L ^ 2) Time and O(n * L) Space

The idea is to store all prefixes of every string in a hash map. While building the square row by row, construct the required prefix for the next row and retrieve only the strings having that prefix. This prunes invalid choices early and generates only valid number squares.

Working of Approach:

  • Store every prefix of each string in a hash map, where each prefix maps to possible strings having that prefix.
  • During backtracking, build the required prefix for the next row using the already selected rows.
  • Retrieve only matching strings from the hash map and recursively build the remaining rows.
  • When L rows are selected, add the valid number square to the result.
C++
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
using namespace std;

unordered_map<string, vector<string>> mp;
vector<vector<string>> res;
int len;

// Generate all possible number squares.
void backtrack(vector<string> &curr, int row)
{

    // A valid number square is formed.
    if (row == len)
    {
        res.push_back(curr);
        return;
    }

    // Build the required prefix for the current row.
    string prefix = "";
    for (int i = 0; i < row; i++)
        prefix += curr[i][row];

    // Try all strings having the required prefix.
    for (string &s : mp[prefix])
    {
        curr.push_back(s);
        backtrack(curr, row + 1);
        curr.pop_back();
    }
}

vector<vector<string>> numberSquares(vector<string> &arr)
{

    len = arr[0].size();

    // Store every prefix of every string.
    for (string &s : arr)
    {
        for (int i = 0; i <= len; i++)
            mp[s.substr(0, i)].push_back(s);
    }

    vector<string> curr;

    // Try every string as the first row.
    for (string &s : arr)
    {
        curr.push_back(s);
        backtrack(curr, 1);
        curr.pop_back();
    }

    return res;
}

int main()
{

    vector<string> arr = {"1111", "1222"};

    vector<vector<string>> res = numberSquares(arr);

    cout << "[";

    for (int i = 0; i < res.size(); i++)
    {

        cout << "[";

        for (int j = 0; j < res[i].size(); j++)
        {

            cout << "\"" << res[i][j] << "\"";

            if (j != res[i].size() - 1)
                cout << ", ";
        }

        cout << "]";

        if (i != res.size() - 1)
            cout << ", ";
    }

    cout << "]";

    return 0;
}
Java
import java.util.*;

class GFG {

    static HashMap<String, ArrayList<String> > mp
        = new HashMap<>();
    static ArrayList<ArrayList<String> > res
        = new ArrayList<>();
    static int len;

    // Generate all possible number squares.
    static void backtrack(ArrayList<String> curr, int row)
    {

        // A valid number square is formed.
        if (row == len) {
            res.add(new ArrayList<>(curr));
            return;
        }

        // Build the required prefix for the current row.
        String prefix = "";
        for (int i = 0; i < row; i++)
            prefix += curr.get(i).charAt(row);

        // Try all strings having the required prefix.
        for (String s :
             mp.getOrDefault(prefix, new ArrayList<>())) {

            curr.add(s);
            backtrack(curr, row + 1);
            curr.remove(curr.size() - 1);
        }
    }

    static ArrayList<ArrayList<String> >
        numberSquares(String[] arr)
    {
        mp.clear();
        res.clear();

        len = arr[0].length();

        // Store every prefix of every string.
        for (String s : arr) {

            for (int i = 0; i <= len; i++) {

                String prefix = s.substring(0, i);

                mp.putIfAbsent(prefix, new ArrayList<>());
                mp.get(prefix).add(s);
            }
        }

        ArrayList<String> curr = new ArrayList<>();

        // Try every string as the first row.
        for (String s : arr) {

            curr.add(s);
            backtrack(curr, 1);
            curr.remove(curr.size() - 1);
        }

        return res;
    }

    // Driver Code
    public static void main(String[] args)
    {

        String[] arr = { "1111", "1222" };

        ArrayList<ArrayList<String> > result
            = numberSquares(arr);

        System.out.print("[");

        for (int i = 0; i < result.size(); i++) {

            System.out.print("[");

            for (int j = 0; j < result.get(i).size(); j++) {

                System.out.print("\"" + result.get(i).get(j)
                                 + "\"");

                if (j != result.get(i).size() - 1)
                    System.out.print(", ");
            }

            System.out.print("]");

            if (i != result.size() - 1)
                System.out.print(", ");
        }

        System.out.print("]");
    }
}
Python
# Python Program to generate number squares
# using Hash Map and Backtracking.
mp = {}
res = []
length = 0

# Generate all possible number squares.


def backtrack(curr, row):

    global length

    # A valid number square is formed.
    if row == length:
        res.append(curr.copy())
        return

    # Build the required prefix for the current row.
    prefix = ""

    for i in range(row):
        prefix += curr[i][row]

    # Try all strings having the required prefix.
    for s in mp.get(prefix, []):

        curr.append(s)
        backtrack(curr, row + 1)
        curr.pop()


def numberSquares(arr):

    global length, mp, res

    mp = {}
    res = []

    length = len(arr[0])

    # Store every prefix of every string.
    for s in arr:

        for i in range(length + 1):

            prefix = s[:i]

            if prefix not in mp:
                mp[prefix] = []

            mp[prefix].append(s)

    curr = []

    # Try every string as the first row.
    for s in arr:

        curr.append(s)
        backtrack(curr, 1)
        curr.pop()

    return res


if __name__ == "__main__":

    arr = ["1111", "1222"]

    result = numberSquares(arr)

    print("[", end="")

    for i in range(len(result)):

        print("[", end="")

        for j in range(len(result[i])):

            print("\"" + result[i][j] + "\"", end="")

            if j != len(result[i]) - 1:
                print(", ", end="")

        print("]", end="")

        if i != len(result) - 1:
            print(", ", end="")

    print("]")
C#
using System;
using System.Collections.Generic;

class GFG {

    static Dictionary<string, List<string> > mp
        = new Dictionary<string, List<string> >();
    static List<List<string> > res
        = new List<List<string> >();
    static int len;

    // Generate all possible number squares.
    static void backtrack(List<string> curr, int row)
    {

        // A valid number square is formed.
        if (row == len) {

            res.Add(new List<string>(curr));
            return;
        }

        // Build the required prefix for the current row.
        string prefix = "";

        for (int i = 0; i < row; i++)
            prefix += curr[i][row];

        // Try all strings having the required prefix.
        if (mp.ContainsKey(prefix)) {

            foreach(string s in mp[prefix])
            {

                curr.Add(s);
                backtrack(curr, row + 1);
                curr.RemoveAt(curr.Count - 1);
            }
        }
    }

    static List<List<string>> numberSquares(string[] arr)
    {
        mp.Clear();
        res.Clear();

        len = arr[0].Length;

        // Store every prefix of every string.
        foreach(string s in arr)
        {

            for (int i = 0; i <= len; i++) {

                string prefix = s.Substring(0, i);

                if (!mp.ContainsKey(prefix))
                    mp[prefix] = new List<string>();

                mp[prefix].Add(s);
            }
        }

        List<string> curr = new List<string>();

        // Try every string as the first row.
        foreach(string s in arr)
        {

            curr.Add(s);
            backtrack(curr, 1);
            curr.RemoveAt(curr.Count - 1);
        }

        return res;
    }

    // Driver Code
    public static void Main()
    {

        string[] arr = { "1111", "1222" };

        List<List<string> > result = numberSquares(arr);

        Console.Write("[");

        for (int i = 0; i < result.Count; i++) {

            Console.Write("[");

            for (int j = 0; j < result[i].Count; j++) {

                Console.Write("\"" + result[i][j] + "\"");

                if (j != result[i].Count - 1)
                    Console.Write(", ");
            }

            Console.Write("]");

            if (i != result.Count - 1)
                Console.Write(", ");
        }

        Console.Write("]");
    }
}
JavaScript
// JavaScript Program to generate number squares
// using Hash Map and Backtracking.

let mp = new Map();
let res = [];
let len = 0;

// Generate all possible number squares.
function backtrack(curr, row)
{

    // A valid number square is formed.
    if (row == len) {
        res.push([...curr ]);
        return;
    }

    // Build the required prefix for the current row.
    let prefix = "";

    for (let i = 0; i < row; i++)
        prefix += curr[i][row];

    // Try all strings having the required prefix.
    if (mp.has(prefix)) {

        for (let s of mp.get(prefix)) {

            curr.push(s);
            backtrack(curr, row + 1);
            curr.pop();
        }
    }
}

function numberSquares(arr)
{

    mp = new Map();
    res = [];

    len = arr[0].length;

    // Store every prefix of every string.
    for (let s of arr) {

        for (let i = 0; i <= len; i++) {

            let prefix = s.substring(0, i);

            if (!mp.has(prefix))
                mp.set(prefix, []);

            mp.get(prefix).push(s);
        }
    }

    let curr = [];

    // Try every string as the first row.
    for (let s of arr) {

        curr.push(s);
        backtrack(curr, 1);
        curr.pop();
    }

    return res;
}

// Driver Code
let arr = [ "1111", "1222" ];
let result = numberSquares(arr);
console.log(JSON.stringify(result));

Output
[["1111", "1111", "1111", "1111"], ["1111", "1222", "1222", "1222"]]

Time Complexity: O(n × L + Ans × L ^ 2) - Stores all prefixes and explores only strings matching the required prefix while forming valid squares.
Space Complexity: O(n × L) - Stores prefixes of all strings in the hash map.

[Expected Approach] Using Trie with Backtracking - O(n * L + Ans * L ^ 2) Time and O(n * L) Space

The idea is to insert all strings into a Trie, where every node stores the strings sharing its prefix. During backtracking, build the required prefix for the next row and use the Trie to directly retrieve only the matching strings. This efficiently prunes invalid choices while generating all valid number squares.

Working of Approach:

  • First, insert all strings into the Trie and store each string at every Trie node along its prefix path.
  • Start backtracking by selecting each string as the first row of the number square.
  • For the next row, build the required prefix using characters from the already selected rows and search matching strings in the Trie.
  • Recursively add valid strings having the required prefix until the square size is reached.
  • When all rows are selected, store the formed arrangement as a valid number square.

Let us understand with an example:
Input: arr[] = ["1111", "1222"]

  • Insert all strings into the Trie. For each prefix, store the strings having that prefix.
  • Choose "1111" as the first row. Required prefix for the next row is "1", so Trie returns {"1111", "1222"}.
  • Choose "1111" again repeatedly to form ["1111","1111","1111","1111"], which satisfies row-column conditions and is stored.
  • Backtracking tries "1222" for the next rows, forming ["1111","1222","1222","1222"], which is also a valid number square.
  • All possible valid arrangements are generated and returned as the final result.

Output: [["1111","1111","1111","1111"],["1111","1222","1222","1222"]].

C++
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

struct TrieNode
{
    TrieNode *children[10];
    vector<string> words;

    TrieNode()
    {
        fill(children, children + 10, nullptr);
    }
};

TrieNode *root;

void insert(string &word)
{
    TrieNode *node = root;
    for (char ch : word)
    {
        int idx = ch - '0';
        if (!node->children[idx])
            node->children[idx] = new TrieNode();
        node = node->children[idx];

        // Store string at every node along its path
        node->words.push_back(word);
    }
}

vector<string> getStringsWithPrefix(string &prefix)
{
    TrieNode *node = root;
    for (char ch : prefix)
    {
        int idx = ch - '0';
        if (!node->children[idx])
            return {};
        node = node->children[idx];
    }
    return node->words;
}

void backtrack(vector<string> &sq, int len, vector<vector<string>> &res)
{
    if (sq.size() == len)
    {
        res.push_back(sq);
        return;
    }

    int idx = sq.size();

    // Build required prefix for next string
    string prefix = "";
    for (int i = 0; i < idx; i++)
        prefix += sq[i][idx];

    for (string &s : getStringsWithPrefix(prefix))
    {
        sq.push_back(s);
        backtrack(sq, len, res);
        sq.pop_back();
    }
}

vector<vector<string>> numberSquares(vector<string> &arr)
{
    root = new TrieNode();
    int len = arr[0].size();

    // Build trie with all strings
    for (string &s : arr)
        insert(s);

    vector<vector<string>> res;
    vector<string> sq;

    for (string &s : arr)
    {
        sq.push_back(s);
        backtrack(sq, len, res);
        sq.pop_back();
    }

    return res;
}

int main()
{

    vector<string> arr = {"1111", "1222"};

    vector<vector<string>> res = numberSquares(arr);

    cout << "[";

    for (int i = 0; i < res.size(); i++)
    {

        cout << "[";

        for (int j = 0; j < res[i].size(); j++)
        {

            cout << "\"" << res[i][j] << "\"";

            if (j != res[i].size() - 1)
                cout << ", ";
        }

        cout << "]";

        if (i != res.size() - 1)
            cout << ", ";
    }

    cout << "]";

    return 0;
}
Java
import java.util.*;

class GFG {

    static class TrieNode {
        TrieNode[] children = new TrieNode[10];
        ArrayList<String> words = new ArrayList<>();
    }

    static TrieNode root;

    static void insert(String word)
    {

        TrieNode node = root;

        for (char ch : word.toCharArray()) {

            int idx = ch - '0';

            if (node.children[idx] == null)
                node.children[idx] = new TrieNode();

            node = node.children[idx];

            // Store string at every node along its path
            node.words.add(word);
        }
    }

    static ArrayList<String>
    getStringsWithPrefix(String prefix)
    {

        TrieNode node = root;

        for (char ch : prefix.toCharArray()) {

            int idx = ch - '0';

            if (node.children[idx] == null)
                return new ArrayList<>();

            node = node.children[idx];
        }

        return node.words;
    }

    static void backtrack(ArrayList<String> sq, int len,
                          ArrayList<ArrayList<String> > res)
    {

        if (sq.size() == len) {

            res.add(new ArrayList<>(sq));
            return;
        }

        int idx = sq.size();

        // Build required prefix for next string
        String prefix = "";

        for (int i = 0; i < idx; i++)
            prefix += sq.get(i).charAt(idx);

        for (String s : getStringsWithPrefix(prefix)) {

            sq.add(s);
            backtrack(sq, len, res);
            sq.remove(sq.size() - 1);
        }
    }

    static ArrayList<ArrayList<String> >
        numberSquares(String[] arr)
    {

        root = new TrieNode();

        int len = arr[0].length();

        // Build trie with all strings
        for (String s : arr)
            insert(s);

        ArrayList<ArrayList<String> > res
            = new ArrayList<>();
        ArrayList<String> sq = new ArrayList<>();

        for (String s : arr) {

            sq.add(s);
            backtrack(sq, len, res);
            sq.remove(sq.size() - 1);
        }

        return res;
    }

    // Driver Code
    public static void main(String[] args)
    {

        String[] arr = { "1111", "1222" };

        ArrayList<ArrayList<String> > res
            = numberSquares(arr);

        System.out.print("[");

        for (int i = 0; i < res.size(); i++) {

            System.out.print("[");

            for (int j = 0; j < res.get(i).size(); j++) {

                System.out.print("\"" + res.get(i).get(j)
                                 + "\"");

                if (j != res.get(i).size() - 1)
                    System.out.print(", ");
            }

            System.out.print("]");

            if (i != res.size() - 1)
                System.out.print(", ");
        }

        System.out.print("]");
    }
}
Python
# Python Program to generate number squares
# using Trie and Backtracking.
class TrieNode:

    def __init__(self):
        self.children = [None] * 10
        self.words = []


root = None

def insert(word):

    node = root

    for ch in word:

        idx = ord(ch) - ord('0')

        if node.children[idx] is None:
            node.children[idx] = TrieNode()

        node = node.children[idx]

        # Store string at every node along its path
        node.words.append(word)


def getStringsWithPrefix(prefix):

    node = root

    for ch in prefix:

        idx = ord(ch) - ord('0')

        if node.children[idx] is None:
            return []

        node = node.children[idx]

    return node.words


def backtrack(sq, length, res):

    if len(sq) == length:

        res.append(sq.copy())
        return

    idx = len(sq)

    # Build required prefix for next string
    prefix = ""

    for i in range(idx):
        prefix += sq[i][idx]

    for s in getStringsWithPrefix(prefix):

        sq.append(s)
        backtrack(sq, length, res)
        sq.pop()


def numberSquares(arr):

    global root

    root = TrieNode()

    length = len(arr[0])

    # Build trie with all strings
    for s in arr:
        insert(s)

    res = []
    sq = []

    for s in arr:

        sq.append(s)
        backtrack(sq, length, res)
        sq.pop()

    return res


if __name__ == "__main__":

    arr = ["1111", "1222"]

    result = numberSquares(arr)

    print(result)
C#
using System;
using System.Collections.Generic;

class GFG {

    class TrieNode {

        public TrieNode[] children = new TrieNode[10];
        public List<string> words = new List<string>();
    }

    TrieNode root;

    void insert(string word)
    {

        TrieNode node = root;

        foreach(char ch in word)
        {

            int idx = ch - '0';

            if (node.children[idx] == null)
                node.children[idx] = new TrieNode();

            node = node.children[idx];

            // Store string at every node along its path
            node.words.Add(word);
        }
    }

    List<string> getStringsWithPrefix(string prefix)
    {

        TrieNode node = root;

        foreach(char ch in prefix)
        {

            int idx = ch - '0';

            if (node.children[idx] == null)
                return new List<string>();

            node = node.children[idx];
        }

        return node.words;
    }

    void backtrack(List<string> sq, int len,
                   List<List<string> > res)
    {

        if (sq.Count == len) {

            res.Add(new List<string>(sq));
            return;
        }

        int idx = sq.Count;

        // Build required prefix for next string
        string prefix = "";

        for (int i = 0; i < idx; i++)
            prefix += sq[i][idx];

        foreach(string s in getStringsWithPrefix(prefix))
        {

            sq.Add(s);
            backtrack(sq, len, res);
            sq.RemoveAt(sq.Count - 1);
        }
    }

    public List<List<string> > numberSquares(string[] arr)
    {

        root = new TrieNode();

        int len = arr[0].Length;

        // Build trie with all strings
        foreach(string s in arr) insert(s);

        List<List<string> > res = new List<List<string> >();
        List<string> sq = new List<string>();

        foreach(string s in arr)
        {

            sq.Add(s);
            backtrack(sq, len, res);
            sq.RemoveAt(sq.Count - 1);
        }

        return res;
    }

    // Driver Code
    public static void Main()
    {

        GFG obj = new GFG();

        string[] arr = { "1111", "1222" };

        List<List<string> > res = obj.numberSquares(arr);

        Console.Write("[");

        for (int i = 0; i < res.Count; i++) {

            Console.Write("[");

            for (int j = 0; j < res[i].Count; j++) {

                Console.Write("\"" + res[i][j] + "\"");

                if (j != res[i].Count - 1)
                    Console.Write(", ");
            }

            Console.Write("]");

            if (i != res.Count - 1)
                Console.Write(", ");
        }

        Console.Write("]");
    }
}
JavaScript
class TrieNode {
    constructor()
    {
        this.children = Array(10).fill(null);
        this.words = [];
    }
}

let root = null;

function insert(word)
{
    let node = root;
    for (let ch of word) {
        let idx = ch.charCodeAt(0) - "0".charCodeAt(0);
        if (!node.children[idx]) {
            node.children[idx] = new TrieNode();
        }
        node = node.children[idx];

        // Store string at every node along its path
        node.words.push(word);
    }
}

function getStringsWithPrefix(prefix)
{
    let node = root;
    for (let ch of prefix) {
        let idx = ch.charCodeAt(0) - "0".charCodeAt(0);
        if (!node.children[idx]) {
            return [];
        }
        node = node.children[idx];
    }
    return node.words;
}

function backtrack(sq, len, res)
{
    if (sq.length === len) {
        res.push([...sq ]);
        return;
    }

    let idx = sq.length;

    // Build required prefix for next string
    let prefix = "";
    for (let i = 0; i < idx; i++) {
        prefix += sq[i][idx];
    }

    for (let s of getStringsWithPrefix(prefix)) {
        sq.push(s);
        backtrack(sq, len, res);
        sq.pop();
    }
}

function numberSquares(arr)
{
    root = new TrieNode();
    let len = arr[0].length;

    // Build trie with all strings
    for (let s of arr) {
        insert(s);
    }

    let res = [];
    let sq = [];

    for (let s of arr) {
        sq.push(s);
        backtrack(sq, len, res);
        sq.pop();
    }

    return res;
}

// Driver Code
let arr = [ "1111", "1222" ];
let result = numberSquares(arr);
console.log(JSON.stringify(result));

Output
[["1111", "1111", "1111", "1111"], ["1111", "1222", "1222", "1222"]]

Time Complexity: O(n × L + Ans × L ^ 2) - Builds the Trie and generates only valid arrangements by searching required prefixes efficiently.
Space Complexity: O(n × L) - Stores all strings and their prefixes inside the Trie.

Comment