原答案
我最初的答案包括以下三个步骤。如果规范化数组中的 max 值位于规范化数组中的 min 值之前,该算法就可以工作。我考虑的样本数组是 [4, 0, 9, -2] 和 [0, 1, 3, -15]。请注意,在这两个示例数组中,max 位于 min 之前。但是,如果数组中的绝对值min 出现在绝对值max 之前,则此算法将失败。算法失败的两个例子是 [-15, 1] 和 [40, 31, 140, 131]。
第 1 步:从该索引处的值中减去数组索引
array: 4 0 9 -2
index: -0 -1 -2 -3
----------------
normalized array: 4 -1 7 -5
第 2 步:扫描归一化数组以找到最小值和最大值
max = 7
min = -5
第 3 步:从最大值中减去最小值并除以 2(必要时四舍五入),这就是您的答案
(7 - (-5)) / 2 = 6
原始答案的理由和缺陷
我最初的答案背后的想法是max 和min 之间的中点提供了一个target 值,每个 规范化数组中的条目都可以调整到命中。 max 和 min 距离 target 最远,需要最大的调整,因此提供了答案。但是,在看到 hk6279 的评论后,我意识到标准化数组可以有多个 targets。例如,考虑数组 [40, 31, 140, 131]。第一步是
array: 40 31 140 131
index: -0 -1 -2 -3
-----------------
normalized: 40 30 138 128
前两个数字的target 是35(通过+-5 的调整可以达到)。后两个数字的target 是133(也可以通过+-5 的调整达到)。所以答案是5,对数组的调整是
array: 40 31 140 131
adjustment: -5 +5 -5 +5
-----------------
sorted: 35 36 135 136
(旁注:数组[-15,1]也有两个目标。-15的目标是-15,调整为0。0的目标(1的归一化值)是0,调整0。所以答案是 0)。
更复杂(但仍为 O(n)) 的答案
第 1 步:通过从该索引处的值中减去数组索引来规范化数组。这一步与原来的答案没有变化。
第 2 步:定义一个数据结构来保存有关数组条目的信息。
struct Section
{
int max; // the maximum value seen in this section of the array
int min; // the minimum value seen in this section of the array
int startIndex; // the starting index for this section of the array
int endIndex; // the ending index for this section of the array
}
第 3 步:扫描规范化数组,同时创建 Section 结构数组。 (sectionsArray 可能和normalized 数组一样长。)sectionsArray 的创建规则是
initialize the first section as { normalized[0], normalized[0], 0, 0 }
for each subsequent entry in the normalized array
{
if ( normalized[i] > currentSection.max ) // found a larger value than the current max
{
newSection = { normalized[i], normalized[i], i, i } // create a new section and add it to the sectionsArray
currentSection = newSection // the new section is now our current section
}
else if ( normalized[i] < currentSection.min ) // found a new minimum for the current section
{
currentSection.min = normalized[i] // update the min and end of the current section
currentSection.endIndex = i;
}
else // normalized[i] is within the current range of values
{
currentSection.endIndex = i; // update the end of the current section
}
}
请注意,在这一步中,sectionsArray 中的最大值严格按照升序排列。这对下一步很重要。
第 4 步:从 sectionsArray 的末尾向后工作,尽可能合并各个部分。合并两个部分的规则是
if ( sectionsArray[i].min <= sectionsArray[i-1].min ) // bigger max and smaller min allows preceding section to be absorbed into the current section
{
sectionsArray[i-1].max = sectionsArray[i].max
sectionsArray[i-1].min = sectionsArray[i].min
sectionsArray[i-1].endIndex = sectionsArray[i].endIndex
discard sectionsArray[i]
}
第 5 步:扫描sectionsArray,找出max 和min 之间的最大差异。最大的差异,除以二并在必要时四舍五入,就是问题的答案。此外,min 和 max 之间的中点是该数组部分的目标值(可以截断目标值)。
一个例子
考虑数组 [8,5,8,6,14,12,18,13]。首先对数组进行归一化:
Input array: 8 5 8 6 14 12 18 13
index: -0 -1 -2 -3 -4 -5 -6 -7
------------------------------
Normalized: 8 4 6 3 10 7 12 6
然后创建sections数组:
{ 8, 3, 0, 3 } // started with 8, 4 became the min, 6 was in range, 3 replaced 4 as the min. 10 ended the section since it was higher than 8
{ 10, 7, 4, 5 } // started with 10, 7 became the min. 12 ended the section.
{ 12, 6, 6, 7 }
向后工作:10,7 部分可以吸收到 12,6 部分中,导致
{ 8, 3, 0, 3 }
{ 12, 6, 4, 7 }
最大差是6,所以答案是3。
第一部分的目标是 (8+3)/2 = 5(截断后)
第二部分的目标是 (12+6)/2 = 9
调整如下:
Normalized: 8 4 6 3 10 7 12 6
Adjustments: -3 1 -1 2 -1 2 -3 3
-------------------------------
Targets: 5 5 5 5 9 9 9 9
对输入数组应用同样的调整:
Input array: 8 5 8 6 14 12 18 13
Adjustments: -3 1 -1 2 -1 2 -3 3
-------------------------------
Sorted: 5 6 7 8 13 14 15 16
将此技术应用于此线程中的其他数组
input: 4 0 9 -2
normalized: 4 -1 7 -5
sections: { 4, -1, 0, 1 } { 7, -5, 2, 3 }
combined: { 7, -5, 0, 3 }
answer: (7 - (-5)) / 2 = 6
targets: one target for the entire normalized array => (7 + (-5)) / 2 = 1
input: 0 1 3 -15
normalized: 0 0 1 -18
sections: { 0, 0, 0, 1 } { 1, -18, 2, 3 }
combined: { 1, -18, 0, 3 }
answer: (1 - (-18)) / 2 = 10
targets: one target for the entire normalized array => (1 + (-18)) / 2 = -8
input: -15 1
normalized: -15 0
sections: { -15, -15, 0, 0 } { 0, 0, 1, 1 }
combined: same as above
answer: 0 (same answer for both sections)
targets: targets are -15 and 0
input: 40 31 140 131
normalized: 40 30 138 128
sections: { 40, 30, 0, 1 } { 138, 128, 2, 3 }
combined: same as above
answer: 5 (same answer for both sections)
targets: targets are 35 and 133
挑战
找到一个破坏这个算法的反例并将其发布在 cmets 中:)