[英]What is the min buffer value such that an array of ints will be sorted in increasing order?
問題:給定一個整數數組,找到最小緩沖區值,以便可以按嚴格遞增的順序對數組進行排序。 數組中的每個元素都可以加上或減去緩沖區值。
Ex: [4, 0, 9, -2]
最小緩沖區值為6,因為您可以將數組更改為:
[4 - (6 or 5 or 4 or 3), 0 + (-1 or 0 or 1 or 2), 9 - (6) = 3, -2 + (6) = 4]
我相信我有一個解決方案可以使用O(N ^ 2),但我想知道我是否可以做得更好。
編輯:沒關系,我的解決方案不起作用。
我的解決方案
對於每個元素,繪制一條斜率為1的線,通過該元素。 找到允許每個元素移動到線上的最小緩沖區值。 跟蹤獲得的緩沖區值,並在最后返回最小的緩沖區值。
謝謝
O(n)
可以通過逐個循環數組並保持不變量正確並跟蹤當前緩沖區大小來實現:
abs((curr-prev)/2) + 1
到當前緩沖區)和先前/當前值(到可能的最小值)。 此時我們不需要關心先前的條目,因為我們正在增加緩沖區以減少先前/當前值,我們可以簡單地從每個先前的值中減去abs((curr-prev)/2) + 1
並且不變量會持有。 一些例子使它更清晰(粗體 - 當前,斜體 - 以前):
I)輸入:[4,0,9,-2]
完成,緩沖區= 6
II)輸入:[40,31,140,131]
完成,緩沖區= 5
III)輸入:[1,1,1,1]
完成,緩沖區= 2
IV)輸入:[7,11,1,2,3]
完成,緩沖區= 6
V)輸入:[0,1,3,-15]
直到[0,1,3]沒有任何改變
完成,緩沖區= 10
VI)輸入:[1,2,3,4]
完成,緩沖區= 0
原來的答案
我原來的答案包括以下三個步驟。 該算法可用,前提是規范化數組中的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步:從最大值中減去min並除以2(必要時向上舍入),這就是你的答案
(7 - (-5)) / 2 = 6
原答案的基本原理和缺陷
我最初的答案背后的想法是, max
和min
之間的中點提供了一個target
,規范化數組中的每個條目都可以調整為命中。 離target
最遠的max
和min
需要最大的調整,因此提供了答案。 然而,在看到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
之間的最大差異。 最大的差異除以2並在必要時進行四舍五入是問題的答案。 此外, 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
挑戰
找到一個打破這個算法的計數器示例並將其發布在評論中:)
您可以使用二進制搜索來解決此問題。
所以假設緩沖區的大小是x =(低+高)/ 2,你可以做的是從每個索引從0到n - 1(n是數字元素),你只需要計算什么是使用緩沖區x可以采取的最小值(條件是它應該大於最后一個元素)。 這個貪婪將幫助您驗證查找x是否可以是有效的解決方案。
例如,如果x = 6,則數組為[4,0,9,-2]
index 0, min is 4 - 6 = -2 index 1, min is 0 - 1 = -1 (as we need to make this greater than -2) index 2, min is 9 - 6 = 3 index 3, min is -2 + 6 = 4
所以,6是有效的。
偽代碼:
int low = 0;
int high = //n times Max absolute value in the array
while(low <- high){
int x = (low + high)/2
if(x make the array become sorted)
update min result;
high = x - 1;
else
low = x + 1;
}
這是一個O(N)
解決方案。
對於相鄰的一對,比如a
和b
,如果a > b
發生,我們需要調整它們。 為了將它們調整為升序,我們需要找到一個X
,使得a - X < b + X
,相當於找到滿足a - b < 2X
X
因此,我們只需要掃描一次數組以找到a > b
那些對,並計算ceil((a - b) / 2)
,並回答最大值。
有效的實現可以寫成如下:
temp = a[0];
ans = 0
for (i = 1; i < N; i ++)
temp = max(temp + 1, a[i])
ans = max(ans, temp - a[i]);
return ceil(ans / 2)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.