微軟100題-求連續子數組之和的最大值+題目變形

求連續子數組之和的最大值:這個題很早前我就研究過了,百度實習面試的時候問了我一道類似的題目,就是給定兩個數組和一個數,在兩個數組中各取一個數,使其和爲輸入的值,也是該題目的一種變形,我上來就給出了一個最優的算法。然後計算時間複雜度,接着就被問的更難了,三個數組。。。  OMG,然後我就暈了,應該先說一個O(n^3)的實現的。然後再優化,但目前我還沒有想到合適的優化辦法。


以上題目如果有什麼問題,自己百度吧,這個都太簡單了,經典的題目了。今天我想聊一下題目的變種題。


(變形一)給定一個向量,要查找總和最接近0的子向量,而不是具有最大總和的子向量,如果希望查找總和最接近某一個給定數t的子向量,結果又怎樣?

解答:首先針對0,先利用一下求子數組最大和的O(n^2)算法。

(方法一)

maxsofar=(最小值)

for(i=0; i<n; i++)

       sum =0;

        for(j=i; j<n; j++)

               sum += a[j];

               maxsofar = max(maxsofar,sum);

(方法二)

cumarr[0]= a[0];

for(i=; i<n; i++)

       cumarr[i] = cumarr[i-1] +a[i];

max = 最小值;

for(i=0; i<n; i++)

       for(j=i; j<n;j++)

            sum = cumarr[j] - cummarr[i-1];

            maxsofar = max( maxsofar,sum);

我們利用方法二的思想。來解決 最接近0的情況

current[0] = a[0];

for(i=1; i<n; i++)

       current[i] = current [i-1]+a[i];

sort(current);//將數組current 按照升序排序,排序的時候注意保存原始的位置號,怎麼實現,定義一個結構體,一個記錄i,一個記錄和,最後按照和的大小排序就可以了

掃描排序後的數組,計算相鄰元素之間的差,取差的絕對值最小的兩個元素 current[ i ],和current[ j ],  ( j > i )

 最後的子序列就是 a[i+1],a[i+2],..., a[j] 。

對於最接近t的情況,則計算排序後數組中相鄰兩個元素之間的差值時,用絕對值和t比較就可以啦。

OK了。   

(變形二)

收費公路由n個收費站之間的n-1段公路組成,每一段公路都有相關的使用費。如果在O(n)時間內駛過兩個收費站,並且僅使用一個費用數組,或在固定的時間內路過兩個收費站,並且使用一個具有O(n^2)個表項的表,那麼給出兩站之間的行駛費用很容易。請描述一個數據結構,該結構僅需要O(n)的空間,卻可以在固定的時間內完成任意路段的費用計算。

跟(變形一)的題目很接近吧。答案也非常的接近, 就是不用再排序了,當輸入任意兩個站 i  和 j 時,只需要計算 current[ j ] - current[ i-1] 就OK啦!

(變形三)

給定整數m,n 和實數向量 x[n] ,請找出使總和 x[i] +....+ x[i+m] 最接近0 的整數 i, (0<=i <n-m)

思路同上,計算x[0]到x[i]的總和current[i],得到響亮current[0],current[1],current[2],...,current[n-1]

然後找到 i -1,使得 current[i-1] 和current[i+m] 的和最接近 0。

minnum= current[m];

for(i=1; i<n-m; i++)

      plus = current[ i+m]-current[i-1];

      minnum = min (minnum, plus);

(變形四)- 今年騰訊實習生的一道加試題

給定一數組a[N],我們希望構造數組b [N],其中b[j]=a[0]*a[1]…a[N-1] / a[j],在構造過程中,不允許使用除法:
要求O(1)空間複雜度和O(n)的時間複雜度;
除遍歷計數器與a[N] b[N]外,不可使用新的變量(包括棧臨時變量、堆空間和全局靜態變量等);
青銅程序(主流編程語言任選)實現並簡單描述。

思路:

從後往前計算b:

b[n-1]=1;

b[n-2]=a[n-1]*1;

b[n-3]=a[n-2]*b[n-2] = a[n-2]*a[n-1]*1;

...

b[1]=a[2]*a[3]*a[4]*...*a[n-1];

b[0]=a[1]*a[2]*a[3]*...*a[n-1];

從前往後計算a,要改變a原來的值:(爲了方便明白新數組與原數組的關係,新數組用A表示,但是說上我們並沒有申請新的空間)

A[0]=a[0];

A[1]=a[1]*A[0]= a[0]*a[1];

A[2]=a[2]*A[1] = a[0]*a[1]*a[2];

...

A[n-2]=a[0]*a[1]*a[2]*...*a[n-2];

A[n-1]=a[n-1];//不做處理了,因爲用不到

最後計算b的最終值

for(i=1; i<n; i++)

     b[i]=b[i]*A[i-1];

全部的代碼爲:

b[n-1]=1;

for(i=n-2; i>=0;i--)

      b[i]=b[i-1]*a[i];

for(i=1; i<n-1;i++)

      a[i]=a[i]*a[i-1];

for(i=1; i<n; i++)

      b[i]=b[i]*a[i-1];

(變形之最-給定n*n的實數數組,需要求矩形子數組的最大總和,複雜度又是多少?)

《編程之美》上有解答。可惜我還沒有很熟練。











































發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章