从具有 O(n) 的数组中获取最大的时间顺序下降、最小值和最大值
Get the biggest chronological drop, min and max from an array with O(n)
我写了一个 javascript 函数来分析数组中最大的落差。但是还有一个小问题。作为最大值,我总是从我的孔阵列而不是我的下降中获得最大值。
示例:
数组:[100,90,80,120]
最大下降值在 100 到 80 之间。因此最大值必须为 100,最小值必须为 80。我的函数总是 returns 整个数组中的最大值。在我的情况下 120
function checkData(data) {
let max = 0
let min = 0
let drop = 0
for (let i = 0; i < data.length; i++) {
if (max < data[i]) {
max = data[i] //?
} else {
let tempDrop = max - data[i]
drop = Math.max(tempDrop, drop)
min = max - drop
}
}
return [max, min, drop]
}
我想得到从左到右按时间顺序正确的最大增量
这完全符合预期(按照您的预期输出),如以下代码片段所示。
问题一定在于您如何将数据作为数组发送。
alert(checkData([100, 90, 80, 120]));
function checkData(data) {
let max = 0
let min = 0
let drop = 0
for (let i = 0; i < data.length; i++) {
if (max < data[i]) {
max = data[i] //?
} else {
let tempDrop = max - data[i]
drop = Math.max(tempDrop)
min = max - drop
}
}
return [max, min, drop]
}
// Output : 120, 80, 20
但是,如果您要查找的是最大值、最小值,然后是最大值和最小值之间的最大差异,在您给出的示例中为 40,那么您可以简单地执行此操作。
alert(checkData([100, 90, 80, 120]));
function checkData(data) {
let max = data.reduce(function(a, b) {
return Math.max(a, b);
});
let min = data.reduce(function(a, b) {
return Math.min(a, b);
});
let drop = max-min;
return [max, min, drop];
}
// Output : 120, 80, 40
我只提到这个,因为我不知道为什么你说你期望最大的差异是 20,给定 100 和 80,当你在同一个数组中有 120 和 80 时,这意味着最大的差异是40.
您需要跟踪两件事:
- 一个元素的最大值
i
。
- 从元素
i
到列表末尾的最小值。
然后您只需要找出每个指数的跌幅,select哪个指数最大。
代码如下:
function maxDrop (data) {
if (!data || data.length === 0) {
return;
}
const max = [];
const min = [];
for (let i = 0; i < data.length; i++) {
const left = data.slice(0, i);
const right = data.slice(i, data.length);
max.push(Math.max.apply(null, left));
min.push(Math.min.apply(null, right));
}
let maxDrop = max[0] - min[0];
let maxValue = max[0];
let minValue = min[0];
for (let j = 0; j < data.length; j++) {
const drop = max[j] - min[j];
if (maxDrop < drop) {
maxDrop = drop;
maxValue = max[j];
minValue = min[j];
}
}
return [maxValue, minValue, maxDrop];
}
console.log(maxDrop([100,90,80,120]))
console.log(maxDrop([100,110,120,300,200,70,60,50,90,400]))
console.log(maxDrop([100,90,80,120,30]))
您需要迭代数组一次 (O(n)
) 并保持 运行 的最小值和最大值计数,并且:
- 每次值增加时重置它 w.r.t。之前的值
- 但如果差异大于之前记录的值,请记下它们
function checkData(array) {
var currentmax = array[0];
var currentmin = array[0];
var overallmax = array[0];
var overallmin = array[0];
var i;
for (i = 1; i < array.length; i++) {
if (array[i] <= array[i - 1]) {
// value is same or decreased
currentmin = array[i];
} else {
// check if previous iteration was the largest
if (currentmax - currentmin > overallmax - overallmin) {
overallmax = currentmax;
overallmin = currentmin;
}
// restart
currentmax = array[i];
currentmin = array[i];
}
}
// check if last iteration was the largest
if (currentmax - currentmin > overallmax - overallmin) {
overallmax = currentmax;
overallmin = currentmin;
}
return [overallmax, overallmin, overallmax - overallmin];
}
console.log(checkData([100, 90, 80, 120]));
console.log(checkData([100, 90, 80, 120, 200, 100, 90]));
console.log(checkData([10, 100, 50, 50, 10, 100, 50, 50, 1]));
听起来您希望 returned 最大值和最小值与计算最大跌幅时使用的值相同,而不是总体最大值和最小值。在这种情况下,只需添加一个额外的变量来存储更新 drop 时的变量。替换
drop = Math.max(tempDrop, drop)
使用 if 语句(伪代码):
if current_drop is greater than stored_drop:
stored_drop = current_drop
stored_max_min = current max and min
然后 return 额外存储的最大值和最小值。
你的循环应该跟踪当前的下降并将它与之前最大的下降进行比较。您可以通过跟踪索引来做到这一点:
function checkData(data) {
let bestDropStart = 0
let bestDropEnd = 0
let bestDrop = 0
let currentDropStart = 0
let currentDropEnd = 0
let currentDrop = 0
for (let i = 1; i < data.length; i++) {
if (data[i] < data[i - 1]) {
// we are dropping
currentDropEnd = i
currentDrop = data[currentDropStart] - data[i]
} else {
// the current drop ended; check if it's better
if (currentDrop > bestDrop) {
bestDrop = currentDrop
bestDropStart = currentDropStart
bestDropEnd = currentDropEnd
}
// start a new drop
currentDropStart = currentDropEnd = i
currentDrop = 0
}
}
// check for a best drop at end of data
if (currentDrop > bestDrop) {
bestDrop = currentDrop
bestDropStart = currentDropStart
bestDropEnd = currentDropEnd
}
// return the best drop data
return [data[bestDropStart], data[bestDropEnd], bestDrop]
}
console.log(checkData([100, 90, 80, 120]))
console.log(checkData([100, 90, 80, 120, 30]))
console.log(checkData([70, 100, 90, 80]))
console.log(checkData([100, 90, 80, 120, 30, 50]))
您也可以只保留当前和最佳下降的开始值和结束值,但我更喜欢明确跟踪索引。这样对我来说似乎更清楚(更容易调试和维护)。
要再添加一个..
一种可能的方法是先创建所有下降范围,然后再创建下降幅度最大的范围
减少版本:
function checkData(data) {
let dropInd = 1,
mx = data.reduce((arr,val, ind) => {
if(ind && val > data[ind-1])dropInd++;
arr[dropInd] = arr[dropInd] || {max:val};
arr[dropInd].min = val;
arr[dropInd].drop = arr[dropInd].max - val;
return arr;
}, []) //after reduce, islands are created based on 'dropInd'
.sort((v1,v2)=>v2.drop - v1.drop) //sort by drop descending
[0]; //the first value now contains the maximum drop
return [mx.max,mx.min,mx.drop];
}
console.log(checkData([100, 90, 80, 120]));
console.log(checkData([100, 90, 80, 120, 200, 100 ,90]));
console.log(checkData([200,100, 90, 80, 120, 100 ,90]));
console.log(checkData([200,120,190, 90, 80, 120, 100 ,90]));
我写了一个 javascript 函数来分析数组中最大的落差。但是还有一个小问题。作为最大值,我总是从我的孔阵列而不是我的下降中获得最大值。
示例: 数组:[100,90,80,120]
最大下降值在 100 到 80 之间。因此最大值必须为 100,最小值必须为 80。我的函数总是 returns 整个数组中的最大值。在我的情况下 120
function checkData(data) {
let max = 0
let min = 0
let drop = 0
for (let i = 0; i < data.length; i++) {
if (max < data[i]) {
max = data[i] //?
} else {
let tempDrop = max - data[i]
drop = Math.max(tempDrop, drop)
min = max - drop
}
}
return [max, min, drop]
}
我想得到从左到右按时间顺序正确的最大增量
这完全符合预期(按照您的预期输出),如以下代码片段所示。
问题一定在于您如何将数据作为数组发送。
alert(checkData([100, 90, 80, 120]));
function checkData(data) {
let max = 0
let min = 0
let drop = 0
for (let i = 0; i < data.length; i++) {
if (max < data[i]) {
max = data[i] //?
} else {
let tempDrop = max - data[i]
drop = Math.max(tempDrop)
min = max - drop
}
}
return [max, min, drop]
}
// Output : 120, 80, 20
但是,如果您要查找的是最大值、最小值,然后是最大值和最小值之间的最大差异,在您给出的示例中为 40,那么您可以简单地执行此操作。
alert(checkData([100, 90, 80, 120]));
function checkData(data) {
let max = data.reduce(function(a, b) {
return Math.max(a, b);
});
let min = data.reduce(function(a, b) {
return Math.min(a, b);
});
let drop = max-min;
return [max, min, drop];
}
// Output : 120, 80, 40
我只提到这个,因为我不知道为什么你说你期望最大的差异是 20,给定 100 和 80,当你在同一个数组中有 120 和 80 时,这意味着最大的差异是40.
您需要跟踪两件事:
- 一个元素的最大值
i
。 - 从元素
i
到列表末尾的最小值。
然后您只需要找出每个指数的跌幅,select哪个指数最大。
代码如下:
function maxDrop (data) {
if (!data || data.length === 0) {
return;
}
const max = [];
const min = [];
for (let i = 0; i < data.length; i++) {
const left = data.slice(0, i);
const right = data.slice(i, data.length);
max.push(Math.max.apply(null, left));
min.push(Math.min.apply(null, right));
}
let maxDrop = max[0] - min[0];
let maxValue = max[0];
let minValue = min[0];
for (let j = 0; j < data.length; j++) {
const drop = max[j] - min[j];
if (maxDrop < drop) {
maxDrop = drop;
maxValue = max[j];
minValue = min[j];
}
}
return [maxValue, minValue, maxDrop];
}
console.log(maxDrop([100,90,80,120]))
console.log(maxDrop([100,110,120,300,200,70,60,50,90,400]))
console.log(maxDrop([100,90,80,120,30]))
您需要迭代数组一次 (O(n)
) 并保持 运行 的最小值和最大值计数,并且:
- 每次值增加时重置它 w.r.t。之前的值
- 但如果差异大于之前记录的值,请记下它们
function checkData(array) {
var currentmax = array[0];
var currentmin = array[0];
var overallmax = array[0];
var overallmin = array[0];
var i;
for (i = 1; i < array.length; i++) {
if (array[i] <= array[i - 1]) {
// value is same or decreased
currentmin = array[i];
} else {
// check if previous iteration was the largest
if (currentmax - currentmin > overallmax - overallmin) {
overallmax = currentmax;
overallmin = currentmin;
}
// restart
currentmax = array[i];
currentmin = array[i];
}
}
// check if last iteration was the largest
if (currentmax - currentmin > overallmax - overallmin) {
overallmax = currentmax;
overallmin = currentmin;
}
return [overallmax, overallmin, overallmax - overallmin];
}
console.log(checkData([100, 90, 80, 120]));
console.log(checkData([100, 90, 80, 120, 200, 100, 90]));
console.log(checkData([10, 100, 50, 50, 10, 100, 50, 50, 1]));
听起来您希望 returned 最大值和最小值与计算最大跌幅时使用的值相同,而不是总体最大值和最小值。在这种情况下,只需添加一个额外的变量来存储更新 drop 时的变量。替换
drop = Math.max(tempDrop, drop)
使用 if 语句(伪代码):
if current_drop is greater than stored_drop:
stored_drop = current_drop
stored_max_min = current max and min
然后 return 额外存储的最大值和最小值。
你的循环应该跟踪当前的下降并将它与之前最大的下降进行比较。您可以通过跟踪索引来做到这一点:
function checkData(data) {
let bestDropStart = 0
let bestDropEnd = 0
let bestDrop = 0
let currentDropStart = 0
let currentDropEnd = 0
let currentDrop = 0
for (let i = 1; i < data.length; i++) {
if (data[i] < data[i - 1]) {
// we are dropping
currentDropEnd = i
currentDrop = data[currentDropStart] - data[i]
} else {
// the current drop ended; check if it's better
if (currentDrop > bestDrop) {
bestDrop = currentDrop
bestDropStart = currentDropStart
bestDropEnd = currentDropEnd
}
// start a new drop
currentDropStart = currentDropEnd = i
currentDrop = 0
}
}
// check for a best drop at end of data
if (currentDrop > bestDrop) {
bestDrop = currentDrop
bestDropStart = currentDropStart
bestDropEnd = currentDropEnd
}
// return the best drop data
return [data[bestDropStart], data[bestDropEnd], bestDrop]
}
console.log(checkData([100, 90, 80, 120]))
console.log(checkData([100, 90, 80, 120, 30]))
console.log(checkData([70, 100, 90, 80]))
console.log(checkData([100, 90, 80, 120, 30, 50]))
您也可以只保留当前和最佳下降的开始值和结束值,但我更喜欢明确跟踪索引。这样对我来说似乎更清楚(更容易调试和维护)。
要再添加一个.. 一种可能的方法是先创建所有下降范围,然后再创建下降幅度最大的范围
减少版本:
function checkData(data) {
let dropInd = 1,
mx = data.reduce((arr,val, ind) => {
if(ind && val > data[ind-1])dropInd++;
arr[dropInd] = arr[dropInd] || {max:val};
arr[dropInd].min = val;
arr[dropInd].drop = arr[dropInd].max - val;
return arr;
}, []) //after reduce, islands are created based on 'dropInd'
.sort((v1,v2)=>v2.drop - v1.drop) //sort by drop descending
[0]; //the first value now contains the maximum drop
return [mx.max,mx.min,mx.drop];
}
console.log(checkData([100, 90, 80, 120]));
console.log(checkData([100, 90, 80, 120, 200, 100 ,90]));
console.log(checkData([200,100, 90, 80, 120, 100 ,90]));
console.log(checkData([200,120,190, 90, 80, 120, 100 ,90]));