Tags

  • AWS (7)
  • Apigee (3)
  • ArchLinux (5)
  • Array (6)
  • Backtracking (6)
  • BinarySearch (6)
  • C++ (19)
  • CI&CD (3)
  • Calculus (2)
  • DesignPattern (43)
  • DisasterRecovery (1)
  • Docker (8)
  • DynamicProgramming (20)
  • FileSystem (11)
  • Frontend (2)
  • FunctionalProgramming (1)
  • GCP (1)
  • Gentoo (6)
  • Git (15)
  • Golang (1)
  • Graph (10)
  • GraphQL (1)
  • Hardware (1)
  • Hash (1)
  • Kafka (1)
  • LinkedList (13)
  • Linux (27)
  • Lodash (2)
  • MacOS (3)
  • Makefile (1)
  • Map (5)
  • MathHistory (1)
  • MySQL (21)
  • Neovim (10)
  • Network (66)
  • Nginx (6)
  • Node.js (33)
  • OpenGL (6)
  • PriorityQueue (1)
  • ProgrammingLanguage (9)
  • Python (10)
  • RealAnalysis (20)
  • Recursion (3)
  • Redis (1)
  • RegularExpression (1)
  • Ruby (19)
  • SQLite (1)
  • Sentry (3)
  • Set (4)
  • Shell (3)
  • SoftwareEngineering (12)
  • Sorting (2)
  • Stack (4)
  • String (2)
  • SystemDesign (13)
  • Terraform (2)
  • Tree (24)
  • Trie (2)
  • TwoPointers (16)
  • TypeScript (3)
  • Ubuntu (4)
  • Home

    [Dynamic Programming] All Construct

    Published Nov 16, 2021 [  DynamicProgramming  ]

    Problem

    Write a function allConstruct(target, wordBank) that accepts a target string and an array of strings

    The function should return a 2D array containing all of the ways that the target can be constructed by concatenating elements of the wordBank array. Each element of the 2D array should represent on combination that constructs the target.

    You may reuse elements of wordBank as many times as needed.

    Brute Force

    const allConstruct = (target, wordBank) => {
    	// base case
    	// think of the return type, it should be the same as the last return line
    	if(target === '') return [[]]
    
    	let res = []
    
    	for(let word of wordBank) {
    		if(target.startsWith(word)) {
    			let remainRes = allConstruct(target.slice(word.length), wordBank)
    			let temp = remainRes.map(x => [word, ...x])
    			res.push(...temp)
    		}
    	}
    
    	// the return type should be the same as the base type
    	return res;
    }
    

    Memoization

    const allConstructMemo = (target, wordBank, memo = {}) => {
    	if(target in memo) return memo[target]
    	// base case
    	// think of the return type, it should be the same as the last return line
    	if(target === '') return [[]]
    
    	let res = []
    
    	for(let word of wordBank) {
    		if(target.startsWith(word)) {
    			let remainRes = allConstructMemo(target.slice(word.length), wordBank, memo)
    			let temp = remainRes.map(x => [word, ...x])
    			res.push(...temp)
    		}
    	}
    
    	memo[target] = res;
    	// the return type should be the same as the base type
    	return res;
    }
    

    Tabulation

    const allConstructTab = (target, wordBank) => {
    	// default value & base case
    	let table = Array(target.length + 1).fill().map(x => [])
    	console.log(table)
    
    	for(let i = 0; i <= target.length; i++) {
    		// if we can construct at table i
    		if(table[i].length !== 0) {
    			for(let word of wordBank) {
    				if(target.slice(i, i + word.length) === word) {
    					// [['a', 'b']]
    					let temp = table[i].map(x => [...x, word])
    					if(i + word.length <= target.length) {
    						// [['ab']]
    						table[i + word.length].push(...temp)
    					}
    				}
    			}
    		}
    	}
    	
    	return table[target.length]
    }
    

    Reference