Short and easy recursive solution
Use ranges to split a particular word into two: w[..i] and w[i..]:\ncsharp\npublic class Solution\n{\n    public IList<string> FindAllConcatenatedWordsInADict(s
Use ranges to split a particular word into two: `w[..i]` and `w[i..]`:\n```csharp\npublic class Solution\n{\n    public IList<string> FindAllConcatenatedWordsInADict(string[] words)\n    {\n        HashSet<string> ws = new(words);\n        return words.Where(w => IsConcatenated(w)).ToList();\n\n        bool IsConcatenated(string w, int count = 0)\n        {\n            if (w.Length == 0) return count > 1;\n\n            for (int i = 1; i <= w.Length; i++)\n            {\n                if (ws.Contains(w[..i]) && IsConcatenated(w[i..], count + 1)) return true;\n            }\n            \n            return false;\n        }\n    }\n}\n```\n\nThe same logic can be expressed in a more concise way, looks horrible though:\n```csharp\npublic class Solution\n{\n    public IList<string> FindAllConcatenatedWordsInADict(string[] words)\n    {\n        HashSet<string> ws = new(words);\n        return words.Where(w => IsConcatenated(w)).ToList();\n\n        bool IsConcatenated(string w, int count = 0) =>\n            w.Length == 0 && count > 1\n            || Enumerable.Range(1, w.Length)\n                .Where(i => ws.Contains(w[..i]) && IsConcatenated(w[i..], count + 1))\n                .Any();\n    }\n}\n```
['Depth-First Search', 'Recursion', 'C#']