一些动态规划的练习题

Posted GoldenaArcher

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一些动态规划的练习题相关的知识,希望对你有一定的参考价值。

一些动态规划的练习题

大部分题目是分治的题目,所以 cv 了一下题目……每道题前面大概也空个四五行这样……?

top down 和 bottom up 都做了

  1. fib

    斐波那契数字(同样也可以求序列来着)

    /**
     *
     *
     *
     *
     *
     *
     *
     *
     */
    const memoFibTopDown = (n: number, memo: number[]): number => 
      if (n === 1) return 0;
    
      if (n === 2) return 1;
    
      if (!memo[n])
        memo[n] = memoFibTopDown(n - 1, memo) + memoFibTopDown(n - 2, memo);
      return memo[n];
    ;
    
    console.log(memoFibTopDown(6, []));
    console.log(memoFibTopDown(7, []));
    
    // avoid recursion
    const memoFibBottomUp = (n: number): number => 
      const memo = new Array(n + 1).fill(0);
      memo[2] = 1;
      for (let i = 2; i < n; i++) 
        memo[i + 1] = memo[i] + memo[i - 1];
      
    
      return memo[n];
    ;
    
    console.log(memoFibBottomUp(6));
    console.log(memoFibBottomUp(7));
    
  2. number factor

    /**
     *
     *
     *
     *
     */
    // number factor
    // problem
    // Given N, find the number of ways to express N as a sum of 1, 3 and 4.
    // example
    // N = 4, res = 4 - 4, 1, 3, 3, 1, 1, 1, 1, 1
    // N = 4, res = 6 -4, 1, 1, 4, 1, 3, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1
    const numFactorTopDown = (num: number): number => 
      const memo: number[] = new Array(num + 1).fill(0);
      const expression = [1, 3, 4];
    
      const recursion = (num: number): number => 
        if (num < 0) return 0;
        if (num === 0) return 1;
    
        if (memo[num]) return memo[num];
    
        let sum = 0;
        for (const exp of expression) 
          sum += recursion(num - exp);
        
    
        memo[num] = sum;
        return sum;
      ;
    
      recursion(num);
    
      return memo[num];
    ;
    
    console.log(numFactorTopDown(4));
    console.log(numFactorTopDown(5));
    console.log(numFactorTopDown(6));
    console.log(numFactorTopDown(7));
    
    const numFactorBottomUp = (num: number): number => 
      const memo = new Array(num + 1).fill(0);
      const expression = [1, 3, 4];
      for (const exp of expression) 
        memo[exp] = 1;
      
    
      for (let i = 1; i <= num; i++) 
        let sum = memo[i];
        for (const exp of expression) 
          sum += memo[i - exp] ?? 0;
        
    
        memo[i] = sum;
      
    
      return memo[num];
    ;
    
    console.log(numFactorBottomUp(4));
    console.log(numFactorBottomUp(5));
    console.log(numFactorBottomUp(6));
    console.log(numFactorBottomUp(7));
    
  3. house robber

    /**
     *
     *
     *
     *
     */
    // house robber
    // problem
    // given n number of houses along the street with some amount of money
    // adjacent hoouses cannot be stolen
    // find the max amount that can be stolen
    // ex1: [6, 7, 1, 30, 8, 2, 4], res: [_, 7, _, 30, _, _, 4] = 41
    // it can be divided:
    // max(6 + f([1, 30, 8, 2, 4], 0 + f([7, 1, 30, 8, 2, 4]))
    const houseRobberTD = (houses: number[]): number => 
      const memo = new Array(houses.length).fill(0);
    
      const recursion = (num: number): number => 
        if (num >= houses.length) return 0;
        if (num === houses.length - 1) return houses[houses.length - 1];
        if (memo[num]) return memo[num];
    
        const pick = houses[num] + recursion(num + 2);
        const noPick = recursion(num + 1);
    
        memo[num] = Math.max(pick, noPick);
    
        return memo[num];
      ;
    
      return recursion(0);
    ;
    
    console.log(houseRobberTD([6, 7, 1, 30, 8, 2, 4]));
    console.log(houseRobberTD([1, 2, 3, 1]));
    console.log(houseRobberTD([2, 7, 9, 3, 1]));
    console.log(houseRobberTD([1]));
    
    const houseRobberBU = (houses: number[]): number => 
      const memo = new Array(houses.length).fill(0);
    
      for (let i = 0; i < houses.length; i++) 
        const pick = houses[i] + (memo[i - 2] ?? 0);
        const notPick = memo[i - 1] ?? 0;
    
        memo[i] = Math.max(pick, notPick);
      
    
      return memo[houses.length - 1];
    ;
    
    console.log(houseRobberBU([6, 7, 1, 30, 8, 2, 4]));
    console.log(houseRobberBU([1, 2, 3, 1]));
    console.log(houseRobberBU([2, 7, 9, 3, 1]));
    console.log(houseRobberBU([1]));
    
  4. convert one string to another

    /**
     *
     *
     *
     *
     */
    // convert one string to another
    // problem
    // given 2 strings s1 and s2
    // converting s2 to s1 using celete, insert, or replace operations
    // find the minimum count of edit operations
    // ex1, "catch" & "carsh", res = 1, replace 'r' with 't'
    // ex2, "table" & "tbres", res = 3, insert '2 at index 1, replace 'r' with 'l', and delete 's'
    // min(num_of_op_performed + f(s1[1:], s2[1:]))
    // in DP, use 2D array to remember all the operation like:
    //            s1
    // s2
    const convertStringTD = (s1: string, s2: string): number => 
      const memo: number[][] = Array.from(new Array(s1.length), () =>
        new Array(s2.length).fill(0)
      );
    
      const recursion = (i: number, j: number): number => 
        if (i === s1.length) return s2.length - j;
        if (j === s2.length) return s1.length - i;
        if (s1[i] === s2[j]) return recursion(i + 1, j + 1);
    
        if (!memo[i][j]) 
          const insertOp = recursion(i + 1, j);
          const deleteOp = recursion(i, j + 1);
          const replaceOp = recursion(i + 1, j + 1);
    
          memo[i][j] = 1 + Math.min(insertOp, deleteOp, replaceOp);
        
    
        return memo[i][j];
      ;
    
      recursion(0, 0);
    
      return recursion(0, 0);
    ;
    
    console.log(convertStringTD('', 'abc'));
    console.log(convertStringTD('abc', ''));
    console.log(convertStringTD('abc', 'd'));
    console.log(convertStringTD('catch', 'carch'));
    console.log(convertStringTD('table', 'tbres'));
    console.log(convertStringTD('dable', 'tbres'));
    
    const convertStringBU = (s1: string, s2: string): number => 
      const memo: number[][] = Array.from(new Array(s1.length + 1), () =>
        new Array(s2.length + 1).fill(0)
      );
    
      for (let i = 0; i <= s1.length; i++) 
        memo[i][0] = i;
      
      for (let j = 0; j <= s2.length; j++) 
        memo[0][j] = j;
      
    
      for (let i = 1; i <= s1.length; i++) 
        for (let j = 1; j <= s2.length; j++) 
          if (s1[i - 1] === s2[j - 1]) 
            memo[i][j] = Math.min(
              memo[i - 1][j - 1],
              memo[i - 1][j],
              memo[i][j - 1]
            );
            continue;
          
    
          // insert op
          const insertOp = memo[i - 1][j];
          // delete op
          const deleteOp = memo[i][j - 1];
          // replace op
          const replaceOp = memo[i - 1][j - 1];
    
          memo[i][j] = Math.min(insertOp, deleteOp, replaceOp) + 1;
        
      
    
      console.log(memo);
    
      return memo[s1.length][s2.length];
    ;
    
    console.log(convertStringBU('catch', 'carch'));
    console.log(convertStringBU('dable', 'tbres'));
    console.log(convertStringBU('table', 'tbres'));
    console.log(convertStringBU('table', 'tbrltt'));
    
  5. zero one knapsack problem

    这道题其实是个非典型 DP,用 D&C 和 DP 其实没什么区别……就算用 DP 也没有可以重复地柜的子问题,不过还是试着写了一下。

    /**
     *
     *
     *
     *
     */
    // zero one knapsack problem
    // problem
    // given weight and profit of n items
    // find the maximum profit given capacity of C
    // items cannot be broken
    // profit: [31, 26, 17, 72]
    // weight: [ 3,  1,  2,  5]
    // kapacity: 7
    // res = 26 + 72 = 98
    // max(0 + profit[1, ..., n], profit[0] + profit[1, ..., n])
    const zeroOneKnapsackProblemTD = (
      profits: number[],
      weights: number[],
      capacity: number
    ): number => 
      const memo = new Map();
    
      const recursion = (n: number, capacity: number): number => 
        if (capacity <= 0) return 0;
        if (n === profits.length - 1)
          return weights[n] > capacity ? 0 : profits[n];
    
        const key = `$n,$capacity`;
    
        if (!memo.has(key)) 
          let takenProfit = 0,
            takenCapacity = 0;
    
          if (capacity > weights[n]) 
            takenCapacity = capacity - weights[n];
            takenProfit += profits[n];
          
    
          memo.set(
            key,
            Math.max(
              recursion(n + 1, capacity),
              takenProfit + recursion(n + 1, takenCapacity)
            )
          );
        
    
        return memo.get(key);
      ;
    
      return recursion(0, capacity);
    ;
    
    console.log(zeroOneKnapsackProblemTD动态规划:零钱兑换问题(javascript求解)

    动态规划-练习

    动态规划算法入门练习 (python实现)

    习题—动态规划贪心算法

    5.5 动态规划 习题

    动态规划练习题