preface
It is still necessary to learn the front-end algorithm. Not to mention that large factories test the algorithm in interviews, but when doing the permission module, if you don't understand the algorithm, you can't write the user-defined traversal of the tree structure.
Today, I will make a summary of the dynamic programming and dfs encountered recently, hoping to help you learn the algorithm.
Relationship between DP and dfs
Dynamic programming (dp):
- Is a bottom-up traversal.
- You need a recursive formula, such as f(n)=f(n-1)+f(n-2).
- No recursion, just ordinary iteration, so the performance is good.
Depth first search (dfs):
- Is a recursion from top to bottom.
- We also need a recurrence formula, such as f(n)=f(n-1)+f(n-2).
- Recursion from top to bottom. After encountering termination conditions, it will continue to take values from bottom to top (the essence of recursion). The process is similar to dp
- Because it traverses all possibilities, its performance is particularly poor and it is generally pruned
- The general pruning technique is to terminate or memorize in advance according to conditions
contact
- The memorized dfs is essentially similar to dp
- Because both of them need recursive formulas, in theory, all the problems dp that dfs can solve can be solved
- However, some problems are suitable for dfs, such as solving the problem of possibility
Double solutions to a classic problem
leetcode322. Change money
dp
var coinChange = function(coins, amount) { /** Ergodic i dp(n) = min( dp(n-conin[i]) + 1) */ coins.sort((a,b)=>b-a) const arr = new Array(amount+1).fill(0) for(let i =1;i<=amount;i++){ let curAmount = i //total for(let j=0;j<coins.length;j++){ let curConin = coins[j] //Current coin exchange if(curConin<=curAmount){ let res = arr[curAmount-curConin]+1 //This number must be greater than or equal to 0 if(res===0) continue //Equal to 0, this change is not advisable arr[i] = arr[i]===0?res:Math.min(arr[i],res) //Equal to 0 has not been initialized yet. Initialize it first } } if(!arr[i]) arr[i]=-1 } // console.log(arr) return arr[amount] };
dfs
If you do not prune, you will timeout. If you prune with the cache, the general efficiency of pruning will not be able to beat Dp unless there is a very good pruning strategy
var coinChange = function(coins, amount) { coins.sort((a,b)=>b-a) let cache = {} const dfs = (restamount)=>{ if(restamount===0) return 0 if(restamount<coins[coins.length-1]) return -1 //If the balance is smaller than the minimum denomination, it cannot be successfully redeemed if(cache[restamount])return cache[restamount] if(restamount<coins[coins.length-1]) return for(var i=0;i<coins.length;i++){ if(coins[i]<=restamount){ let res = dfs(restamount-coins[i])+1 if(res===0) continue cache[restamount] = cache[restamount]?Math.min(cache[restamount],res):res } } // When we get here, the cache[restamount] has actually determined the top-down depth first traversal. In fact, there is a bottom-up process by default, so it is naturally slower than dp if(!cache[restamount]) cache[restamount]=-1 return cache[restamount] } return dfs(amount) };
Topics suitable for dsf
leetcode46. Full arrangement
Solving the problem of possibility is very suitable for dfs
If you use dp, the code will be difficult to organize
var permute = function(nums) { //dfs /** dp(n) = dp(n-1)Each element in the array adds n at position i (0 < = i < = n) */ const dfs=(nums)=>{ // [1,2] if(nums.length===1) return [nums.slice(0,1)] const arr = dfs(nums.slice(0,-1)) const res = [] arr.forEach(item=>{ for(var i=0;i<=item.length;i++){ let addedItem = item.slice() addedItem.splice(i,0,nums[nums.length-1]) res.push(addedItem) } }) return res } return dfs(nums) };
Topics suitable for dp
leetcode198. raid homes and plunder houses
This problem is very refreshing to solve with dp. Of course, the recursive formula contains greedy thought.
var rob = function(nums) { //DP (N) = max (DP (N-2) + nums [N], DP (N-1)), there are N in total, greedy. Income when it is the turn of the nth house from left to right const dp = new Array(nums.length).fill(0) dp[1] = nums[0] for(let i=2;i<=nums.length;i++){ dp[i] = Math.max(dp[i-2]+nums[i-1] , dp[i-1]) //It's the turn of the income of house i } return dp[nums.length] };