问:
- 给一个包含N个整数元素的集合A,一个包含M个整数元素的集合B。定义一个操作F,从一个集合取出一个元素放到另一个集合,且操作过后两个集合的平均值都上升。问最多可以进行多少次操作F
- 给一个长度N的二维数组,数组中每一项有两个元素。表示有N个任务。两个元素分别代表任务开始时间和任务结束时间。假设每个任务只需要一天就可以完成,请问是否可以每个任务都按时完成。
- 给一个无序数组,可能有正、负、0。任选两个数字相加,请返回相加后绝对值最小的值
解: 1.
function getMaxFrequency(setA,setB) {
let res = 0
// 平均值
const meanA = getMean(setA)
const meanB = getMean(setB)
// 当平均值一样时,无法满足条件
if (meanA === meanB) return 0
let bigSet = meanA > meanB ? setA : setB
let bigMean = meanA > meanB ? meanA : meanB
let smallSet = bigSet === setA ? setB : setA
let smallMean = bigMean === meanA ? meanB : meanA
// 假设是A平均值更大
while (getMean(bigSet) > getMean(smallSet)) {
// 找到 A 集合中的某个值 X ,这个值要满足 meanB < X < meanA。很明显,只有这样才能使得两个集合的平均值都上升。
// 那么可以看出X的范围是两个平均值的上下限。那么A上升的越快并且B上升的越慢则X的范围越广。
// 所以结论是取集合A中距离meanB最近 并且大于 meanB 并且不能在集合B中已存在的数,
// 给A排序取X
let minX = null
bigSet = new Set(Array.from(bigSet).sort((a,b) => a-b))
for (let i of bigSet) {
if (i > smallMean && i < bigMean && !smallSet.has(i)) {
minX = i
break
}
}
if (minX) {
res++
bigSet.delete(minX)
smallSet.add(minX)
continue
}
break
}
return res
function getMean(set) {
let mean = 0
set.forEach((item) => {
mean += item
})
mean = mean / set.size
return mean
}
}
- 遍历数组,遍历时创建两个节点,分别为开始节点和结束节点。每个节点都有任务的相关信息。把节点放入一个辅助数组,按照time排序。遍历辅助数组,当碰到开始节点时,就收集任务,把节点放入一个任务数组,并且按照任务结束时间排序。当碰到结束节点时,就按照时间差从任务数组中弹出对应数量的任务(即这么多天内做了多少任务)。如果此时任务数组中结束时间最小的任务还是小于等于当前时间,那么说明无法按时完成了,返回false。
function isCompleteTask(arr) {
const helpArr = []
const taskStack = []
for (let i of arr) {
// 开始时间节点
const startNode = {
time: i[0],
end: i[1],
type: 1 // 收集任务
}
// 结束时间节点
const endNode = {
time: i[1],
start: i[0],
type: 2 // 触发检查
}
helpArr.push(startNode,endNode)
}
helpArr.sort((a, b) => a.time - b.time)
let preDay = helpArr[0].time
for (let i of helpArr) {
// 收集任务
if (i.type === 1) {
taskStack.push(i)
}
// 触发检查
if (i.type === 2) {
// 可以做几个任务
let canDoCount = i.time - preDay
taskStack.sort((a, b) => a.end - b.end)
while (canDoCount) {
taskStack.shift()
canDoCount--
}
if (taskStack.length && taskStack[0].end <= preDay) {
return false
}
preDay = i.time
}
}
return true
}
function getMinABS(arr) {
arr.sort((a,b) => a-b)
let res = Infinity
// 首先,如果全是非负数,那么数组前两个数的和就是最小的
if (arr[0] >= 0) {
return arr[0] + arr[1]
}
// 如果全是负数,那么数组最后两个数的和就是最小的
if (arr[arr.length -1] < 0) {
return Math.abs(arr[arr.length - 1] + arr[arr.length - 2])
}
// 如果有正有非负,那么其结果就是(正数+正数),(非负+非负),(非负+负数) 三种情况中的一个
// 遍历数组,找距离每一项对应相反数最近的数。
for (let i = 0; i <arr.length;i++) {
const tempNear= getMostNear(arr, -arr[i], i)
res = Math.min(Math.abs(tempNear+arr[i]), res)
}
return res
function getMostNear(arr, target, ignoreIdx) {
arr = [...arr]
arr.splice(ignoreIdx, 1)
let tempNear = Infinity
let nearIdx = -1
let left = 0
let right = arr.length - 1
let midIdx = Math.ceil((right + left) / 2)
while (left <= right) {
if (arr[midIdx] === target) {
tempNear = arr[midIdx]
nearIdx = midIdx
break
}
if (arr[midIdx] < target) {
left = midIdx + 1
}
if (arr[midIdx] > target) {
right = midIdx - 1
}
if (Math.abs(target - arr[midIdx]) < Math.abs(target - tempNear)) {
tempNear = arr[midIdx]
nearIdx = midIdx
}
midIdx = Math.floor((right + left) / 2)
}
return tempNear
}
}