3093. Longest Common Suffix Queries
Problem Description
You have two arrays of strings: wordsContainer
and wordsQuery
.
For each query string wordsQuery[i]
, you need to find a string from wordsContainer
that shares the longest common suffix with it. A suffix is a substring that appears at the end of a string. For example, "ing" is a suffix of "running".
When multiple strings in wordsContainer
share the same longest common suffix with a query:
- First tiebreaker: Choose the string with the smallest length
- Second tiebreaker: If multiple strings have the same smallest length, choose the one that appears earlier in
wordsContainer
(smaller index)
Return an array ans
where ans[i]
is the index of the string in wordsContainer
that best matches wordsQuery[i]
according to the rules above.
Example walkthrough:
If wordsContainer = ["abc", "bbc", "cc"]
and wordsQuery = ["c"]
:
- "abc" has suffix "c" in common (length 1)
- "bbc" has suffix "c" in common (length 1)
- "cc" has suffix "c" in common (length 1)
All three share the same longest common suffix of length 1. Among them, "cc" has the smallest length (2), so the answer would be index 2.
The solution uses a Trie (prefix tree) data structure, but since we're dealing with suffixes, strings are inserted in reverse order. Each Trie node tracks:
children
: Array of 26 child nodes (for each letter a-z)length
: The length of the shortest string passing through this nodeidx
: The index of that shortest string inwordsContainer
During insertion, each string is reversed and added character by character. At each node, if the current string is shorter than the stored length
, the node's length
and idx
are updated.
For queries, we traverse the reversed query string through the Trie as far as possible. When we can't continue (no matching child), we return the idx
stored at the current node, which represents the best match according to the problem's criteria.
Intuition
The key insight is recognizing that finding the longest common suffix is essentially the same problem as finding the longest common prefix, but with strings reversed. This immediately suggests using a Trie data structure, which excels at prefix matching.
Think about how we normally use a Trie for prefix matching: we insert words character by character from the beginning, creating a tree where common prefixes share the same path. To adapt this for suffix matching, we can simply insert words in reverse order. For example, "abc" becomes "cba" when inserted, so the suffix "bc" becomes the prefix "cb" in our reversed Trie.
The challenging part is handling the tiebreaking rules. When multiple strings share the same longest common suffix, we need to pick the shortest one, and if there's still a tie, the one with the smallest index.
Here's the clever part: we can handle this during Trie construction itself. At each node in the Trie, we store two pieces of information:
- The length of the shortest string that passes through this node
- The index of that string in the original array
As we insert each string, we update these values at every node along the path if we find a shorter string (or same length but earlier index). This way, each node always "remembers" the best candidate according to our tiebreaking rules.
When querying, we traverse the Trie with the reversed query string as far as we can go. The moment we can't continue (either we hit a null child or reach the end of the query), the current node already contains the index of the best matching string. No additional comparison is needed because we've pre-computed the optimal choice during insertion.
This approach is efficient because:
- We only build the Trie once for all queries
- Each query is answered in
O(m)
time wherem
is the query string length - The tiebreaking logic is handled during insertion rather than at query time
Learn more about Trie patterns.
Solution Approach
The implementation consists of two main components: the [Trie](/problems/trie_intro)
class for suffix matching and the Solution
class that orchestrates the process.
Trie Node Structure
Each Trie node contains:
children
: An array of size 26 (for letters a-z) to store child nodeslength
: Tracks the length of the shortest string passing through this nodeidx
: Stores the index of that shortest string inwordsContainer
We use __slots__
for memory optimization and initialize length
and idx
to infinity (inf
) to ensure any actual string will update these values.
Insert Operation
The insert(w, i)
method adds a string w
with index i
to the Trie:
-
Update root node: Before traversing, we check if the current string is shorter than what's stored at the root. If so, we update the root's
length
andidx
. -
Reverse traversal: We iterate through the string in reverse order using
w[::-1]
. For example, "abc" is processed as "c", "b", "a". -
Character-by-character insertion: For each character:
- Calculate its index:
idx = ord(c) - ord("a")
(converts 'a' to 0, 'b' to 1, etc.) - Create a new Trie node if the path doesn't exist
- Move to the child node
- Update the child node's
length
andidx
if the current string is shorter
- Calculate its index:
This ensures that at each node along the path, we maintain the index of the shortest string that passes through it.
Query Operation
The query(w)
method finds the best matching string for a query:
-
Reverse traversal: Similar to insertion, we traverse the query string in reverse using
w[::-1]
. -
Follow the path: For each character, we attempt to follow the corresponding child node.
-
Stop condition: If we encounter a
None
child (path doesn't exist), we break the loop. This happens when we've found the longest possible common suffix. -
Return result: We return the
idx
stored at the current node, which represents the best matching string according to our tiebreaking rules.
Main Solution
The stringIndices
method coordinates the entire process:
-
Build the Trie: Create a new Trie and insert all strings from
wordsContainer
with their indices:for i, w in enumerate(wordsContainer): trie.insert(w, i)
-
Process queries: For each query string, find the best match using the Trie:
return [trie.query(w) for w in wordsQuery]
Time and Space Complexity
-
Time Complexity:
- Building the Trie:
O(n * m)
wheren
is the number of strings inwordsContainer
andm
is the average string length - Processing queries:
O(q * m)
whereq
is the number of queries - Total:
O((n + q) * m)
- Building the Trie:
-
Space Complexity:
O(n * m)
for storing the Trie structure
The elegance of this solution lies in pre-computing the tiebreaking decisions during Trie construction, making query operations both simple and efficient.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to understand how the Trie-based solution works.
Given:
wordsContainer = ["abcd", "bcd", "xbcd"]
wordsQuery = ["cd", "bcd", "xyz"]
Step 1: Build the Trie
We insert each word from wordsContainer
in reverse order:
-
Insert "abcd" (index 0):
- Reverse it: "dcba"
- Create path: root β d β c β b β a
- At each node, store length=4, idx=0
-
Insert "bcd" (index 1):
- Reverse it: "dcb"
- Follow existing path: root β d β c β b
- At root: length=3, idx=1 (3 < 4, so update)
- At 'd': length=3, idx=1 (3 < 4, so update)
- At 'c': length=3, idx=1 (3 < 4, so update)
- At 'b': length=3, idx=1 (3 < 4, so update)
-
Insert "xbcd" (index 2):
- Reverse it: "dcbx"
- Follow path: root β d β c β b β x (create new node 'x')
- At root: keep length=3, idx=1 (4 > 3, no update)
- At 'd': keep length=3, idx=1 (4 > 3, no update)
- At 'c': keep length=3, idx=1 (4 > 3, no update)
- At 'b': keep length=3, idx=1 (4 > 3, no update)
- At 'x': length=4, idx=2
Trie structure after insertion:
root (len=3, idx=1) ββ d (len=3, idx=1) ββ c (len=3, idx=1) ββ b (len=3, idx=1) ββ a (len=4, idx=0) ββ x (len=4, idx=2)
Step 2: Process Queries
-
Query "cd":
- Reverse it: "dc"
- Traverse: root β d β c
- Can continue to 'd' and 'c'
- Can't continue further (query exhausted)
- Return idx at node 'c' = 1
- Answer: index 1 ("bcd" shares suffix "cd")
-
Query "bcd":
- Reverse it: "dcb"
- Traverse: root β d β c β b
- Can continue through all characters
- Query exhausted at node 'b'
- Return idx at node 'b' = 1
- Answer: index 1 ("bcd" shares suffix "bcd")
-
Query "xyz":
- Reverse it: "zyx"
- Try to traverse: root β z
- No child 'z' exists at root
- Return idx at root = 1
- Answer: index 1 ("bcd" has the shortest length among all words)
Final Result: [1, 1, 1]
This example demonstrates how:
- The Trie stores reversed strings to convert suffix matching to prefix matching
- Each node maintains the index of the shortest string passing through it
- Queries traverse as far as possible and return the stored index
- When no common suffix exists (like "xyz"), the root node provides the fallback answer
Solution Implementation
1from typing import List
2from math import inf
3
4
5class Trie:
6 """A Trie data structure for storing strings in reverse order to find longest common suffixes."""
7
8 __slots__ = ("children", "length", "idx")
9
10 def __init__(self):
11 """Initialize a Trie node with 26 children (for lowercase English letters)."""
12 # Array to store child nodes for each letter a-z
13 self.children = [None] * 26
14 # Store the minimum length of strings passing through this node
15 self.length = inf
16 # Store the index of the string with minimum length at this node
17 self.idx = inf
18
19 def insert(self, word: str, index: int) -> None:
20 """
21 Insert a word into the Trie in reverse order.
22
23 Args:
24 word: The string to insert
25 index: The original index of the word in the container
26 """
27 node = self
28
29 # Update root node with minimum length word information
30 if node.length > len(word):
31 node.length = len(word)
32 node.idx = index
33
34 # Insert characters in reverse order (for suffix matching)
35 for char in word[::-1]:
36 # Calculate the index for this character (0-25 for a-z)
37 char_index = ord(char) - ord("a")
38
39 # Create new node if path doesn't exist
40 if node.children[char_index] is None:
41 node.children[char_index] = Trie()
42
43 # Move to child node
44 node = node.children[char_index]
45
46 # Update this node with minimum length word information
47 if node.length > len(word):
48 node.length = len(word)
49 node.idx = index
50
51 def query(self, word: str) -> int:
52 """
53 Find the index of the word with the longest common suffix.
54
55 Args:
56 word: The query string
57
58 Returns:
59 The index of the container word with the longest matching suffix
60 and minimum length among those with the same suffix
61 """
62 node = self
63
64 # Traverse the Trie following the reverse of the query word
65 for char in word[::-1]:
66 char_index = ord(char) - ord("a")
67
68 # Stop if no further matching suffix exists
69 if node.children[char_index] is None:
70 break
71
72 # Move to the next node
73 node = node.children[char_index]
74
75 # Return the index of the best matching word at this node
76 return node.idx
77
78
79class Solution:
80 """Solution class for finding strings with longest common suffixes."""
81
82 def stringIndices(
83 self, wordsContainer: List[str], wordsQuery: List[str]
84 ) -> List[int]:
85 """
86 Find indices of container words with longest common suffix for each query.
87
88 Args:
89 wordsContainer: List of strings to search from
90 wordsQuery: List of query strings
91
92 Returns:
93 List of indices where each index corresponds to the container word
94 with the longest common suffix for each query word
95 """
96 # Build the Trie with all container words
97 trie = Trie()
98 for i, word in enumerate(wordsContainer):
99 trie.insert(word, i)
100
101 # Process each query and return results
102 return [trie.query(word) for word in wordsQuery]
103
1/**
2 * Trie data structure for suffix matching
3 * Stores words in reverse order to facilitate suffix matching
4 */
5class Trie {
6 // Constant representing infinity for initialization
7 private static final int INFINITY = 1 << 30;
8
9 // Array to store child nodes for each letter (a-z)
10 private Trie[] children = new Trie[26];
11
12 // Minimum length of word stored at or below this node
13 private int minLength = INFINITY;
14
15 // Index of the word with minimum length at or below this node
16 private int wordIndex = INFINITY;
17
18 /**
19 * Inserts a word into the trie in reverse order
20 * Updates minimum length and corresponding index at each node
21 * @param word the word to insert
22 * @param index the original index of the word in the container
23 */
24 public void insert(String word, int index) {
25 Trie currentNode = this;
26
27 // Update root node's minimum length if necessary
28 if (currentNode.minLength > word.length()) {
29 currentNode.minLength = word.length();
30 currentNode.wordIndex = index;
31 }
32
33 // Insert characters in reverse order (from last to first)
34 for (int charPos = word.length() - 1; charPos >= 0; charPos--) {
35 int charIndex = word.charAt(charPos) - 'a';
36
37 // Create new node if path doesn't exist
38 if (currentNode.children[charIndex] == null) {
39 currentNode.children[charIndex] = new Trie();
40 }
41
42 // Move to child node
43 currentNode = currentNode.children[charIndex];
44
45 // Update minimum length at current node if necessary
46 if (currentNode.minLength > word.length()) {
47 currentNode.minLength = word.length();
48 currentNode.wordIndex = index;
49 }
50 }
51 }
52
53 /**
54 * Queries the trie for the longest matching suffix
55 * Returns the index of the shortest word with matching suffix
56 * @param word the query word to match
57 * @return index of the best matching word
58 */
59 public int query(String word) {
60 Trie currentNode = this;
61
62 // Traverse the trie following the reverse path of the query word
63 for (int charPos = word.length() - 1; charPos >= 0; charPos--) {
64 int charIndex = word.charAt(charPos) - 'a';
65
66 // Stop if no matching path exists
67 if (currentNode.children[charIndex] == null) {
68 break;
69 }
70
71 // Move to child node
72 currentNode = currentNode.children[charIndex];
73 }
74
75 // Return the index of the shortest word found
76 return currentNode.wordIndex;
77 }
78}
79
80/**
81 * Solution class for finding words with matching suffixes
82 */
83class Solution {
84 /**
85 * Finds indices of words in container that have longest matching suffix
86 * with each query word. Among matches, returns the shortest word.
87 * @param wordsContainer array of container words
88 * @param wordsQuery array of query words
89 * @return array of indices corresponding to best matches for each query
90 */
91 public int[] stringIndices(String[] wordsContainer, String[] wordsQuery) {
92 // Build trie from container words
93 Trie trie = new Trie();
94 for (int i = 0; i < wordsContainer.length; i++) {
95 trie.insert(wordsContainer[i], i);
96 }
97
98 // Process each query word
99 int queryCount = wordsQuery.length;
100 int[] result = new int[queryCount];
101 for (int i = 0; i < queryCount; i++) {
102 result[i] = trie.query(wordsQuery[i]);
103 }
104
105 return result;
106 }
107}
108
1class Trie {
2private:
3 static const int INF = 1 << 30; // Large value representing infinity
4 static const int ALPHABET_SIZE = 26; // Number of lowercase English letters
5
6 Trie* children[ALPHABET_SIZE]; // Array of child nodes for each letter
7 int minLength; // Minimum length of words in this subtree
8 int wordIndex; // Index of the word with minimum length
9
10public:
11 // Constructor: Initialize trie node with null children and infinite values
12 Trie() {
13 for (int i = 0; i < ALPHABET_SIZE; ++i) {
14 children[i] = nullptr;
15 }
16 minLength = INF;
17 wordIndex = INF;
18 }
19
20 // Insert a word into the trie (in reverse order) with its index
21 void insert(string word, int index) {
22 Trie* currentNode = this;
23
24 // Update root node if current word is shorter
25 if (currentNode->minLength > word.length()) {
26 currentNode->minLength = word.length();
27 currentNode->wordIndex = index;
28 }
29
30 // Insert characters from the end of the word (building suffix trie)
31 for (int charPos = word.length() - 1; charPos >= 0; --charPos) {
32 int charIndex = word[charPos] - 'a'; // Convert character to array index
33
34 // Create new node if path doesn't exist
35 if (currentNode->children[charIndex] == nullptr) {
36 currentNode->children[charIndex] = new Trie();
37 }
38
39 // Move to child node
40 currentNode = currentNode->children[charIndex];
41
42 // Update minimum length and index at each node
43 if (currentNode->minLength > word.length()) {
44 currentNode->minLength = word.length();
45 currentNode->wordIndex = index;
46 }
47 }
48 }
49
50 // Query the trie to find the index of shortest word with matching suffix
51 int query(string word) {
52 Trie* currentNode = this;
53
54 // Traverse the trie following the suffix of the query word
55 for (int charPos = word.length() - 1; charPos >= 0; --charPos) {
56 int charIndex = word[charPos] - 'a'; // Convert character to array index
57
58 // Stop if no matching path exists
59 if (currentNode->children[charIndex] == nullptr) {
60 break;
61 }
62
63 // Move to child node
64 currentNode = currentNode->children[charIndex];
65 }
66
67 // Return the index of the shortest word at the deepest matching node
68 return currentNode->wordIndex;
69 }
70};
71
72class Solution {
73public:
74 // Find indices of shortest words in container that share longest suffix with queries
75 vector<int> stringIndices(vector<string>& wordsContainer, vector<string>& wordsQuery) {
76 // Build suffix trie from all container words
77 Trie* suffixTrie = new Trie();
78 for (int i = 0; i < wordsContainer.size(); ++i) {
79 suffixTrie->insert(wordsContainer[i], i);
80 }
81
82 // Process each query word
83 int queryCount = wordsQuery.size();
84 vector<int> result(queryCount);
85
86 for (int i = 0; i < queryCount; ++i) {
87 result[i] = suffixTrie->query(wordsQuery[i]);
88 }
89
90 return result;
91 }
92};
93
1// Global variables to represent the Trie structure
2const ALPHABET_SIZE = 26;
3let trieChildren: (number | null)[][] = [];
4let trieLength: number[] = [];
5let trieIndex: number[] = [];
6let nodeCount: number = 0;
7
8/**
9 * Creates a new trie node and returns its index
10 */
11function createTrieNode(): number {
12 const nodeId = nodeCount++;
13 trieChildren[nodeId] = new Array(ALPHABET_SIZE).fill(null);
14 trieLength[nodeId] = Infinity;
15 trieIndex[nodeId] = Infinity;
16 return nodeId;
17}
18
19/**
20 * Inserts a word into the trie with its corresponding index
21 * The word is inserted in reverse order (from last character to first)
22 * @param word - The word to insert
23 * @param wordIndex - The index of the word in the original array
24 */
25function insert(word: string, wordIndex: number): void {
26 let currentNode = 0; // Start from root
27
28 // Update root node if current word is shorter
29 if (trieLength[currentNode] > word.length) {
30 trieLength[currentNode] = word.length;
31 trieIndex[currentNode] = wordIndex;
32 }
33
34 // Traverse the word from last character to first
35 for (let charPos = word.length - 1; charPos >= 0; charPos--) {
36 const charIndex = word.charCodeAt(charPos) - 'a'.charCodeAt(0);
37
38 // Create child node if it doesn't exist
39 if (trieChildren[currentNode][charIndex] === null) {
40 trieChildren[currentNode][charIndex] = createTrieNode();
41 }
42
43 currentNode = trieChildren[currentNode][charIndex]!;
44
45 // Update node if current word is shorter
46 if (trieLength[currentNode] > word.length) {
47 trieLength[currentNode] = word.length;
48 trieIndex[currentNode] = wordIndex;
49 }
50 }
51}
52
53/**
54 * Queries the trie to find the index of the shortest word with matching suffix
55 * @param word - The word to query
56 * @returns The index of the shortest matching word
57 */
58function query(word: string): number {
59 let currentNode = 0; // Start from root
60
61 // Traverse the word from last character to first
62 for (let charPos = word.length - 1; charPos >= 0; charPos--) {
63 const charIndex = word.charCodeAt(charPos) - 'a'.charCodeAt(0);
64
65 // Stop if no matching child exists
66 if (trieChildren[currentNode][charIndex] === null) {
67 break;
68 }
69
70 currentNode = trieChildren[currentNode][charIndex]!;
71 }
72
73 return trieIndex[currentNode];
74}
75
76/**
77 * Finds indices of shortest words in wordsContainer that have matching suffixes with wordsQuery
78 * @param wordsContainer - Array of words to build the trie from
79 * @param wordsQuery - Array of words to query
80 * @returns Array of indices corresponding to shortest matching words
81 */
82function stringIndices(wordsContainer: string[], wordsQuery: string[]): number[] {
83 // Initialize trie data structures
84 trieChildren = [];
85 trieLength = [];
86 trieIndex = [];
87 nodeCount = 0;
88
89 // Create root node
90 createTrieNode();
91
92 // Build trie from container words
93 for (let i = 0; i < wordsContainer.length; i++) {
94 insert(wordsContainer[i], i);
95 }
96
97 // Process queries and build result array
98 const queryCount = wordsQuery.length;
99 const result: number[] = new Array(queryCount);
100
101 for (let i = 0; i < queryCount; i++) {
102 result[i] = query(wordsQuery[i]);
103 }
104
105 return result;
106}
107
Time and Space Complexity
Time Complexity: O(Lβ + Lβ)
The time complexity consists of two parts:
- Building the trie: For each word in
wordsContainer
, we insert it character by character in reverse order. This takesO(Lβ)
time, whereLβ
is the sum of lengths of all words inwordsContainer
. - Querying the trie: For each word in
wordsQuery
, we traverse the trie character by character in reverse order until we can't proceed further. This takesO(Lβ)
time, whereLβ
is the sum of lengths of all words inwordsQuery
.
Total time complexity: O(Lβ + Lβ)
Space Complexity: O(Lβ Γ |Ξ£|)
The space is dominated by the trie structure:
- In the worst case, we create a new trie node for each character in
wordsContainer
. - Each trie node contains an array of size 26 (for lowercase English letters, where
|Ξ£| = 26
). - The maximum number of nodes is proportional to
Lβ
(the total number of characters inwordsContainer
). - Therefore, the space complexity is
O(Lβ Γ |Ξ£|)
orO(Lβ Γ 26) = O(26Lβ) = O(Lβ Γ |Ξ£|)
.
Note: The reference answer shows O(Lβ Γ |Ξ£| + Lβ)
for time complexity, but the Lβ
term doesn't multiply with |Ξ£|
because during queries, we only traverse existing paths in the trie without creating new nodes or iterating through the alphabet at each node.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting to Update the Root Node
The Pitfall:
A critical but easy-to-miss detail is updating the root node's length
and idx
before traversing the Trie during insertion. The root node represents the empty suffix (no common characters), which every string shares. If you skip this update, queries that have no matching characters with any container word will return incorrect results.
Why It Happens: When traversing a Trie, developers often focus on updating nodes along the path but forget that the root itself needs to track the shortest string in the entire collection.
Example of the Bug:
def insert(self, word: str, index: int) -> None:
node = self
# BUG: Missing root node update!
# If we skip this, queries with no common suffix fail
for char in word[::-1]:
char_index = ord(char) - ord("a")
if node.children[char_index] is None:
node.children[char_index] = Trie()
node = node.children[char_index]
if node.length > len(word):
node.length = len(word)
node.idx = index
Test Case That Exposes the Bug:
wordsContainer = ["abc", "def", "ghi"] wordsQuery = ["xyz"] # No common suffix with any container word # Without root update: Returns inf or crashes # With root update: Correctly returns 0 (shortest word "abc")
The Solution: Always update the root node before traversing:
def insert(self, word: str, index: int) -> None:
node = self
# CRITICAL: Update root node first
if node.length > len(word):
node.length = len(word)
node.idx = index
# Then traverse and update child nodes
for char in word[::-1]:
# ... rest of the insertion logic
2. Incorrect Tiebreaking Logic
The Pitfall:
Using >=
instead of >
when comparing lengths leads to incorrect tiebreaking. The problem specifies that when multiple strings have the same length, we should choose the one with the smaller index (earlier in the array).
Example of the Bug:
# WRONG: This updates even when lengths are equal
if node.length >= len(word): # Bug: should be >
node.length = len(word)
node.idx = index
Test Case That Exposes the Bug:
wordsContainer = ["abc", "bcd", "cde"] # All length 3 wordsQuery = ["c"] # All have suffix "c" # With >= : Returns 2 (last index) # With > : Returns 0 (first index with minimum length)
The Solution: Use strict inequality to preserve the first occurrence:
# CORRECT: Only update if strictly shorter
if node.length > len(word):
node.length = len(word)
node.idx = index
3. Not Handling Empty Strings or Edge Cases
The Pitfall: The code assumes all strings are non-empty and contain only lowercase letters. Empty strings or special characters can cause unexpected behavior.
Defensive Programming Solution:
def insert(self, word: str, index: int) -> None:
if not word: # Handle empty string
return
node = self
if node.length > len(word):
node.length = len(word)
node.idx = index
for char in word[::-1]:
if not 'a' <= char <= 'z': # Validate character
continue
char_index = ord(char) - ord("a")
# ... rest of the logic
Key Takeaway
The most critical pitfall is forgetting to update the root node. This subtle bug can cause the solution to fail completely for queries that don't share any suffix with container words. Always remember that the root node represents the universal case where no characters match, and it must track the shortest string in the entire collection for correct fallback behavior.
Which data structure is used in a depth first search?
Recommended Readings
Trie Introduction Imagine you have a magic dictionary where as soon as you start spelling a word it immediately tells you how many words that start with those letters How cool would that be This is exactly the kind of magic a data structure called trie performs What's a Trie
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!