版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
Java程序員面試分類模擬16論述題1.
如何找出數(shù)組中重復(fù)元素最多的數(shù)正確答案:問題描述:對于數(shù)組{1,1,2,2,4,4,4,4,5,5,6,6,6},元素1出現(xiàn)的次數(shù)為2次,元素2出現(xiàn)的次數(shù)(江南博哥)為2次,元素4出現(xiàn)的次數(shù)為4次,元素5出現(xiàn)的次數(shù)為2次,元素6出現(xiàn)的次數(shù)為3次,找出數(shù)組中出現(xiàn)重復(fù)次數(shù)最多的數(shù)。
上述問題中,程序的輸出應(yīng)該為元素4。
可以采取如下兩種方法來計算數(shù)組中重復(fù)次數(shù)最多的數(shù)。
方法一:空間換時間??梢远x一個數(shù)組intcount[MAX],并將其數(shù)組元素都初始化為0,然后執(zhí)行for(inti=0;i<100;i++)count[A[i]]++操作,在count數(shù)組中找最大的數(shù),即為重復(fù)次數(shù)最多的數(shù)。這是一種典型的空間換時間的算法。一般情況下,除非內(nèi)存空間足夠大,一般不采用這種方法。
方法二:使用Map映射表。通過引入Map映射表(Map提供一對一的數(shù)據(jù)處理能力,其中第一個為關(guān)鍵字,每個關(guān)鍵字只能在Map中出現(xiàn)一次,第二個稱為該關(guān)鍵字的值)來記錄每一個元素出現(xiàn)的次數(shù),然后判斷次數(shù)大小,進而找出重復(fù)次數(shù)最多的元素。示例如下:
importjava.util.*;
publicclassTest{
publicstaticintfindMostFrequentInArray(int[]a){
intresult=0;
intsize=a.length;
if(size==0)
returnInteger.MAX_VALUE;
//記錄每個元素出現(xiàn)的次數(shù)
Map<Integer,Integer>m=newHashMap<Integer,Integer>();
for(inti=0;i<size;i++){
if(m.containsKey(a[i])){
m.put(a[i],m.get(a[i])+1);
}
else{
m.put(a[i],1);
}
}
//找出出現(xiàn)次數(shù)最多的元素
intmost=0;
Iteratoriter=m.entrySet().iterator();
while(iter.hasNext()){
Map.Entryentry==(Map.Entry)iter.next();
intkey=(Integer)entry.getKey();
intval=(Integer)entry.getValue();
if(val>most){
result=key;
most=val;
}
}
returnresult;
}
publicstaticvoidmain(Stnng[]args){
intarray[]={1,5,4,3,4,4,5,4,5,5,6,6,6,6,6};
intmaxFrequenceNum=findMostFrequentInArray(array);
System.out.println(maxFrequenceNum);
}
}
程序運行結(jié)果為:
6
2.
如何求數(shù)組中兩兩相加等于20的組合種數(shù)正確答案:問題描述:給定一個數(shù)組{1,7,17,2,6,3,14},這個數(shù)組中滿足條件的有兩對組合——17+3=20和6+14=20。
方法一:“蠻力”法
最容易想到的方法就是采用兩重循環(huán)遍歷數(shù)組來判斷兩個數(shù)的和是否為20。實現(xiàn)代碼如下:
publicclassTest{
publicstaticvoidfindSum(int[]a,intsum){
intlen=a.length;
for(inti=0;i<len;i++)
for(intj=i;j<len;j++){
if(a[i]+a[j]==sum)
System.out.println(a[i]+","+a[j]);
}
}
publicstaticvoidmain(String[]args){
intarray[]={1,7,17,2,6,3,14};
findSum(array,20);
}
}
程序運行結(jié)果為:
17,3
6,14
由于采用了雙重循環(huán),因此這個算法的時間復(fù)雜度為O(n^2)。
方法二:排序法
先對數(shù)組元素進行排序,可以選用堆排序或快速排序,此時算法的時間復(fù)雜度為O(nlogn),然后對排序后的數(shù)組分別從前到后和從后到前遍歷,假設(shè)從前往后遍歷的下標(biāo)為begin,從后往前遍歷的下標(biāo)為end,那么當(dāng)滿足arr[begin]+arr[end]<20時,如果存在兩個數(shù)的和為20,那么這兩個數(shù)一定在[begin+1,end]之間;當(dāng)滿足arr[begin]+arr[end]>20時,如果存在兩個數(shù)的和為20,那么這兩個數(shù)一定在[begin,end+1]之間。這個過程的時間復(fù)雜度為O(n),因此整個算法的時間復(fù)雜度為O(nlogn)。實現(xiàn)代碼如下:
importjava.util.Arrays;
publicclassTest{
publicstaticvoidfindSum(int[]a,intsum){
Arrays.sort(a);
intbegin=0;
intend=a.length-1;
while(begin<end){
if(a[begin]+a[end]<sum)
begin++;
elseif(a[begin]+a[end]>sum)
end--;
else{
System.out.println(a[begin]+","+a[end]);
begin++;
end--;
}
}
}
publicstaticvoidmain(String[]args){
intarray[]={1,7,17,2,6,3,14};
findSum(array,20);
}
}
程序運行結(jié)果為:
3,17
6,14
這個算法的時間復(fù)雜度主要由排序算法的時間復(fù)雜度來決定。因此,選擇時間復(fù)雜度較低的排序算法能顯著提高該算法的效率。
3.
如何把一個數(shù)組循環(huán)右移k位正確答案:假設(shè)要把數(shù)組序列12345678右移2位變?yōu)?8123456,比較移位前后數(shù)組序列的形式,不難看出,其中有兩段序列的順序是不變的,即78和123456,可以把這兩段看作兩個整體,右移k位就是把數(shù)組的兩部分交換一下。鑒于此,可以設(shè)計這樣一種算法,步驟如下(以數(shù)組序列12345678為例):
1)逆序數(shù)組子序列123456,數(shù)組序列的形式變?yōu)?5432178。
2)逆序數(shù)組子序列78,數(shù)組序列的形式變?yōu)?5432187。
3)全部逆序,數(shù)組序列的形式變?yōu)?8123456。
程序代碼如下:
publicclassTest{
publicstaticvoidreverse(inta[],intb,inte){
for(;b<e;b++,e--){
inttemp=a[e];
a[e]=a[b];
a[b]=temp;
}
}
publicstaticvoidshift_k(inta[],intk){
intn=a.length;
k=k%n;//為了防止k比n大,右移k位跟右移k%n位的結(jié)果是一樣的
reverse(a,n-k,n-1);
reverse(a,0,n-k-1);
reverse(a,0,n-1);
}
publicstaricvoidmain(String[]args){
intarray[]={1,2,3,4,5,6,7,8};
shift_k(array,2);
for(inti=0;i<array.length;i++){
System.out.print(array[i]+"");
}
}
}
程序運行結(jié)果如下:
78123456
從上例中可以看出,該算法只進行了3次逆序操作,因此時間復(fù)雜度為O(n)。
4.
如何找出數(shù)組中第k個最小的數(shù)正確答案:問題描述:給定一個無序的數(shù)組,從一個數(shù)組中找出第k個最小的數(shù),例如,對于給定數(shù)組序列{1,5,2,6,8,0,6},其中第4小的數(shù)為5。
方法一:排序法
最容易想到的方法就是對數(shù)組進行排序,排序后的數(shù)組中第k-1個位置上的數(shù)字即為數(shù)組的第k個最小的數(shù)(原因是數(shù)組下標(biāo)從0開始計數(shù)),這種方法最好的時間復(fù)雜度為O(nlogn)。
方法二:“剪枝”法
采用快速排序的思想來實現(xiàn)。主要思路如下:選一個數(shù)tmp=a[n-1]作為樞紐,把比它小的數(shù)都放在它的左邊,比它大的數(shù)都放在它的右邊,然后判斷tmp的位置,如果它的位置為k-1,那么它就是第k個最小的數(shù);如果它的位置小于k-1,那么說明第k個小的元素一定在數(shù)組的右半部分,采用遞歸的方法在數(shù)組的右半部分繼續(xù)查找;否則第k個小的元素在數(shù)組的左半部分,采用遞歸的方法在左半部分數(shù)組中繼續(xù)查找。示例如下:
publicclassTest{
publicstaticintquikSort(intarray[],intlow,inthigh,intk){
inti,j;
inttmp;
if(low>high)
returnInteger.MIN_VALUE;
i=low+1;
j=high;
tmp=array[i];
while(i<j){
while(i<j&&array[j]>=tmp)
j--;
if(i<j)
array[i++]=array[j];
while(i<j&&array[i]<tmp)
i++;
if(i<j)
array[j--]=array[i];
}
array[i]=tmp;
if(i+1==k)
returntmp;
elseif(i+1>k)
returnquikSort(array,low,i-1,k);
else
returnquikSort(array,i+1,high,k);
}
publicstaticintgetKMin(intarray[],intk){
if(array==null)
returnInteger.MIN_VALUE;
if(array.length<k)
returnInteger.MIN_VALUE;
returnquikSort(array,0,array.length-1,k);
}
publicstaticvoidmain(String[]args){
inta[]={1,5,2,6,8,0,6};
intkMin=getKMin(a,4);
System.out.println(kMin);
}
}
程序運行結(jié)果為:
5
表面上看起來這種方法還是在對數(shù)組進行排序,但是它比排序法的效率高,主要原因是當(dāng)在數(shù)組右半部分遞歸查找時,完全不需要關(guān)注左半部分數(shù)組的順序,因此省略了對左半部分數(shù)組的排序。因此,這種方法可以被看作一種“剪枝”方法,不斷縮小問題的規(guī)模,直到找到第k個小的元素。
5.
如何找出數(shù)組中只出現(xiàn)一次的數(shù)字正確答案:問題描述:一個整型數(shù)組里除了一個數(shù)字之外,其他數(shù)字都出現(xiàn)了兩次。找出這個只出現(xiàn)1次的數(shù)字。要求時間復(fù)雜度是O(n),空間復(fù)雜度是O(1)。
如果本題對時間復(fù)雜度沒有要求,最容易想到的方法就是先對這個整型數(shù)組排序,然后從第一個數(shù)字開始遍歷,比較相鄰的兩個數(shù),從而找出這個只出現(xiàn)1次的數(shù)字,這種方法的時間復(fù)雜度最快為O(nlogn)。
由于時間復(fù)雜度與空間復(fù)雜度的限制,該方法不可取,因此需要一種更高效的方式。題目強調(diào)只有一個數(shù)字出現(xiàn)1次,其他數(shù)字出現(xiàn)了兩次,首先想到的是異或運算,根據(jù)異或運算的定義可知,任何一個數(shù)字異或它自己都等于0,所以,如果從頭到尾依次異或數(shù)組中的每一個數(shù)字,那些出現(xiàn)兩次的數(shù)字全部在異或中會被抵消掉,最終的結(jié)果剛好是這個只出現(xiàn)1次的數(shù)字。示例如下:
publicclassTest{
publicstaticintfindNotDouble(inta[]){
intn=a.length;
intresuh=a[0];
inti;
for(i=1;i<n;++j)
result^=a[i];
returnresult;
}
publicstaticvoidmain(String[]args){
intarray[]={1,2,3,2,4,3,5,4,1};
intnum=findNotDouble(array);
System.out.println(num);
}
}
程序運行結(jié)果為:
5
引申:如果題目改為數(shù)組A中,一個整型數(shù)組里除了一個數(shù)字之外,其他數(shù)字都出現(xiàn)了3次,那么如何找出這個數(shù)?
上述異或運算的方法只適用于其他數(shù)字出現(xiàn)的次數(shù)為偶數(shù)的情況,如果其他數(shù)字出現(xiàn)的次數(shù)為奇數(shù),上述介紹的方法則不再適用。如果數(shù)組中的所有數(shù)都出現(xiàn)n次,那么這個數(shù)組中的所有數(shù)對應(yīng)的二進制數(shù)中,各個位上的1出現(xiàn)的個數(shù)均可以被n整除。以n=3為例,假如數(shù)組中有如下元素:{1,1,1,2,2,2},它們對應(yīng)的二進制表示為01,01,01,10,10,10。顯然,這個數(shù)組中的所有數(shù)字對應(yīng)的二進制數(shù)中第0位有3個1,第1位有3個1。對于本題而言,假設(shè)出現(xiàn)一次的這個數(shù)為a,那么去掉a后其他所有數(shù)字對應(yīng)的二進制數(shù)的每個位置出現(xiàn)1的個數(shù)為3的倍數(shù)。因此可以對數(shù)組中的所有數(shù)字對應(yīng)的二進制數(shù)中各個位置上1的個數(shù)對3取余數(shù),就可以得到出現(xiàn)1次的這個數(shù)的二進制表示,從而可以找出這個數(shù)。示例如下:
publicclassTest{
publicstaticintfindOnee(inta[],intappearTimes){
intn=a.length;
int[]bitCount=newint[32];
//計算數(shù)組中所有數(shù)組對應(yīng)的二進制數(shù)各個位置上出現(xiàn)1的次數(shù)
for(inti=0;i<n;i++)
for(intj=0;j<32;j++)
bitCount[j]+=((a[i]>>j)&1);
//若某位上的結(jié)果不能被整除,則肯定目標(biāo)數(shù)字在這一位上
intappearOne=0;
for(inti=0;i<32;i++)
if(bitCount[i]%appearTimes!=0)
appearOne+=(1<<i);
returnappearOne;
}
publicstaticvoidnlain(String[]args){
intarray[]={1,2,1,2,4,2,4,4,1,3};
intnum=findOnce(array,3);
System.out.println(num);
}
}
程序運行結(jié)果為:
3
此外,這種方法不僅適用于求解其他數(shù)字出現(xiàn)個數(shù)為奇數(shù)的情況,也適用于求解出現(xiàn)次數(shù)為偶數(shù)的情況,具有更好的通用性。
6.
如何找出數(shù)組中唯一的重復(fù)元素正確答案:問題描述:數(shù)組a[N],1~N-1這N-1個數(shù)存放在a[N]中,其中某個數(shù)重復(fù)1次。寫一個函數(shù),找出被重復(fù)的數(shù)字。要求每個數(shù)組元素只能訪問1次,并且不用輔助存儲空間。
由于題目要求每個數(shù)組元素只能訪問1次,且不用輔助存儲空間,因此可以從原理上入手,采用數(shù)學(xué)求和法,因為只有一個數(shù)字重復(fù)1次,而又是連續(xù)的,根據(jù)累加和原理,對數(shù)組的所有項求和,然后減去1~N-1的和,即為所求的重復(fù)數(shù)。示例如下:
publicclassTest{
publicstaticintxor_findDup(int[]a){
intn=a.length;
inttmp1=0;
inttmp2=0;
for(inti=0;i<n-1;++i){
tmp1+=(i+1);
tmp2+=a[i];
}
tmp2+=a[n-1];
intresult=tmp2-tmp1;
returnresult;
}
publicstaticvoidmain(String[]args){
inta[]={1,2,1,3,4};
intmissingNum=xor_findDup(a);
System.out.println(missingNum);
}
}
程序運行結(jié)果為:
1
如果題目沒有要求每個數(shù)組元素只能訪問1次,且不允許使用輔助存儲空間,還可以用異或法和位圖法來求解。
(1)異或法
根據(jù)異或法的計算方式,每兩個相異的數(shù)執(zhí)行異或運算之后,結(jié)果為1;每兩個相同的數(shù)執(zhí)行異或運算之后,結(jié)果為0,所以,數(shù)組a[N]中的N個數(shù)異或結(jié)果與1~N-1異或的結(jié)果再做異或運算,得到的值即為所求。
設(shè)重復(fù)數(shù)為A,其余N-2個數(shù)異或結(jié)果為B,N個數(shù)異或結(jié)果為A^A^B,1~N-1異或結(jié)果為A^B,由于異或滿足交換律和結(jié)合律,且X^X=0,0^X=X,則有(A^B)^(A^A^B)=A^B^B=A。示例如下:
publicclassTest{
publicstaticintxor_findDup(int[]a){
intn=a.length;
inti;
intresult=0;
for(i=0;i<n;i++){
result^=a[i];
}
for(i=1;i<n;i++){
result^=i;
}
returnresult;
}
publicstaticvoidmain(String[]args){
inta[]={1,2,1,3,4};intmissingNum=xor_findDup(a);
System.out.println(missingNum);
}
}
程序運行結(jié)果為:
1
(2)空間換時間法
申請長度為N-1的整型數(shù)組flag并初始化為0,然后從頭開始遍歷數(shù)組a,取每個數(shù)組元素a[i]的值,將其對應(yīng)的數(shù)組flag中的元素賦值為1,如果已經(jīng)置過1,那么該數(shù)就是重復(fù)的數(shù)。示例如下:
publicclassTest{
publicstaticintfindInteger(int[]a){
intn=a.length;
boolean[]arrayflag=newboolean[n];
inti=1;
intresult=Integer.MAX_VALUE;
while(i<n){
arrayflag[i]=false;
i++;
}
for(i=0;i<n;i++){
if(arrayflag[a[i]]==false)
arrayflag[a[i]]=true;
else{
result=a[i];
}
}
returnresult;
}
publicstaricvoidmain(String[]args){
inta[]={1,2,1,3,4};
intmissingNum=findInteger(a);
System.out.println(missingNum);
}
}
程序運行結(jié)果為:
1
這種方法的空間復(fù)雜度比較大,需要申請長度為N的整數(shù)數(shù)組。當(dāng)然也可以通過使用位圖的方法來降低空間復(fù)雜度,即不是用一個整型數(shù)字來表示元素是否出現(xiàn)過(0表示未出現(xiàn),1表示出現(xiàn)過),而是使用1bit來表示,因此需要申請數(shù)組的長度為N/32取上整。
此題可以進行一個變形:取值為[1,n-1]含n個元素的整數(shù)數(shù)組,至少存在一個重復(fù)數(shù),即可能存在多個重復(fù)數(shù),O(n)時間內(nèi)找出其中任意一個重復(fù)數(shù),例如,array[]={1,2,2,4,5,4},則2和4均是重復(fù)元素。
方案一:位圖法。使用大小為n的位圖,記錄每個元素是否已經(jīng)出現(xiàn)過,一旦遇到一個已經(jīng)出現(xiàn)過的元素,則直接將之輸出。該方法的時間復(fù)雜度是O(n),空間復(fù)雜度為O(n)。
方案二:數(shù)組排序法。先對數(shù)組進行計數(shù)排序,然后順序掃描整個數(shù)組,一旦遇到一個已出現(xiàn)的元素,則直接將之輸出。該方法的時間復(fù)雜度為O(n),空間復(fù)雜度為O(n)。
以上提出的兩種方案都需要額外的存儲空間,能否不使用額外存儲空間呢?答案是可以。于是想到了方案三:取反法。取反:去的基本思路如下:如果遍歷到數(shù)組中的元素為i,那么把a[i]的值取反,如果i在數(shù)組中出現(xiàn)兩次,那么a[i]會經(jīng)過兩次取反操作,a[i]的值跟原始的值相等,且為正數(shù);如果i出現(xiàn)了1次,那么a[i]的值為原始值的相反數(shù),且為負數(shù),可以根據(jù)這個原理來實現(xiàn)。實現(xiàn)方法如下:將數(shù)組元素值作為索引,對于元素arry[i],如果array[array[i]]大于0,那么設(shè)置array[array[i]]=-array[array[i]];如果array[array[i]]小于0,那么設(shè)置array-[array[i]]=-array[-array[i]],最后從數(shù)組第二個元素開始遍歷數(shù)組,如果array[i]>0,那么這個數(shù)就是重復(fù)的。由于在進行遍歷后對數(shù)組中的數(shù)據(jù)進行了修改,因此需要對數(shù)據(jù)進行還原(對數(shù)組中的負數(shù)取反)。示例如下:
publicclassTest{
publicstaticintxor_findDup(int[]a){
intn=a.length;
intresult=Integer.MAX_VALUE;
for(inti=0;i<n;i++){
if(a[i]>0){
a[a[i]]=-a[a[i]];
}else{
a[-a[i]]=-a[-a[i]];
}
}
for(inti=1;i<n;i++){
if(a[i]>0)
result=i;
else
a[i]=-a[i];
}
returnresult;
}
publicstaticvoidmain(String[]args){
inta[]={4,2,1,3,4};
intmissingNum=xor_findDup(a);
System.out.println(missingNum);
}
}
方法四是一種非?!霸幃悺钡乃惴ǎ褪遣捎妙愃朴趩捂湵硎欠翊嬖诃h(huán)的問題?!芭袛鄦捂湵硎欠翊嬖诃h(huán)”是一個非常經(jīng)典的問題,同時單鏈表可以采用數(shù)組實現(xiàn),此時每個元素值作為next指針指向下一個元素。本題可以轉(zhuǎn)化為“已知一個單鏈表中存在環(huán),找出環(huán)的入口點”這種想法。具體思路如下:將array[i]看作第i個元素的索引,即array[i]→array[array[i]]→array[array[array[i]]]→array[array[array[array[i]]]]→…,最終形成一個單鏈表,由于數(shù)組a中存在重復(fù)元素,因此一定存在一個環(huán),且環(huán)的入口元素即為重復(fù)元素。
該題的關(guān)鍵在于,數(shù)組array的長度是n,而元素的范圍是[1,n-1],所以array[0]不會指向自己,進而不會陷入錯誤的自循環(huán)。如果元素的范圍中包含0,那么該題不可直接采用該方法。示例如下:
publicclassTest1{
publicstaticintfindInteger(inta[]){
intx,y;
x=y=0;
do{
x=a[a[x]];
//x一次走兩步
y=a[y];
//y一次走一步
}while(x!=y);
//找到環(huán)中的一個點
x=0;
do{
x=a[x];
y=a[y];
}while(x!=y);
//找到入口點
returnx;
}
publicstaticvoidmain(String[]args){
inta[]={1,2,1,3,4};
intmissingNum=findInteger(a);
System.out.println(missingNum);
}
}
程序運行結(jié)果為:
1
7.
如何用遞歸方法求一個整數(shù)數(shù)組的最大元素正確答案:對于本題而言,最容易實現(xiàn)的方法為對數(shù)組進行遍歷,定義一個變量max為數(shù)組的第一個元素,然后從第二個元素開始遍歷,在遍歷過程中,每個元素都與max的值進行比較,若該元素的值比max的值大,則把該元素的值賦給max。當(dāng)遍歷完數(shù)組后,最大值也就求出來了。而使用遞歸方法求解的主要思路為:遞歸的求解“數(shù)組第一個元素”與“數(shù)組中其他元素組成的子數(shù)組的最大值”的最大值。示例如下:
publicclassTest{
privateintmax(inta,intb){
returna>b?a:b;p
}
publicintmaxnum(inta[],intbegin){
intlength=a.length-begin;
it(length==1)
returna[begin];
else{
returnmax(a[begin],maxnum(a,begin+1));
}
}
publicstaticvoidmain(String[]args){
Testt=newTest();
int[]num={0,16,2,3,4,5,10,7,8,9};
System.out.println(t.maxnum(num,0));
}
}
程序運行結(jié)果為:
16
8.
如何求數(shù)對之差的最大值正確答案:問題描述:數(shù)組中的一個數(shù)字減去它右邊子數(shù)組中的一個數(shù)字可以得到一個差值,求所有可能的差值中的最大值,例如,數(shù)組{1,4,17,3,2,9}中,最大的差值為17-2=15。
方法一:“蠻力”法?!靶U力”法也是最容易想到的方法,其原理如下:首先,遍歷數(shù)組,找到所有可能的差值;其次,從所有差值中找出最大值。具體實現(xiàn)方法為:針對數(shù)組a中的每個元素a[i](0<i<n-1),求所有a[i]-a[j](i<j<n)的值中的最大值。示例如下:
publicclassTest{
publicstaticintgetMax(int[]a){
if(a==null)
returnInteger.MIN_VALUE;
intlen=a.length;
if(len<=1)
returnInteger.MIN_VALUE;
intmax=Integer.MIN_VALUE;
for(inti=0;i<len-1;i++){
tbr(intj=i+1;j<len;j++)
if(a[i]-a[j]>max)
max=a[i]-a[j];
}
returnmax;
}
publicstaticvoidmain(String[]args){
int[]a={1,4,17,3,2,9};
System.out.println(getMax(a));
}
}
程序運行結(jié)果為:
15
采用這種方法雖然也能求出最大值,但是它的時間復(fù)雜度為O(n)。
方法二:二分法。通過二分法可以減少計算的次數(shù)。思路如下:把數(shù)組分為兩個子數(shù)組,那么最大的差值只能有3種可能:①最大的差值對應(yīng)的被減數(shù)和減數(shù)都在左子數(shù)組中,假設(shè)最大差值為leftMax;②被減數(shù)和減數(shù)都在右子數(shù)組中,假設(shè)最大差值為rightMax;③被減數(shù)是左子數(shù)組的最大值,減數(shù)是右子數(shù)組中的最小值,假設(shè)差值為mixMax。那么就可以得到這個數(shù)組的最大差值為這3個差值的最大值,即max(leftMax,rightNax,mixMax)。實現(xiàn)代碼如下:
importjavautil.concurrent.atomic.AtomicInteger;
publicclassTest{
publicstaticintgetMax(inta[]){
if(a==null)
returnInteger.MIN_VALUE;
intlen=a.length;
if(len<=1)
returnInteger.MIN_VALUE;
AtomicIntegermax=newAtomicInteger(0);
AtomicIntegermin=newAtomicInteger(0);
returngetMaxDiff(a,0,len-1,max,min);
}
publicstaticintgetMaxDiff(inta[],intbegin,intend,AtomicIntegermax,AtomicIntegermin){
if(begin==end){
max.set(a[begin]);
min.set(a[begin]);
returnInteger.MIN_VALUE;
}
intmiddle=begin+(end-begin)/2;
//數(shù)組前半部分的最小值與最大值
AtomicIntegerlMax=newAtomicInteger(0);
AtomicIntegerlMin=newAtomicInteger(0);
//數(shù)組前半部分的最:趕差值(第一種情況)
intleflMax=getMaxDiff(a,begin,middle,1Max,1Min);
//數(shù)組后半部分的最小值與最大值
AtomicIntegerrMax=newAtomicInteger(0);
AtomicIntegerrMin=newAtomicInteger(0);
//數(shù)組后半部分的最大差值(第二種情況)
intrightMax=getMaxDiff(a,middle+1,end,rMax,rMin);
//對應(yīng)第三種情況
intmixMax=1Max.get()-rMin.get();
//求數(shù)組的最大值與最小值
if(1Max.get()>rMax.get())
max.set(1Max.get());
else
max.set(rMax.get());
if(1Min.get()<rMin.get())
min.set(1Min.get());
else
min.set(rMin.get());
//求最大的差值
intallMax=(leftMax>rightMax)?leftMax:rightMax;
allMax=(allMax>mixMax)?allMax:mixMax;
returnallMax;
}
publicstaticvoidmain(String[]args){
int[]a={1,4,17,3,2,9};
System.out.println(getMax(a));
}
}
程序運行結(jié)果為:
15
顯然,以上這種方法對數(shù)組只經(jīng)過一次遍歷,一次時間復(fù)雜度為O(n),但是由于采用了遞歸的實現(xiàn)方式,在遞歸調(diào)用時要進行壓棧與彈棧操作,因此有額外的開銷,會導(dǎo)致算法性能有所下降。另外,在實現(xiàn)時,為了通過傳遞引用的方式獲取數(shù)組的最大值與最小值,使用了AtomicInteger而不是Integer類。主要原因為Integer類雖然也可以傳遞引用,但是它是不可變量,在方法內(nèi)部不能對其進行修改。
方法三:動態(tài)規(guī)劃。通過對題目進行分析,發(fā)現(xiàn)這是一個非常典型的動態(tài)規(guī)劃問題,可以用動態(tài)規(guī)劃的方法來求解。實現(xiàn)思路如下:給定數(shù)組a,申請額外的數(shù)組diff和max,其中diff[i]是以數(shù)組中第i個數(shù)字為減數(shù)的所有數(shù)對之差的最大值(前i+1個數(shù)組成的子數(shù)組中最大的差值),max[i]為前i+1個數(shù)的最大值。假設(shè)已經(jīng)求得了diff[i],diff[i+1]的值有兩種可能性:①等于diff[i];②等于max[i]-a[i]。通過上面的分析,可以得到動態(tài)規(guī)劃方法的計算表達式為:diff[i+1]=max(diff[i],max[i-1]-a[i]),max[i+1]=max(max[i],a[i+1])。數(shù)組最大的差值為diff[n-1](n為數(shù)組的長度)。示例如下:
publicclassTest{
publicstaticintmax(intm,intn){
return(m>n)?m:n;
}
publicstaticintgetMax(int[]a){
if(a==null)
returnInteger.MIN_VALUE;
intlen=a.length;
if(len<=1)
returnInteger.MIN_VALUE;
int[]diff=Newint[len];
int[]max=newint[len];
diff[0]=0;
max[0]=a[0];
for(inti=1;i<len;i++){
diff[i]=max(diff[i-1],max[i-1]-a[i]);
max[i]=max(max[i-1],a[i]);
}
returndiff[len-1];
}
publicstaticvoidmain(String[]args){
int[]a={1,4,17,3,2,9};
System.out.println(getMax(a));
}
}
程序運行結(jié)果為:
15
以上這種方法也是對數(shù)據(jù)進行了一次遍歷,因此時間復(fù)雜度為O(n),由于沒有采用遞歸的方式,因此相比方法二,在性能上有所提升。由于引入了兩個額外的數(shù)組,因此這個算法的空間復(fù)雜度也為O(n)。
從動態(tài)規(guī)劃方法的計算公式中可以看出,在求解diff[i+1]時,只用到了diff[i]與max[i],而與數(shù)組diff和max中其他數(shù)字無關(guān),因此可以通過兩個變量而不是數(shù)組來記錄diff[i]與max[i]的值,從而降低了算法的空間復(fù)雜度。示例如下:
publicclassTest{
publicstaticintmax(intm,intn){
return(m>n)?m:n;
}
publicstaticintgetMax(int[]a){
if(a==null)
returnInteger.MIN_VALUE;
intlen=a.length;
if(len<=1)
returnInteger.MIN_VALUE;
intdiff=0;
intmax=a[0];
for(inti=1;i<len;i++){
diff=max(diff,max-a[i]);
max=max(max,a[i]);
}
returndiff;
}
publicstaticvoidmain(String[]args){
int[]a={1,4,17,3,2,9};
System.out.println(getMax(a));
}
}
引申:這道題還可以用求最大子數(shù)組之和的方法來解決嗎?
答案:可以。實現(xiàn)思路如下:給定一個數(shù)組a(數(shù)組長度為n),額外申請一個長度為n-1的數(shù)組diff,數(shù)組diff中的值滿足diff[i]=a[i]-a[i+1],那么a[i]-a[j](0<i<j<n)就等價于diff[i]+diff[i+1]+…+diff[j]。因此,求所有a[i]-a[j]組合的最大值就可以轉(zhuǎn)換為求解所有diff[i]+diff[i+1]+…+diff[j]組合的最大值。由于diff[i]+diff[i+1]+…+diff[j]代表diff的一個子數(shù)組,因此可以用11.5.3節(jié)中求最大子數(shù)組之和的方法來解決。
9.
如何求絕對值最小的數(shù)正確答案:問題描述:有一個升序排列的數(shù)組,數(shù)組中可能有正數(shù)、負數(shù)或0,求數(shù)組中元素的絕對值最小的數(shù),例如,數(shù)組{-10,-5,-2,7,15,50},絕對值最小的是-2。
求絕對值最小的數(shù)可以分為3種情況:①如果數(shù)組第一個元素為非負數(shù),那么絕對值最小的數(shù)肯定為數(shù)組的第一個元素;②如果數(shù)組最后一個元素為負數(shù),那么絕對值最小的數(shù)肯定是數(shù)組的最后一個元素;③數(shù)組中即有正數(shù)又有負數(shù)時,首先找到正數(shù)與負數(shù)的分界點,如果分界點恰好為0,那么0就是絕對值最小的數(shù),否則通過比較分界點左右的正數(shù)與負數(shù)的絕對值來確定最小的數(shù)。對于上面的例子來說,正數(shù)與負數(shù)的分界點為-2和7。通過比較它們的絕對值從而確定-2的絕對值更小,因此-2就是要查找的數(shù)。
那么如何來查找正數(shù)與負數(shù)的分界點呢?最簡單的方法仍然是順序遍歷數(shù)組,找出第一個非負數(shù)(前提是數(shù)組中既有正數(shù)又有負數(shù)),接著通過比較分界點兩個數(shù)的值來找出絕對值最小的數(shù)。這種方法在最壞的情況下時間復(fù)雜度為O(n)。下面主要介紹采用二分法來查找正數(shù)與負數(shù)的分界點的方法。其主要思路為:取數(shù)組中間位置的值a[mid]。①a[mid]=0,那么這個數(shù)就是絕對值最小的數(shù);②a[mid]>0,如果a[mid-1]<0,那么就找到了分界點,通過比較a[mid]與a[mid-1]的絕對值就可以找到數(shù)組中絕對值最小的數(shù),如果a[mid-1]=0,那么a[mid一1]就是要找的數(shù),否則接著在數(shù)組的左半部分查找;③a[mid]<0,如果a[mid+1]>0,那么通過比較a[mid]與a[mid+1]的絕對值即可,如果a[mid+1]=0,那么a[mid+1]就是要查找的數(shù),否則接著在數(shù)組的右半部分繼續(xù)查找。實現(xiàn)代碼如下:
publicclassTest{
publicstaticintgetMinAbsoluteValue(int[]a){
if(a==null)
returnInteger.MIN_VALUE;
intlen=a.length;
if(len<1)
returnInteger.MIN_VALUE;
//數(shù)組中沒有負數(shù)
if(a[0]>=0)
returna[0];
//數(shù)組中沒有正數(shù)
if(a[len-1]<=0)
returna[len-1];
intmid=0;
intbegin=0;
intend=len-1;
intabsMin=0;
//數(shù)組中既有正數(shù)又有負數(shù)
while(true){
mid=begin+(end-begin)/2;
//如果值等于0,那么就是絕對值最小的數(shù)
if(a[mid]==0){
return0;
}//如果值大于0,那么正負數(shù)的分界點在左半部分
elseif(a[mid]>0){
//繼續(xù)在數(shù)組的左半部分查找
if(a[mid-1]>0)
end=mid-1;
elseif(a[mid-1]==0)
return0;
//找到正負數(shù)的分界點
else
break;
}//如果值小于0,在數(shù)組右半部分查找
else{
//在數(shù)組右半部分繼續(xù)查找
if(a[mid+1]<0)
begin=mid+1;
elseif(a[mid+1]==0)
return0;
//找到正負數(shù)的分界點
else
break;
}
}
//獲取正負數(shù)分界點出絕對值最小的值
if(a[mid]>0){
if(a[mid]<Math.abs(a[mid-1]))
absMin=a[mid];
else
absMin=a[mid-1];
}else{
if(Math.abs(a[mid])<a[mid+1])
absMin=a[mid];
else
absMin=a[mid+1];
}
returnabsMin;
}
publicstaticvoidmain(String[]args)throwsException{
int[]a1={-10,-5,-2,7,15,50};
int[]a2={2,4,6,8,27};
im[]a3={-13,-9,-7,-3};
intvalue=getMinAbsoluteValue(a1);
System.out.println(value);
value=getMinAhsoluteValue(a2);
System.out.println(value);
value=getMinAbsoluteValue(a3);
System.out.println(value);
}
}
程序運行結(jié)果為:
-2
2
-3
10.
如何求數(shù)組中兩個元素的最小距離正確答案:問題描述:給定一個數(shù)組,數(shù)組中含有重復(fù)元素,給出兩個數(shù)n1和n2,求這兩個數(shù)字在數(shù)組中所出現(xiàn)位置的最小距離,例如,數(shù)組{4,5,6,4,7,4,6,4,7,8,5,6,4,3,10,8}中,4和8的最小距離為2。
實現(xiàn)思路如下:遍歷數(shù)組,會遇到以下兩種情況。
1)當(dāng)遇到n1時,記錄下n1值對應(yīng)的數(shù)組下標(biāo)的位置n1_index,通過求n1_index與上次遍歷到n2的下標(biāo)值n2_index的差,可以求出最近一次遍歷到的n1與n2的距離。
2)當(dāng)遇到n2時,同樣記錄下它在數(shù)組中下標(biāo)的位置n2_index,然后通過求n2_index與上次遍歷到n1的下標(biāo)值n1_index的差,求出最近一次遍歷到的n1與n2的距離。
定義一個變量min_dist記錄n1與n2的最小距離,在以上兩種情況下,每次求出n1與n2的距離后與min_dist相比,求最小值。這樣只需對數(shù)組進行一次遍歷就可以求出最小距離,因此時間復(fù)雜度為O(n)。實現(xiàn)代碼如下:
publicclassTest{
privatestaticintmin(inta,intb){
returna>b?b:a;
}
publicstaticintminDistance(inta[],intn1,intn2){
if(a==null)
returnInteger.MIN_VALUE;
intlen=a.length;
intn1_index=-1;
intn2_index=-1;
intmin_dist=Integer.MIN_VALUE+1;
for(inti=0;i<len;++i){
if(a[i]==n1){
n1_index=i;
if(n2_index>=0)
min_dist=min(Math.ahs(min_dist),Math.abs(n1_index-n2_index));}
if(a[i]==n2){
n2_index=i;
if(n1_index>=0)
min_dist=min(Math.abs(min_dist),Math.abs(n2_index-n1_index));
}
}
returnmin_dist;
}
publicstaricvoidmain(String[]args){
inta[]={4,5,6,4,7,4,6,4,7,8,5,6,4,3,10,8};
System.out.println(minDistanee(a,4,8));
}
}
程序運行結(jié)果為:
2
11.
如何求指定數(shù)字在數(shù)組中第一次出現(xiàn)的位置正確答案:問題描述:給定數(shù)組a={3,4,5,6,5,6,7,8,9,8},這個數(shù)組中相鄰元素之差都為1,給定數(shù)字9,它在數(shù)組中第一次出現(xiàn)的位置的下標(biāo)為8(數(shù)組下標(biāo)從0開始)。
方法一:“蠻力”法。假設(shè)指定數(shù)字為t順序遍歷數(shù)組中每一個元素,并且將數(shù)組中的元素與t進行比較,判斷兩個值是否相等,若相等,則返回下標(biāo)位置;若遍歷完數(shù)組還沒找到t,則說明t在數(shù)組中不存在,返回-1。該方法的時間復(fù)雜度為O(n)。
這種方法顯然沒有用到題目中“這個數(shù)組中相鄰元素之差的絕對值為1”這一條件,下面介紹一種更高效的方法。
方法二:跳躍搜索法。通過對數(shù)組中元素的特點進行分析發(fā)現(xiàn)如下規(guī)律:假設(shè)先從數(shù)組a中查找9出現(xiàn)的位置,首先用數(shù)組中第一個元素(數(shù)組下標(biāo)為0)3與9進行比較,它們的差值為6,由于數(shù)組中相鄰兩個元素的差值為1,因此9在數(shù)組中出現(xiàn)的最早的位置必定為:第1+6=7個位置(數(shù)組下標(biāo)為6)。這是因為:如果數(shù)組是遞增的,那么數(shù)組第7個元素的值才為9;如果數(shù)組不是遞增的,那么9出現(xiàn)的位置肯定在數(shù)組中第7個元素后面;上面的示例中待查找的數(shù)比數(shù)組中第一個元素的值大,對于待查找的數(shù)比數(shù)組中第一個元素小的情況,可以用相同的方法。根據(jù)這個特點可以得出算法的思路為:從數(shù)組第一個元素開始(i=0),把數(shù)組當(dāng)前位置的值與t進行比較,如果相等,則返回數(shù)組下標(biāo),否則,從數(shù)組下標(biāo)為i+|t-a[i]|處繼續(xù)查找。實現(xiàn)代碼如下:
publicclassTest{
publicstaticintfindIndex(inta[],intt){
if(a==null)
return;
intlen=a.length;
inti=0;
while(i<len){
if(a[i]==t){
returni;
}else{
i+=Math.abs(t-a[i]);
}
}
return-1;
}
publicstaticvoidmain(String[]args){
inta[]={3,4,5,6,5,6,7,8,9,8};
System.out.println(findIndex(a,9));
}
}
程序運行結(jié)果為:
8
顯然,采用以上跳躍搜索法減:少了對數(shù)組中元素的訪問個數(shù),從而提高了算法的效率。
12.
如何對數(shù)組的兩個子有序段進行合并正確答案:問題描述:數(shù)組a[0,mid-1]和a[mid,n-1]是各自有序的,對數(shù)組a[0,n-1]的兩個子有序段進行合并,得到a[0,n-1]整體有序。要求空間復(fù)雜度為O(1)(注:al[i]元素是支持'<'運算符的)。假設(shè)給定數(shù)組a={1,5,6,7,9,2,4,8,10,13,14},mid=5,a[0]~a[4]是有序的,a[5]~a[10]是有序的,合并后的數(shù)組為{1,2,4,5,6,7,8,9,10,13,14}。
假設(shè)數(shù)組中的兩個子有序段都按升序排列,如上例所示。下面給出在這種情況下的實現(xiàn)思路。
由于限定空間復(fù)雜度為O(1),因此不能使用歸并方法。最容易想到的就是插入排序方法,這種算法的時間復(fù)雜度為O(n^2),空間復(fù)雜度為O(1),能滿足題目要求,但是由于插入排序方法沒有用到“數(shù)組a[0,mid-1]和a[mid,num-1]是各自有序的”這個條件,因此這種算法肯定不是最好的算法,下面給出另外一種方法。
實現(xiàn)思路:首先,遍歷數(shù)組中下標(biāo)為0~mid-1的元素,將遍歷到的元素的值與a[mid]進行比較,當(dāng)遍歷到a[i](0<=i<=mid-1)時,如果滿足a[mid]<a[i],那么交換a[i]與a[mid]的值。接著找到交換后的a[mid]在a[mid,num-1]中的具體位置(在a[mid,num-1]中進行插入排序),實現(xiàn)方法為:遍歷a[mid~num-2],如果a[mid+1]<a[mid],那么交換a[mid]與a[mid+1]的位置。實現(xiàn)代碼如下:
publicclassTest{
publicstaticvoidfindRightPlaceForMid(inta[],intmid){
intlen=a.length;
inttmp;
for(inti=mid;i<len-1;i++){
if(a[i+1]<a[i]){
tmp=a[i];
a[i]=a[i+1];
a[i+1]=tmp;
}
}
}
publicstaticvoidsort(inta[],intmid){
inttmp;
for(inti=0;i<=mid-1;i++){
if(a[mid]<a[i]){
tmp=a[i];
a[i]=a[mid];
a[mid]=tmp;
findRightPlaceForMid(a,mid);
}
}
}
publicstaticvoidmain(String[]args){
inta[]={1,5,6,7,9,2,4,8,10,13,14};
sort(a,5);
fnr(inti=0;i<11;i++)
System.out.print(a[i]+"");
}
}
程序運行結(jié)果為:
12456789101314
在實現(xiàn)時需要注意的問題是:題目中給出了“al[i]元素是支持<'運算符的”這一限制條件,因此,在程序中只能出現(xiàn)形如“a[i]<a[j]”的表達式,最好不要出現(xiàn)“a[j]>a[i]”這種寫法。
引申:
1)如果數(shù)組中兩個子有序段都按降序排列,可以用類似的方法來解決。
2)如果其中一個子序段按升序排列,另外一個子序段按降序排列,可以首先對其中一個子序段進行逆序,然后采用上面介紹的方法進行排序。
13.
如何計算兩個有序整型數(shù)組的交集正確答案:假設(shè)兩個含有n個元素的有序(非降序)整型數(shù)組a和b,其中a={0,1,2,3,4},b={1,3,5,7,9},那么它們的交集為{1,3}。
計算數(shù)組交集可以采用很多種方法,但數(shù)組的相對大小一般會影響算法的效率,所以需要根據(jù)兩個數(shù)組的相對大小來確定采用的方法:
1)對于兩個數(shù)組長度相當(dāng)?shù)那闆r,一般可以采取如下3種方法。
方法一:二路歸并法。設(shè)兩個數(shù)組分別為array1[n1]和array2[n2]。分別以i,j從頭開始遍歷兩個數(shù)組。在遍歷過程中,若當(dāng)前遍歷位置的array1[i]與array2[j]相等,則此數(shù)為兩個數(shù)組的交集,記錄下來,并繼續(xù)向后遍歷array1和array2。若array1[i]大于array2[j],則須繼續(xù)向后遍歷array2。若array1[i]小于array2[j],則需要繼續(xù)向后遍歷array1,直到有一個數(shù)組結(jié)束遍歷即停止。實現(xiàn)代碼如下:
importjava.util.*;
publicclassTest{
publicstaticArrayList<Integer>mixed(intarray1[],intarray2[]){
ArrayList<Integer>mix=newArrayList<Integer>();
inti=0,j=0;
intn1=array1.length;
intn2=array2.length;
while(i<n1&&j<n2){
if(array1[i]==array2[j]){
mix.add(array1[i]);
i++;
j++;
}elseif(array1[i]>array2[j]){
j++;
}elseif(array1[i]<array2[j]){
i++;
}
}
returnmix;
}
publicstaticvoidmain(String[]args){
int[]a={0,1,2,3,4};
int[]b={1,3,5,7,9};
ArrayList<Integer>mix=mixed(a,b);
for(inti=0;i<mix.size();i++)
System.out.print(mix.get(i)+"");
}
}
程序運行結(jié)果為:
13
方法二:順序遍歷法。順序遍歷兩個數(shù)組,將數(shù)組元素存放到哈希表中,同時對統(tǒng)計的數(shù)組元素進行計數(shù),若為2,則為二者的交集元素。
方法三:散列法。遍歷兩個數(shù)組中任意一個數(shù)組,將遍歷得到的元素存放到散列表,然后遍歷另外一個數(shù)組,同時對建立的散列表進行查詢,若存在,則為交集元素。
2)對于兩個數(shù)組長度相差懸殊的情況,例如,數(shù)組a的長度遠遠大于數(shù)組b的長度,則可以采用下面幾種方法。
方法一:依次遍歷長度短的數(shù)組,將遍歷得到的數(shù)組元素在長數(shù)組中進行二分查找。具體而言,設(shè)兩個指向兩個數(shù)組末尾元素的指針,取較小的那個數(shù)在另一個數(shù)組中二分查找,找到,則存在一個交集,并且將該目標(biāo)數(shù)組的指針指向該位置的前一個位置。如果沒有找到,同樣可以找到一個位置,使得目標(biāo)數(shù)組中在該位置后的數(shù)肯定不在另一個數(shù)組中存在,直接移動該目標(biāo)數(shù)組的指針指向該位置的前一個位置,再循環(huán)找,直到一個數(shù)組為空為止。由于兩個數(shù)組中都可能出現(xiàn)重復(fù)的數(shù),因此二分查找時,當(dāng)找到一個相同的數(shù)x時,其下標(biāo)為i,那么下一個二分查找的下界變?yōu)閕+1,避免x重復(fù)使用。
方法二:采用與方法一類似的方法,但是每次查找在前一次查找的基礎(chǔ)上進行,這樣可以大大縮小查找表的長度。
方法三:采用與方法二類似的方法,但是遍歷長度小的數(shù)組的方式有所不同,即從數(shù)組頭部和尾部同時開始遍歷,這樣可以進一步縮小查找表的長度。
14.
如何判斷一個數(shù)組中數(shù)值是否連續(xù)相鄰正確答案:一個數(shù)組序列,元素取值可能是0~65535中的任意一個數(shù),相同數(shù)值不會重復(fù)出現(xiàn)。0是例外,可以反復(fù)出現(xiàn)。設(shè)計一種算法,當(dāng)從該數(shù)組序列中隨意選取5個數(shù)值,判斷這5個數(shù)值是否連續(xù)相鄰。需要注意以下4點:
1)5個數(shù)值允許是亂序的,例如{8,7,5,0,6}。
2)0可以通配任意數(shù)值,例如{8,7,5,0,6}中的0可以通配成9或者4。
3)0可以多次出現(xiàn)。
4)全0算連續(xù),只有一個非0算連續(xù)。
如果沒有0的存在,要組成連續(xù)的數(shù)列,最大值和最小值的差距必須是4,存在0的情況下,只要最大值和最小值的差距小于4就可以了,所以應(yīng)找出數(shù)列中非0的最大值和非0的最小值,時間復(fù)雜度為O(n),如果非0最大-非0最小+1<=5(即非0最大-非0最小<=4),那么這5個數(shù)值連續(xù)相鄰,否則,不連續(xù)相鄰。因此,該算法的時間復(fù)雜度為O(n)。
程序代碼如下:
publicclassTest{
publicstaticBooleanIsContinuous(int[]a){
intn=a.length;
intmin=-1,max=-1;
for(inti=0;i<n;i++){
if(a[i]!=0){
if(min>a[i]||-1==min)
min=a[i];
if(mox<a[i]||-1==max)
max=a[i];
}
}
if(max-min>n-1)
returnfalse;
else
returntrue;
}
publicstaticvoidmain(String[]args){
intarray[]={8,7,5,0,6};
if(IsContinuous(array))
System.out.println("數(shù)組{8,7,5,0,6}連續(xù)相鄰\n");
else
System.out.println("數(shù)組{8,7,5,0,6}不連續(xù)相鄰");
}
}
程序運行結(jié)果為:
8,7,5,0,6連續(xù)相鄰
15.
如何求解數(shù)組中反序?qū)Φ膫€數(shù)正確答案:問題描述:給定一個數(shù)組a,如果a[i]>a[j](i<j),那么a[i]與a[j]被稱為一個反序,例如,給定數(shù)組{1,5,3,2,6},共有(5,3)、(5,2)和(3,2)三個反序?qū)Α?/p>
方法一:“蠻力”法。最容易想到的方法是對數(shù)組中的每一個數(shù)字,遍歷它后面的所有數(shù)字,如果后面的數(shù)字比它小,那么就找到一個逆序?qū)?,實現(xiàn)代碼如下:
publicclassTest{
publicstaticintreverseCount(inta[]){
intcount=0;
intlen=a.length;
for(inti=0;i<len;i++){
for(intj=i+1;j<len;j++){
if(a[i]>a[j]){
count++;
}
}
}
returncount;
}
publicstaticvoidmain(String[]args){
intarray[]={1,5,3,2,6};
intcount=reverseCount(array);
System.out.println(count);
}
}
程序運行結(jié)果為:
3
這種方法是采用二重遍歷實現(xiàn)的,因此時間復(fù)雜度為O(n^2)。
方法二:分治歸并法??梢詤ⅲ嚎細w并排序的方法,在歸并排序的基礎(chǔ)上額外使用一個計數(shù)器來記錄逆序?qū)Φ膫€數(shù)。下面以數(shù)組序列{5,8,3,6}為例,說明計數(shù)的方法,歸并的過程如下所示。
示例如下:
publicclassTest{
publicstaticintreverseCount=0;
publicstaticvoidmerge(intarray[],intbegin,intmid,intend){
inti,j,k,n1,n2;
n1=mid-begin+1;
n2=end-mid;
int[]L=newint[n1];
int[]R=newint[n2];
for(i=0,k=begin;i<n1;i++,k++)
L[i]=array[k];
for(i=0,k=mid+1;i<n2;i++,k++)
R[i]=array[k];
for(k=begin,i=0,j=0;i<n1&&j<n2;k++){
if(L[i]<R[j]){
array[k]=L[i++];
}else{
reverseCount+=mid-i+1;
array[k]=R[j++];
}
}
if(i<n1){
for(j=i;j<n1;j++,k++)
array[k]=L[j];
}
if(j<n2){
for(i=j;i<n2;i++,k++)
array[k]=R[i];
}
}
publicstaticvoidmerge_sort(inta[],intbegin,intend){
if(begin<end){
intmid=(end+begin)/2;
merge_sort(a,begin,mid);
merge_sort(a,mid+1,end);
merge(a,begin,mid,end);
}
}
publicstaticvoidmain(String[]args){
intarray[]={1,5,3,2,6};
merge_sort(array,0,array.length-1);
System.out.println(reverseCount);
}
}
程序運行結(jié)果為:
3
這種方法與歸并排序有著相同的時間復(fù)雜度O(nlogn)。
16.
如何求解最小三元組距離正確答案:問題描述:已知3個升序整數(shù)數(shù)組a[1]、b[m]和c[n]。請在3個數(shù)組中各找一個元素,使得組成的三元組距離最小。三元組的距離定義是:假設(shè)a[i]、b[j]和c[k]是一個三元組,那么距離為Distance=max(|a[i]-b[j]|,|a[i]-c[k]|,|b[j]-c[k]|),請設(shè)計一個求最小三元組距離的最優(yōu)算法。
方法一:“蠻力”法。最容易想到的方法就是分別遍歷3個數(shù)組中的元素,分別求出它們的距離,然后從這些值里面查找最小值,示例如下:
publicclassTest{
publicstaticintmax(inta,intb,intc){
intmax=a<b?b:a;
max=max<c?c:max;
returnmax;
}
publicstaticintSolvingviolence(inta[],intb[],intc[]){
intaLen=a.length;
intbLen=b.length;
intcLen=c.length;
intminDist=max(Math.abs(a[0]-b[0]),Math.abs(a[0]-c[0]),Math.abs(b[0]-
c[0]));
intdist=0;
for(inti=0;i<aLen;i++){
for(intj=0;j<bLen;j++){
for(intk=0;k<cLen;k++){
//求距離
dist=max(Math.abs(a[i]-b[j]),Math.abs(a[i]-c[k]),
Math.abs(b[j]-c[k]));
//找出最小距離
if(minDist>dist){
minDist=dist;
}
}
}
}
returnminDist;
}
publicstaticvoidmain(String[]args){
inta[]={3,4,5,7};
intb[]={10,12,14,1,5,17};
intc[]={20,21,23,24,37,30};
System.out.println(Solvingviolence(a,b,c));
}
}
這個算法的時間復(fù)雜度為O(1*m*n),顯然這個方法沒有用到數(shù)組升序這一特性,因此不是最好的方法。
方法二:最小距離法。假設(shè)當(dāng)前遍歷到這3個數(shù)組中的元素分別為ai,bi,ci,并且ai<=bi<=ci,此時它們的距離肯定為Di=ci-ai,那么可以分如下3種情況討論:
1)如果接下來求ai,bi,ci+1的距離,那么由于ci+1>=ci,此時它們的距離必定為Di+1=ci+1-ai,顯然Di+1>=Di,因此Di+1不可能為最小距離。
2)如果接下來
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 小學(xué)一年級100以內(nèi)
- 《管飼患者臨床護理》課件
- 小學(xué)數(shù)學(xué)五年級下分數(shù)混合運算
- 《施工視頻截圖》課件
- 《管子加工及連接》課件
- 《刑事訴訟法立案》課件
- 廣東省深圳市福田區(qū)2023-2024學(xué)年高三上學(xué)期期末考試英語試題
- 《滴眼藥水的護理》課件
- 游戲行業(yè)技術(shù)工作概覽
- 水果店前臺服務(wù)總結(jié)
- 水利水電工程安全管理制度例文(三篇)
- 2025四川宜賓市南溪區(qū)屬國企業(yè)招聘融資人員6人管理單位筆試遴選500模擬題附帶答案詳解
- DB45T 2048-2019 微型消防站建設(shè)管理規(guī)范
- 2025年超星爾雅學(xué)習(xí)通《勞動通論》章節(jié)測試題庫及參考答案(培優(yōu))
- SCTP大云云計算PT2題庫【深信服】認證考試題庫及答案
- 外研版(2024新版)七年級上冊英語期末質(zhì)量監(jiān)測試卷 3套(含答案)
- 《測土配方施肥》課件
- 新疆烏魯木齊市(2024年-2025年小學(xué)六年級語文)統(tǒng)編版質(zhì)量測試(上學(xué)期)試卷及答案
- 人教版2024-2025學(xué)年第一學(xué)期八年級物理期末綜合復(fù)習(xí)練習(xí)卷(含答案)
- 職業(yè)健康檢查管理制度
- 電梯維保管理體系手冊
評論
0/150
提交評論