動態規劃練習題-合唱隊形

動態規劃練習題彙總segmentfault

題目描述
N位同窗站成一排,音樂老師要請其中的(N-K)位同窗出列,使得剩下的K位同窗不交換位置就能排成合唱隊形。
合唱隊形定義:設K位同窗從左到右依次編號爲1, 2, …, K,他們的身高分別爲T1, T2, …, TK,
則他們的身高知足T1 < T2 < … < Ti, Ti > Ti+1 > … > TK (1 <= i <= K)。
要求:已知全部N位同窗的身高,計算最少須要幾位同窗出列,能夠使得剩下的同窗排成合唱隊形。
輸入
同窗的身高序列,序列長度爲N,如[186,186,150,200,160,130,197,220]
輸出
就是最少須要幾位同窗出列this


1 思路
尋找一個同窗,其左邊同窗的身高遞增序列+其右邊同窗的身高遞減序列是最長的,該問題難點在於如何計算一個序列的最長遞增/遞減序列code

2 拆分子問題
須要找到以序列中每一個元素開始到序列尾的序列的最長遞增/遞減序列,這些序列中最長的即爲整個序列的最長遞增/遞減序列,子問題就是序列[i:n-1]的最長遞增/遞減序列,其中 0<=i<nget

3 計算
對一個序列[0,k]來講,第i個元素的最長遞增序列A(i)=maxLength{ [序列i,shouldAdd(A(j)),其中i<j<k]},當序列i<序列j,shouldAdd(A(j))=A(j),不然shouldAdd(A(j))=nullit

4 代碼
bottom-up DPio

const heightArray = [186,186,150,200,160,130,197,220];
class CalHeight {
  constructor(options) {
    this.heightArray = Array.isArray(options) ? options : [];
  }
  getScoreMemorize() {
    let maxArr = [];
    for (let i = 0; i < this.heightArray.length; i++) {
      const left = this.getMaxAscend(this.heightArray.slice(0, i + 1));
      const right = this.getMaxAscend(this.heightArray.slice(i, this.heightArray.length).reverse()).reverse();
      const newArr = [...new Set(left.concat(right))];
      if (newArr.length > maxArr.length) {
        maxArr = newArr;
      }
    }
    console.log(`最少須要 ${this.heightArray.length - maxArr.length} 位同窗出列,留在隊裏的同窗的身高是${maxArr.join()}`);
  }
  getMaxAscend(arr){
    let ascendArr = [];
    for (let i = arr.length - 1; i >= 0; i--){
      let maxArr = [];
      ascendArr[i] = {
        id: i,
        value: arr[i],
        arr: [arr[i]]
      };
      for (let j = i + 1; j < arr.length; j++){
        if (arr[i] < ascendArr[j].value) {
          if (ascendArr[j].arr.length > maxArr.length) {
            maxArr = ascendArr[j].arr;
          }
        }
      }
      ascendArr[i].arr = ascendArr[i].arr.concat(maxArr);
    }
    let result = [];
    ascendArr.forEach(item => {
      if (item.arr.length > result.length) {
        result = item.arr;
      }
    });
    return result;
  }
}
new CalHeight(heightArray).getScoreMemorize();

recursive DPconsole

const heightArray = [186,186,150,200,160,130,197,220];
class CalHeight {
  constructor(options) {
    this.heightArray = Array.isArray(options) ? options : [];
  }
  getScoreRecursive() {
    let maxArr = [];
    for (let i = 0; i < this.heightArray.length; i++) {
      const left = this.getAscend(this.heightArray.slice(0, i + 1));
      const right = this.getAscend(this.heightArray.slice(i, this.heightArray.length).reverse()).reverse();
      const newArr = [...new Set(left.concat(right))];
      if (newArr.length > maxArr.length) {
        maxArr = newArr;
      }
    }
    console.log(`最少須要 ${this.heightArray.length - maxArr.length} 位同窗出列,留在隊裏的同窗的身高是${maxArr.join()}`);
  }
  getAscend(arr) {
    let max = [];
    let memo = {};
    this.getAscendRecursive(arr,0,memo);
    Object.keys(memo).forEach(item => {
      if (memo[item].arr.length > max.length) {
        max = memo[item].arr;
      }
    });
    return max;
  }
  getAscendRecursive(arr, n = 0, memo = {}) {
    if (memo[n]) {
      return memo[n];
    }
    if (n === arr.length - 1) {
      memo[n] = { value: arr[n], arr: [arr[n]]};
      return memo[n];
    } else {
      let max = [arr[n]];
      for (let i = n + 1; i < arr.length; i++){
        const next = this.getAscendRecursive(arr, i,memo);
        if (arr[n] < next.value) {
          if (next.arr.length >= max.length) {
            max = [].concat(arr[n], next.arr);
          }
        }
      }
      memo[n] = { value: arr[n],arr: max };
      return memo[n];
    }
  }
}
new CalHeight(heightArray).getScoreRecursive();

5 時間複雜度
對每一個同窗,都須要計算其左邊同窗的身高遞增序列+其右邊同窗的身高遞減序列;計算一個序列[0:k]的最長遞增序列,須要計算序列中每一個元素的最長遞增序列,且計算第i個元素的最長遞增序列時,須要進行k-i次比較,所以時間複雜度爲O(n3)class

相關文章
相關標籤/搜索