1

Example: 3 1 2 7 5 8 6 9 4

v1.0.0

Cycle from front to back to find all the possibilities

 const arr = [3, 1, 2, 7, 5, 8, 6, 9, 4]
for (let i = 0; i < arr.length; i++) {
    const n = arr[i]
    console.log(i, n)
    // todo
}

i = 0, longest possible combination:

 3 ... // i = 0, n = 3

i = 1, longest possible combination:

 3 ... // i = 0, n = 3
1 ... // i = 1, n = 1

i = 2, longest possible combination:

 3 ...   // i = 0, n = 3
1 ...   // i = 1, n = 1
1 2 ... // i = 2, n = 2

And so on:
i = 9, final combination:

 0 1 2 3 4 // 序号

3         // i = 0, n = 3
1         // i = 1, n = 1
1 2       // i = 2, n = 2
1 2 7     // i = 3, n = 7
1 2 5     // i = 4, n = 5
1 2 7 8   // i = 5, n = 8
1 2 5 8
1 2 5 6   // i = 6, n = 6
1 2 7 8 9 // i = 7, n = 9
1 2 5 8 9
1 2 5 6 9
1 2 4     // i = 8, n = 4

The longest increasing subsequence found is 1 2 7 8 9, 1 2 5 8 9, 1 2 5 6 9

v2.0.0

we can find out that

 1 2 7 ...
1 2 5 ...

The possibility that 1 2 5 can bring includes all the possibilities that 1 2 7 can bring

 1 2 5 8 ...
1 2 5 6 ...

The possibilities that 1 2 5 6 can bring include all the possibilities that 1 2 5 8 can bring

So we only need to use the minimum value under the same sequence number

Take i = 5, n = 8 as an example:

 0 1 2 // 序号

3 ...
1 ...
1 2 ...
1 2 7 ...
1 2 5 ...

become

 3 ...
1 ...
1 2 ...
1 2 7 ...
1 2 5 ...
1 2 5 8 ...

Serial number 2, the corresponding value [7, 5], the minimum value is 5, only 1 2 5 is used here

The final combination of the above:

 3         // i = 0, n = 3
1         // i = 1, n = 1
1 2       // i = 2, n = 2
1 2 7     // i = 3, n = 7
1 2 5     // i = 4, n = 5
1 2 5 8   // i = 5, n = 8
1 2 5 6   // i = 6, n = 6
1 2 5 6 9 // i = 7, n = 9
1 2 4     // i = 8, n = 4

The longest increasing subsequence is found to be 1 2 5 6 9. When the data is too large, the number of loops is greatly reduced

Note: If we want to find all the possibilities, we can only sacrifice performance, but in many cases, we only need to find the longest one of them, for example: Vue's virtual node comparison

v3.0.0

In the previous example, each time we need to find the smallest bit under the corresponding serial number, and then compare it. In fact, we can record the minimum value under each serial number in an array (min_arr).

 0 1 2 3 4 // 序号

3         // i = 0, n = 3, min_arr = [3]
1         // i = 1, n = 1, min_arr = [1]
1 2       // i = 2, n = 2, min_arr = [1, 2]
1 2 7     // i = 3, n = 7, min_arr = [1, 2, 7]
1 2 5     // i = 4, n = 5, min_arr = [1, 2, 5]
1 2 5 8   // i = 5, n = 8, min_arr = [1, 2, 5, 8]
1 2 5 6   // i = 6, n = 6, min_arr = [1, 2, 5, 6]
1 2 5 6 9 // i = 7, n = 9, min_arr = [1, 2, 5, 6, 9]
1 2 4     // i = 8, n = 4, min_arr = [1, 2, 4, 6, 9]

From v2.0.0, we only need to compare with the minimum value of each serial number, that is, the current n is directly compared with min_arr

Ideas:

  1. If the current n is larger than the last item of min_arr, put it directly at the end, such as: i = 3, n = 7, 7 is larger than 2, and 7 is placed directly after 2
  2. If the current n is smaller than the last item of min_arr, loop min_arr from back to front until you find an item smaller than n, and put n behind it. At this time, the original item behind it must be larger than n, so replace the original item behind it. Item; such as: i = 8, n = 4, keep looking forward, 2 is smaller than 4, stop the loop, 4 is placed behind 2, the original 5 after 2 must be larger than 4, otherwise it should end at 5 , so directly replace the original 5 (the code will use the binary search method )

v4.0.0

At this time, we found that although the final value of min_arr is incorrect, the value of the last digit must be correct. If we change our thinking, mark who is behind the last digit, and then mark it forward layer by layer. , does this thing happen, such as

 0 1 2 3 4 // 序号

3         // i = 0, n = 3, min_arr = [3], 3前面为undefined
1         // i = 1, n = 1, min_arr = [1], 1前面为undefined
1 2       // i = 2, n = 2, min_arr = [1, 2], 2前面为1
1 2 7     // i = 3, n = 7, min_arr = [1, 2, 7], 7前面为2
1 2 5     // i = 4, n = 5, min_arr = [1, 2, 5], 5前面为2
1 2 5 8   // i = 5, n = 8, min_arr = [1, 2, 5, 8], 8前面为5
1 2 5 6   // i = 6, n = 6, min_arr = [1, 2, 5, 6], 6前面为5
1 2 5 6 9 // i = 7, n = 9, min_arr = [1, 2, 5, 6, 9], 9前面为6
1 2 4     // i = 8, n = 4, min_arr = [1, 2, 4, 6, 9], 4前面为2

First find 9, then 6, then 5, then 2, then 1, then the longest increasing subsequence found is 1 2 5 6 9

finally

In the program, we need to map the value to an index to better find its position

 0 1 2 3 4 5 6 7 8 // 索引
3 1 2 7 5 8 6 9 4 // 值

The above v4.0.0 becomes

 0 1 2 3 4 // 序号

0         // i = 0, min_arr = [0], 0前面为undefined
1         // i = 1, min_arr = [1], 1前面为undefined
1 2       // i = 2, min_arr = [1, 2], 2前面为1
1 2 3     // i = 3, min_arr = [1, 2, 3], 3前面为2
1 2 4     // i = 4, min_arr = [1, 2, 4], 4前面为2
1 2 4 5   // i = 5, min_arr = [1, 2, 4, 5], 5前面为4
1 2 4 6   // i = 6, min_arr = [1, 2, 4, 6], 6前面为4
1 2 4 6 7 // i = 7, min_arr = [1, 2, 4, 6, 7], 7前面为6
1 2 8     // i = 8, min_arr = [1, 2, 8, 6, 7], 8前面为2

First find the index 7, then 6, then 4, then 2, then 1. At this time, the index is 1 2 4 6 7, and the corresponding longest increasing subsequence value is 1 2 5 6 9

source code

 function getSequence(arr:number[]) {
  const len = arr.length
  const min_arr = [0] // 存储最小的索引,以索引0为基准
  const prev_arr = arr.slice() // 储存前面的索引,slice为浅复制一个新的数组
  let last_index
  let start
  let end
  let middle
  for (let i = 0; i < len; i++) {
    let arrI = arr[i]
    // 1. 如果当前n比min_arr最后一项大
    last_index = min_arr[min_arr.length - 1]
    if (arr[last_index] < arrI) {
      min_arr.push(i)
      prev_arr[i] = last_index // 前面的索引
      continue
    }
    // 2. 如果当前n比min_arr最后一项小(二分类查找)
    start = 0
    end = min_arr.length - 1
    while(start < end) {
      middle = (start + end) >> 1 // 相当于Math.floor((start + end)/2)
      if (arr[min_arr[middle]] < arrI) {
        start = middle + 1
      } else  {
        end = middle
      }
    }
    if (arr[min_arr[end]] > arrI) {
      min_arr[end] = i
      if (end > 0) {
        prev_arr[i] = min_arr[end - 1] // 前面的索引
      }
    }
  }

  // 从最后一项往前查找
  let result = []
  let i = min_arr.length
  let last = min_arr[i - 1]
  while(i-- > 0) {
    result[i] = last
    last = prev_arr[last]
  }

  return result
}

console.log(getSequence([3, 1, 2, 7, 5, 8, 6, 9, 4]))
// 索引:[ 1, 2, 4, 6, 7 ]
// 值: [ 1, 2, 5, 6, 9 ]

zhaowenyin
369 声望22 粉丝

我会修电脑


« 上一篇
vue3的diff算法