导弹拦截
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是 \le 50000≤50000 的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
解: 第一问算法原型是求最长递减子序列的长度。 学习记录的上一个文章是求最长递增子序列,稍微改一下即可
const minLength = (arr) => {
const dp = [{
key: arr[0],
val: 1
}]
for (let i = 1; i < arr.length; i++) {
findSmallAndClosest(arr[i])
}
return dp[dp.length - 1].val
function findSmallAndClosest(target) {
let left = 0
let right = dp.length - 1
let res = -1
while (left <= right) {
const mid = ~~((left + right) / 2)
if (dp[mid].key <= target) {
res = mid
right = mid - 1
} else {
left = mid + 1
}
}
if (res === -1) {
dp[dp.length] = {
key: target,
val: dp[dp.length - 1].val + 1
}
} else {
dp[res].key = target
}
}
}
第二问: 计算一轮最长递减子数组之后元素移除,再接着计算此时的最长递减子数组,直到数组清空,最长递减子数组的个数就是需要多少个拦截系统。但是这种方法需要重复遍历,并且会修改数组。
贪心解: 遍历数组,碰到一个导弹就选择刚好比它高的拦截系统去匹配它,若没有比它高的就配置一个新的拦截系统。
const getMinNum = (arr) => {
const interceptArr = []
for (let i = 0; i < arr.length; i++) {
find(arr[i])
}
return interceptArr.length
function find(target) {
let left = 0
let right = interceptArr.length - 1
let res = -1
while (left <= right) {
const mid = ~~((left + right) / 2)
if (interceptArr[mid] >= target) {
res = mid
right = mid - 1
} else {
left = mid + 1
}
}
if (res === -1) {
interceptArr[interceptArr.length] = target
} else {
interceptArr[res] = target
}
}
}