動態規劃練習題-數字三角形

動態規劃練習題彙總segmentfault

問題描述:this

clipboard.png

在上面的數字三角形中尋找一條從頂部到底邊的路徑,使得路徑上所通過的數字之和最大。
路徑上的每一步都只能往左下或 右下走。只須要求出這個最大和便可,沒必要給出具體路徑。 三角形的行數大於1小於等於100,數字爲 0 - 99spa

輸入:
三角形序列:[[7],[3,8],[8,1,0],[2,7,4,4],[4,5,2,6,5]]code

輸出:
最大和,走過的數字序列blog

1 思路
把三角形看作一個二叉樹,根節點爲第一層,往第i+1層走時,是在第i層的基礎上增長i+1個可選項,用到達第i層的路徑和加上可選項,將有最大和的可選項歸入路徑ip

2 拆分子問題
第i層的每一個節點都有其最大路徑和,往第i+1層走時,每一個節點都有兩個選項,所以能夠計算獲得第i+1層每一個節點的最大路徑和get

3 計算
以w(i)(k)表示第i層的第k個節點的值,以S(i+1)做爲到達第i+1層的最大路徑和,以Sk(i+1)做爲第i+1層第k個節點的最大路徑和,其中1<=k<=i+1,S(i+1)=max{ Sk(i) + max{w(i+1)(k),w(i+1)(k+1)}, 其中1<=k<=i}it

4 代碼
bottom-up DPconsole

const numbers = [[7], [3, 8], [8, 1, 0], [2, 7, 4, 4], [4, 5, 2, 6, 5]];
class CalTree {
  constructor(numbers) {
    this.numbers = numbers;
    this.sums = numbers.map((item,rowIndex) => {
      return item.map((item, index) => {
        return rowIndex === 0 && index === 0 ? item : 0;
      });
    });
    this.path = numbers.map(item => {
      return item.map(item => item);
    });
  }
  getSum() {
    for (let i = 0;i<this.numbers.length-1; i++){
      let nextSums = this.sums[i+1];
      let curSums = this.sums[i];
      let nextItems = this.numbers[i + 1];
      for (let index = 0; index < curSums.length; index++){
        const item = curSums[index];
        const temp1 = item + nextItems[index];
        if (temp1 > nextSums[index]) {
          nextSums[index] = temp1;
          this.path[i+1][index] = [].concat(this.path[i][index], nextItems[index]);
        }
        const temp2 = item + nextItems[index + 1];
        if (temp2 > nextSums[index + 1]) {
          nextSums[index + 1] = temp2;
          this.path[i+1][index + 1] = [].concat(this.path[i][index], nextItems[index + 1]);
        }
      }
    }
    const lastSumArr = this.sums[this.sums.length - 1];
    const lastPathArr = this.path[this.sums.length - 1];
    let maxSum = 0, maxSumPath = [];
    lastSumArr.forEach((item,index) => {
      if (item > maxSum) {
        maxSum = item;
        maxSumPath = lastPathArr[index];
      }
    });
    console.log("最大和是:", maxSum, ", 路徑爲:", maxSumPath.join(","));
  }
}
new CalTree(numbers).getSum();

recurssive DPast

const numbers = [[7], [3, 8], [8, 1, 0], [2, 7, 4, 4], [4, 5, 2, 6, 5]];
class CalTree {
  constructor(numbers) {
    this.numbers = numbers;
    this.sums = numbers.map((item,rowIndex) => {
      return item.map((item, index) => {
        return rowIndex === 0 && index === 0 ? item : 0;
      });
    });
    this.path = [].concat(numbers);
  }
  getSumRecursive() {
    let lastArr = this.sums[this.sums.length - 1];
    for (let i = 0; i < lastArr.length; i++){
      this.cal(this.sums.length - 1, i);
    }
    const lastSumArr = this.sums[this.sums.length - 1];
    const lastPathArr = this.path[this.sums.length - 1];
    let maxSum = 0, maxSumPath = [];
    lastSumArr.forEach((item, index) => {
      if (item > maxSum) {
        maxSum = item;
        maxSumPath = lastPathArr[index];
      }
    });
    console.log("最大和是:", maxSum, ", 路徑爲:", maxSumPath.reverse().join(","));
  }
  cal(depth, index) {
    if (this.sums[depth][index]) {
      return this.sums[depth][index];
    }
    const curItem = this.numbers[depth][index];
    const upSums = this.sums[depth - 1];
    const temp = [].concat(this.path[depth][index]);
    if (index > 0) {
      const temp2 = this.cal(depth - 1, index - 1) + curItem;
      if (temp2 > this.sums[depth][index]) {
        this.sums[depth][index] = temp2;
        this.path[depth][index] = [].concat(temp, this.numbers[depth - 1][index - 1]);
      }
    }
    if (index < upSums.length) {
      const temp1 = this.cal(depth - 1, index) + curItem;
      if (temp1 > this.sums[depth][index]) {
        this.sums[depth][index] = temp1;
        this.path[depth][index] = [].concat(temp, this.numbers[depth - 1][index]);
      }
    }
    return this.sums[depth][index];
  }

}
new CalTree(numbers).getSumRecursive();

5 時間複雜度令三角形的數字個數爲n,能夠發現,除了最底行,其餘行的每一個數字僅參與兩次計算,故時間複雜度爲O(n)

相關文章
相關標籤/搜索