動態規劃練習題-攔截導彈

動態規劃練習題彙總segmentfault

問題描述:
某國爲了防護敵國的導彈襲擊,發展中一種導彈攔截系統。可是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈可以到達任意的高度,可是之後每一發炮彈都不能高於等於前一發的高度。某天,雷達捕捉到敵國導彈來襲。因爲該系統還在試用階段,因此只用一套系統,所以有可能不能攔截全部的導彈。
輸入:
導彈依次飛來的高度 [h1, h2, h3,...hn]
輸出:
最多能攔截的導彈數目緩存


思路:
導彈飛來,咱們能夠選擇攔截或者不攔截,但攔截第一次後,後面的攔截高度受限。一次攔截結果是成功/失敗,咱們須要將攔截成功次數score最大化。this

1 拆分子問題
一次攔截結果是成功或者失敗,score可加1或保持不變。對第i個導彈,攔截它的次序多是第1次,第2次。。。第i次,因此咱們須要計算的是第1次,第2次。。。第i次攔截的成功次數code

2 得分計算
第i次攔截的成功次數爲 S(i) = max(S(j)+shootScore(i,j+1)) ,其中,1<=j<i,shootScore(i,j+1)表示當第i個導彈飛來,咱們已經進行了j次攔截,第j+1次攔截的成功/失敗,成功爲1,失敗爲0,初始值S(1)=1遞歸

3 代碼
bottom-up algorithm
該解法的問題在於:拆分出的子問題個數是n,第i個子問題須要考慮i-1種狀況,計算shootScore(i,j+1)須要進行i-j-1次計算,因此時間複雜度爲O(n3)get

const missileArray = [389, 207, 155, 300, 299, 170, 158, 65];
class Calmissile {
  constructor(options) {
    this.score = [];
    this.missileArray = Array.isArray(options) ? options : [];
  }
  shootScore(cur, len) {
    let maxHeight = this.missileArray[cur-len];
    for (let i = cur - len; i < cur; i++){
      if (this.missileArray[i] < maxHeight) {
        maxHeight = this.missileArray[i]
      }
    }
    return this.missileArray[cur] <= maxHeight ? 1 : 0;
  }
  getScore() {
    for (let i = 0; i < this.missileArray.length; i++){
      for (let j = 0; j < i; j++){
        this.score[j] += this.shootScore(i,j+1);
      }
      this.score.unshift(1);
    }
    let result = [];
    const max = Math.max(...([].concat(this.score)));
    this.score.forEach((item, index) => {
      if (item === max) {
        result.push([index,item]);
      }
    });
    result.forEach(item => {
      console.log(`從第${item[0]}枚導彈開始攔截,能夠攔下${item[1]}枚導彈`);
    })
  }
}
new Calmissile(missileArray).getScore();

bottom-up DP+ memorize
不難發現時間複雜度爲O(n3)的解法中,shootScore有大量的重複計算,所以咱們能夠緩存score和maxHeight,減小計算量it

const missileArray = [389, 207, 155, 300, 299, 170, 158, 65];
class Calmissile {
  constructor(options) {
    this.maxScore = 1;
    this.missileArray = Array.isArray(options) ? options : [];
  }
  getScoreMemorize() {
    let memorize = [{ id: 0, score: 1, maxHeight: this.missileArray[0]}];
    for (let i = 1; i < this.missileArray.length; i++) {
      for (let j = 0; j < i; j++) {
        if (this.missileArray[i] <= memorize[j].maxHeight) {
          if (memorize[j].score + 1 >= this.maxScore) {
            this.maxScore = memorize[j].score + 1;
          }
          memorize[j] = {
            id: j+1,
            score: memorize[j].score+1,
            maxHeight: this.missileArray[i]
          }
        } else {
          if (memorize[j].score >= this.maxScore) {
            this.maxScore = memorize[j].score;
          }
          memorize[j] = {
            id: j+1,
            score: memorize[j].score,
            maxHeight: memorize[j].maxHeight
          }
        }
      }
      memorize.unshift({ id: 0, score: 1, maxHeight: this.missileArray[i] });
    }
    let logs = [];
    memorize.forEach((item, index) => {
      if (item.score === this.maxScore) {
        logs.push([index, item.score]);
      }
    });
    logs.forEach(item => {
      console.log(`從第${item[0]}枚導彈開始攔截,能夠攔下${item[1]}枚導彈`);
    })
  }
  
}

new Calmissile(missileArray).getScoreMemorize();

recurssive DP
與bottom-up+memorize的思路一致,不過採用遞歸的寫法io

const missileArray = [389, 207, 155, 300, 299, 170, 158, 65];
class Calmissile {
  constructor(options) {
    this.maxScore = 1;
    this.missileArray = Array.isArray(options) ? options : [];
  }
  getScoreRecurssive() {
    let logs = [];
    const result = this.getScoreV2(this.missileArray.length - 1);
    result.forEach((item, index) => {
      if (item.score === this.maxScore) {
        logs.push([index, item.score]);
      }
    });
    logs.forEach(item => {
      console.log(`從第${item[0]}枚導彈開始攔截,能夠攔下${item[1]}枚導彈`);
    })
  }
  getScoreV2(n) {
    if (n === 0) {
      return [{
        id: 0,
        score: 1,
        maxHeight: this.missileArray[n]
      }]
    } else {
      let newArr = this.getScoreV2(n - 1).map((item,index) => {
        if (this.missileArray[n] <= item.maxHeight) {
          if (item.score+1 >= this.maxScore) {
            this.maxScore = item.score+1;
          }
          return {
            id: index+1,
            score: ++item.score,
            maxHeight: this.missileArray[n]
          }
        } else {
          if (item.score >= this.maxScore) {
            this.maxScore = item.score;
          }
          return {
            id: index+1,
            score: item.score,
            maxHeight: item.maxHeight
          }
        }
      });
      newArr.unshift({
        id: 0,
        score: 1,
        maxHeight: this.missileArray[n]
      });
      return newArr;
    }
  }
}
new Calmissile(missileArray).getScoreRecurssive();

4 時間複雜度
拆分出的子問題個數是n,第i個子問題須要計算i次新的score和maxHeight,故時間複雜度爲O(n2)console

相關文章
相關標籤/搜索