相差甚遠;及Magic Index分析

謝工在GitChat發表於2013-07-22

今日面試題:相差甚遠

給定一個陣列,我們可以找到兩個不相交的、並且是連續的子陣列A和B,A中的數字和為sum(A), B中的元素和為sum(B)。找到這樣的A和B,滿足sum(A) - sum(B)的絕對值是最大的。

例如:
[2, -1 -2, 1, -4, 2, 8]劃分為A=[-1, -2, 1, -4], B=[2, 8], 最大的值為16。

Magic Index 分析:
給定一個陣列A,其中有一個位置被稱為Magic Index,含義是:如果i是Magic Index,則A[i] = i。假設A中的元素遞增有序、且不重複,請給出方法,找到這個Magic Index。更進一步,當A中允許有重複的元素,該怎麼辦呢?

沒有重複元素的情況

一些同學在遇到這個題目的時候,往往會覺得比較簡單。掃描一遍,不就ok了麼?O(n)的。很簡單呀。可是,大家要注意到,還有一個條件沒有用:A中的元素是有序遞增的。這個條件,並不是放在這裡迷惑大家的,而是有更大的作用的。這個時候,該如何想呢?O(n)不是最好的方法,更好的是什麼呢?怎麼利用陣列有序呢?在有序的陣列中查詢一個滿足特定元素的條件,我們通常會想到二分查詢。 我們來回顧一下二分查詢,對於要查詢的目標t,我們首先與陣列中間的元素比較,如果t大於中間的元素,則在右半部分繼續查詢;如果t小於中間的元素,則在左半部分,繼續查詢。

那麼,我們的題目能夠利用上述的思想呢?我們來看一個具體的例子:

0    1    2    3    4    5    6
-10    -5    1    2    4    10    12

mid=3,A[mid] = 2,即A[mid] < mid。接下來,我們應該在哪一邊查詢呢?我們知道陣列的元素是遞增有序,且不重複的,也就是說,在A[mid]左邊的元素,比A[mid]都要小,沒有重複,意味著什麼呢?每向左移動一位,至少減1。所以,在mid左邊,不可能有一個i,A[i]=i的。如果有,根據前面的分析,我們知道A[mid] - A[i] >= mid - i, 如果A[i] = i,則,A[mid] >= mid, 這與事實A[mid] < mid相悖。所以,接下來,只能在右邊進行查詢。程式碼與二分查詢也很像。

有重複元素的情況

如果陣列A中,有重複元素,是什麼情況呢?經過前面的分析,我們知道,是否有重複的主要差別在,陣列的元素從右到左進行遞減,每次不一定至少是1了,有可能是0了。讓我們直觀的看一下影響吧。

0    1    2    3    4    5    6
-10    2    2    2    9    10    12

看上面的陣列,同樣A[mid] < mid。我們應該繼續查右邊麼?顯然,右邊並不存在Magic Index。查詢右邊,就會找不到這樣的Magic Index。此時,應該如何處理呢?我們無法確定,Magic Index是在左邊,還是在右邊了。那就兩邊都遞迴進行處理吧。

在這裡還有一個小技巧,我們就是要分別遞迴處理[0, mid - 1]和[mid + 1, end](end是陣列長度-1)麼?我們看一個具體的例子:

0    1    2    3    4    5    6
-10    2    2    2    2    10    12

這個例子,當我們進行左半部分遞迴處理的時候,需要考慮的範圍是[0, 3]。可實際上,我們只需要考慮[0, 2]。原因是,陣列元素在mid=4的左邊的值都要小於或者等於A[mid]=2,所以最大的一個有可能是Magic Index的,就是index為A[mid]的情況。所以,這時右邊的邊界應該是min(mid - 1, A[mid])。

那麼,右邊的情況呢?如下例子:

0    1    2    3    4    5    6    
-10    2    2    2    9    10    12

此時,要在右半部分進行查詢,範圍一般是[5, 8]。但是,由於陣列有序,後面的值,一定是大於等於A[mid]=9的。所以,有可能是Magic Index的最小Index是9,也就是說右邊的遞迴,應該是從索引為9的位置開始。此例,就意味著,無需處理右邊了。

本文來自微信:待字閨中,2013-07-15釋出,原創@陳利人 ,歡迎大家繼續關注微信公眾賬號“待字閨中”。

相關文章