簡體   English   中英

什么是最小緩沖區值,使得一組int將按遞增順序排序?

[英]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)可以通過逐個循環數組並保持不變量正確並跟蹤當前緩沖區大小來實現:

  1. 我們從左邊開始,一個接一個地走到右邊
  2. 根據定義,單個元素子陣列被排序
  3. 使用當前緩沖區將當前元素調整到最低可能值(因此不變量仍然保持不變)
  4. 如果當前元素(調整后)大於前一個元素,那么我們不需要做任何事情(已排序
  5. 否則( 未排序 )我們需要更新緩沖區(增加它) - 這通過檢查當前元素的差異和已經排序的數組的最大值來完成,這只是前一個元素(所以我們添加abs((curr-prev)/2) + 1到當前緩沖區)和先前/當前值(到可能的最小值)。 此時我們不需要關心先前的條目,因為我們正在增加緩沖區以減少先前/當前值,我們可以簡單地從每個先前的值中減去abs((curr-prev)/2) + 1並且不變量會持有。

一些例子使它更清晰(粗體 - 當前,斜體 - 以前):

I)輸入:[4,0,9,-2]

  • [ 4 ] - 按定義排序
  • [4,0] -未分類,更新當前用緩沖液[4,0],DIFF =(4-0)/ 2 + 1 = 3 => [1,2],緩沖液= 3 //更新被完成為follow:將前一個值減去整個diff,對於當前的一個檢查newPrevious(這里是1)加1是否在范圍current + -diff中,如果是,則設置newPrevious + 1,否則設置current + diff
  • [1,2,9 -排序,更新當前與緩沖器[1,2,6] //這里更新也同樣做了以前的更新,而是做斷電流+ DIFF我們做的電流差異
  • [1,2,6,-2] -未分類,更新當前用緩沖液[1,2,6,1],仍然未排序所以DIFF =(6-1)/ 2 + 1 = 3,緩沖= 6,[ 1,2,3,4]

完成,緩沖區= 6

II)輸入:[40,31,140,​​131]

  • [ 40 ] - 按定義排序
  • [40,31] -未分類,更新當前用緩沖液[40,31],DIFF =(40-31)/ 2 + 1 = 5 => [35,36],緩沖液= 5
  • [35,36,140] -排序,更新當前[35,36,135]
  • [35,36,135,131] -未分類,更新當前[35,36,135,136]

完成,緩沖區= 5

III)輸入:[1,1,1,1]

  • [ 1 ] - 按定義排序
  • [1,1] -未分類,更新當前的[1,1],DIFF =(1-1)/ 2 + 1 = 1 => [0,1](因為0 + 1是確定),緩沖液= 1
  • [0,1,1] -未分類,更新當前的[0,1,2],分類
  • [0,1,2,1] -未分類,更新當前[0,1,2,2],DIFF =(2-2)/ 2 + 1 = 1 => [0,1,2,3],緩沖區= 2

完成,緩沖區= 2

IV)輸入:[7,11,1,2,3]

  • [ 7 ] - 按定義排序
  • [7,11] -排序,調節[7,11]
  • [7,11,1] -未排序的,調節[7,11,1],DIFF =(11-1)/ 2 + 1 = 6 => [7,5,6],緩沖液= 6
    • 在這里我們可以看到我們不需要在11之前檢查任何東西,因為之前的所有數字都小於11,所以如果我們做11 - X我們可以簡單地做上一個 - X並且不變量仍然會保持
  • [7,5,6,2] -未分類的,調節[7,5,6,7] < -不變仍然成立,我根本沒有在先前步驟中調整第一7
  • [7,5,6,7,3] -未分類的,調節[7,5,6,7,8]

完成,緩沖區= 6

V)輸入:[0,1,3,-15]

直到[0,1,3]沒有任何改變

  • [0,1,3,-15] DIFF = 10,調整先前和當前[0,1,-7,-6] -再次在這里我們可以看到,我們增加從0到10,從而所有的數字緩沖器向左3和3本身可以減少10並且不變量將保持但是對於算法的其余部分我們不需要這樣做

完成,緩沖區= 10

VI)輸入:[1,2,3,4]

  • [1] - 按照定義排序
  • [1,2] - 排序,按緩沖區0調整
  • [1,2,3] - 排序,按緩沖區0調整
  • [1,2,3,4] - 排序,按緩沖區0調整

完成,緩沖區= 0

原來的答案

我原來的答案包括以下三個步驟。 該算法可用,前提是規范化數組中的max位於規范化數組中的min之前。 我考慮的樣本數組是[4,0,9,-2]和[0,1,3,-15]。 請注意,在這兩個示例數組中, maxmin之前。 但是,如果絕對此算法失敗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

原答案的基本原理和缺陷

我最初的答案背后的想法是, maxmin之間的中點提供了一個target ,規范化數組中的每個條目都可以調整為命中。 target最遠的maxmin需要最大的調整,因此提供了答案。 然而,在看到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以找到maxmin之間的最大差異。 最大的差異除以2並在必要時進行四舍五入是問題的答案。 此外, minmax之間的中點是數組該部分的目標值(目標值可以被截斷)。

一個例子

考慮數組[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)解決方案。

對於相鄰的一對,比如ab ,如果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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM