一些分治的练习题

Posted GoldenaArcher

tags:

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

一些分治的练习题

这次因为有稍微写一下题目,所以每道题前面大概空个四五行这样……?

  1. numFactor

    /**
     *
     *
     *
     *
     */
    // 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 numFactor = (num: number): number => 
      const expression = [1, 3, 4];
      let sum = 0;
      if (num === 0) return 1;
      if (num < 0) return 0;
    
      for (const exp of expression) 
        sum += numFactor(num - exp);
      
    
      return sum;
    ;
    
    console.log(numFactor(4));
    console.log(numFactor(5));
    
  2. houseRobber

    /**
     *
     *
     *
     *
     */
    // 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 houseRobber = (houses: number[]): number => 
      if (houses.length === 1) return houses[0];
      if (houses.length === 2) return Math.max(...houses);
    
      let sum = 0;
    
      sum += Math.max(
        houses[0] + houseRobber(houses.slice(2)),
        houseRobber(houses.slice(1))
      );
    
      return sum;
    ;
    
    console.log(houseRobber([6, 7, 1, 30, 8, 2, 4]));
    
  3. 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:]))
    const convertString = (s1: string, s2: string): number => 
      if ((!s1.length && s2.length) || (s1.length && !s2.length))
        return Math.abs(s2.length - s1.length);
    
      if (s1.length === 1 && s2.length === 1) return s1 === s2 ? 0 : 1;
    
      if (s1[0] === s2[0])
        return convertString(s1.substring(1), s2.substring(1));
    
      const deleteOp = 1 + convertString(s1, s2.substring(1)),
        insertOp = 1 + convertString(s1.substring(1), s2),
        replaceOp = 1 + convertString(s1.substring(1), s2.substring(1));
    
      return Math.min(insertOp, deleteOp, replaceOp);
    ;
    
    console.log(convertString('', 'abc'));
    console.log(convertString('abc', ''));
    console.log(convertString('catch', 'carch'));
    console.log(convertString('table', 'tbres'));
    
  4. zero one knapsack problem

    LC 有原题,但是忘了名字是啥……如果 profit 可以分的话这道题的解法用的就是贪心。

    /**
     *
     *
     *
     *
     */
    // 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 zeroOneKnapsackProblem = (
      profifts: number[],
      weights: number[],
      capacity: number
    ) => 
      if (capacity <= 0) return 0;
      if (profifts.length === 1) 
        if (weights[0] > capacity) return 0;
    
        return profifts[0];
      
    
      let takenProfit = 0,
        takenCapacity = 0;
    
      if (capacity > weights[0]) 
        takenCapacity = capacity - weights[0];
        takenProfit += profifts[0];
      
    
      return Math.max(
        zeroOneKnapsackProblem(profifts.slice(1), weights.slice(1), capacity),
        takenProfit +
          zeroOneKnapsackProblem(
            profifts.slice(1),
            weights.slice(1),
            takenCapacity
          )
      );
    ;
    
    console.log(zeroOneKnapsackProblem([31, 26, 17, 72], [3, 1, 2, 5], 7));
    
  5. longest common subsequence

    /**
     *
     *
     *
     *
     */
    // longest common subsequence
    // problem
    // s1 and s2 are string
    // find longest common subsequence which is common to both strings
    // subsequence - a sequence that can be driven from another sequence by deleting some elements
    //               without changing the order of them
    // ex: "elephant", "erepat", res = "eepat"
    const longestCommonSubsequence = (s1: string, s2: string): string => 
      if ((!s1.length && s2.length) || (s1.length && !s2.length)) return '';
      if (s1.length === 1 && s2.length === 1) 
        if (s1 === s2) return s1 === s2 ? s1 : '';
      
    
      if (s1[0] === s2[0])
        return (
          s1[0] + longestCommonSubsequence(s1.substring(1), s2.substring(1))
        );
    
      const deleteS1 = longestCommonSubsequence(s1.substring(1), s2);
      const deleteS2 = longestCommonSubsequence(s1, s2.substring(1));
    
      if (deleteS1.length > deleteS2.length) return deleteS1;
    
      return deleteS2;
    ;
    
    console.log(longestCommonSubsequence('elephant', 'erepat'));
    console.log(longestCommonSubsequence('elephant', 'erepatadadfasd'));
    

    另一种解法,就返回 LCS 的长度而不是 LCS,本质上没啥区别

    /**
     *
     *
     *
     *
     */
    const findLCS = (s1: string, s2: string): number => 
      if ((!s1.length && s2.length) || (s1.length && !s2.length)) return 0;
      if (s1.length === 1 && s2.length === 1) return s1 === s2 ? 1 : 0;
      if (s1[0] === s2[0]) return 1 + findLCS(s1.substring(1), s2.substring(1));
    
      return Math.max(
        findLCS(s1.substring(1), s2.substring(0)),
        findLCS(s1.substring(0), s2.substring(1))
      );
    ;
    
    console.log(findLCS('elephant', 'erepat'));
    
  6. longest palindrome subsquence

    /**
     *
     *
     *
     *
     */
    // longest palindrome subsquence
    // problem
    // s is given string
    // find longest palindrome subsequence
    // subsequence - a sequence that can be driven from another sequence by deleting some elements
    //               without changing the order of them
    // ex: "elrmenmet", res = "ememe" or "emnme", length 5
    const findLPS = (s: string): string => 
      if (s.length === 1) return s;
      if (s.length === 2) 
        if (s[0] === s[1]) return s;
    
        return s[0];
      
    
      if (s[0] === s[s.length - 1])
        return s[0] + findLPS(s.substring(1, s.length - 1)) + s[s.length - 1];
    
      const deleteS1 = findLPS(s.substring(1));
      const deleteS2 = findLPS(s.substring(0, s.length - 1));
    
      if (deleteS1.length > deleteS2.length) return deleteS1;
    
      return deleteS2;
    ;
    
    console.log(findLPS('elrmenmet'));
    
  7. minimum cost to reach the last cell

    应该就是 Manhattan Tourist Problem 的简化版,毕竟 Manhattan Tourist Problem 的移动方向更多来着

    /**
     *
     *
     *
     *
     */
    // minimum cost to reach the last cell
    // problem
    // - 2d Matrix is given
    // - each cell has a cost associated with it for accessing
    // - need to start from (0, 0) and reaches (n - 1, n - 1)
    // - only righ or down from current cell
    // - find the way in which the cost is minimum
    // ex:
    // [[4, 7, 8, 6, 4]
    //  [6, 7, 3, 9, 2]
    //  [3, 8, 1, 2, 4]
    //  [7, 1, 7, 3, 7]
    //  [2, 9, 8, 9, 3]]
    // res: 36, 4 --> 6 --> 7 --> 3 --> 1 --> 2 --> 3 --> 7 --> 3
    // min(currCost + f(down), currCost + f(right))
    const minCostToReachLastCell = (matrix: number[][]): number => 
      const recursiveCall = (i: number, j: number): number => 
        if (i === matrix.length - 1 && j === matrix[0].length - 1)
          return matrix[i][j];
    
        if (i === matrix.length || j === matrix[0].length) return Infinity;
    
        const moveRight = recursiveCall(i, j + 1),
          moveDown = recursiveCall(i + 1, j);
    
        return matrix[i][j] + Math.min(moveRight, moveDown);
      ;
    
      return recursiveCall(0, 0);
    ;
    
    console.log(
      minCostToReachLastCell([
        [4, 7, 8, 6, 4],
        [6, 7, 3, 9, 2],
        [3, 8, 1, 2, 4],
        [7, 1, 7, 3, 7],
        [2, 9, 8, 9, 3],
      ])
    );
    
  8. number of paths to reach the last cell with given cost

    和上一题解法差不多,换汤不换药

    /**
     *
     *
     *
     *
     */
    // problem
    // - 2D matrix is given
    // - Each cell has a cost associated with it for accessing
    // - start from (0, 0) and reaches (n - 1, n - 1)
    // - can only move right or down
    // - total cost to reach last cell is given
    // - find # of paths to reach the end of matrix with given cost
    // ex:
    // matrix = [
    //  [4, 7, 1, 6],
    //  [5, 7, 3, 9],
    //  [3, 2, 1, 2],
    //  [7, 1, 6, 3],
    // ]
    // totalCost = 25
    // res = 2:
    //  - 4 --> 7 --> 1 --> 3 --> 1 --> 6 --> 3
    //  - 4 --> 4 --> 7 --> 3 --> 1 --> 2 --> 3
    const numOfWaysToReachEnd = (matrix: number[][], cost: number): number => 
      const recursiveCall = (
        i: number,
        j: number,
        totalCost: number
      ): number => 
        if (totalCost < 0) return 0;
    
        if (i === matrix.length - 1 && j === matrix[0].length - 1) 
          if (totalCost === 0) return 1;
          return 0;
        
    
        if (i === matrix.length || j === matrix[0].length) return 0;
    
        return (
          recursiveCall(i + 1, j, totalCost - matrix[i][j]) +
          recursiveCall(i, j + 1, totalCost - matrix[i][j])
        );
      ;
    
      return recursiveCall(0, 0, cost);
    ;
    
    console.log(
      numOfWaysToReachEnd(
        [
          [4, 7, 1, 6],
          [5, 7, 3, 9],
          [3, 2, 1, 2],
          [7, 1, 6, 3],
        ],
        25
      )
    );
    

以上是关于一些分治的练习题的主要内容,如果未能解决你的问题,请参考以下文章

一些分治的练习题

算法有关点分治的一些理解与看法

最大子数组问题的几种解法

字符串类型的题----------南蛮图腾(分治解法)

LeetCode Array Easy 53. Maximum Subarray 个人解法 和分治思想的学习

浅谈数据结构题的几个非经典解法有感