Two Approaches 1.) Memo + DFS 2.) DP
Memo + DFS:\n\nclass Solution:\n    def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]:\n        wordSet = set(words)\n        rv = []\n  
Memo + DFS:\n```\nclass Solution:\n    def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]:\n        wordSet = set(words)\n        rv = []\n        for wd in words:\n            memo = {}\n            wordSet.remove(wd)\n            if len(wd) > 0 and self.dfs(wd, wordSet, memo):\n                rv.append(wd)\n            wordSet.add(wd)    \n        return rv\n    \n    def dfs(self, s, wordSet, memo):\n        if len(s) == 0:\n            return True\n        \n        if s in memo:\n            return memo[s]\n        \n        result = False\n        nw = \'\'\n        for c in s:\n            nw += c\n            if nw in wordSet and self.dfs(s[len(nw):], wordSet, memo):\n                result = True\n                break\n        \n        memo[s] = result\n        return result \n```\t\t\n\t\nDP:\n```\n\tclass Solution:\n    def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]:\n        wordSet = set(words)\n        rv = []\n        for wd in words:\n            if len(wd) == 0:\n                continue\n            wordSet.remove(wd)\n            dp = [False for _ in range(len(wd)+1)]\n            dp[0] = True\n            for i in range(len(wd)):\n                for j in range(i+1, len(wd)+1):\n                    ss = wd[i:j]\n                    if ss in wordSet and dp[i]:\n                        dp[j] = True\n            wordSet.add(wd)\n            if dp[len(wd)]:\n                rv.append(wd)\n        return rv\n```\t\t\n\t\t
['Depth-First Search', 'Python']