阿里線上程式設計,去除三個元素,四等分陣列問題!
阿新 • • 發佈:2019-01-31
/**
* Created by lw_co on 2017/3/3.
*/import
java.util.*;publicclassSolution{/**
請完成下面這個函式,實現題目要求的功能 **//**
當然,你也可以不按照這個模板來作答,完全按照自己的想法來 ^-^ **//**
*
* 對於一個長度為N的整型陣列A, 數組裡所有的數都是正整數,對於兩個滿足0<=X <= Y <N的整數,A[X], A[X+1] … A[Y]構成A的一個切片,記作(X, Y)。
用三個下標 m1, m2, m3下標滿足條件 0 < m1, m1 + 1 < m2, m2 +1 < m3 < N – 1。
可以把這個整型陣列分成(0, m1-1), (m1+1, m2-1), (m2+1, m3-1), (m3+1, N-1) 四個切片。如果這四個切片中的整數求和相等,稱作“四等分”。
編寫一個函式,求一個給定的整型陣列是否可以四等分,如果可以,返回一個布林型別的true,如果不可以返回一個布林型別的false。
限制條件: 陣列A最多有1,000,000項,陣列中的整數取值範圍介於-1,000,000到1,000,000之間。
要求: 函式的計算複雜度為O(N),使用的額外儲存空間(除了輸入的陣列之外)最多為O(N)。
例子:
對於陣列A=[2, 5, 1, 1, 1, 1, 4, 1, 7, 3, 7] 存在下標 2, 7, 9使得陣列分成四個分片[2, 5], [1, 1, 1, 4], [7], [7],這三個分片內整數之和相等,所以對於這個陣列,函式應該返回true。
對於陣列 A=[10, 2, 11, 13, 1, 1, 1, 1, 1], 找不到能把陣列四等分的下標,所以函式應該返回false。
*//****************************************************//**
* 注意:
* 1、只刪除3個元素,等分為四份。
* 2、陣列元素為正整數。
* 3、疑問:後面又說整數取值範圍介於-1,000,000到1,000,000之間?明顯混淆視聽,看來阿里的題考查閱讀與觀察啊!
* 方法一:
* 1、先二等分,去除中間那個元素。至少中間左邊還是右邊有待考證
*此方法有bug
*
* *//**
* indexBegin開始索引,indexEnd結束索引。
* 在sumArr,與chooseRemove中均計算的是indexBegin<=i<indexEnd的元素。
* 元素分佈:0至v1-1,v1+1到v2-1,v2+1到N-1
* *//**測試用例:
* {1,1,1,1,7,1,3,4,1,2,1,5,2,2} true;把7換成10,把4換成1,原式也可等分,但卻如下
* {1,1,1,1,10,1,3,1,1,2,1,5,2,2} false;
* {2,2,5,1,2,1,1,3,1,10,1,1,1,1} false;上面的倒序。看來與順序無關,演算法還是存在問題,此種解法存在問題。
*
* *///方法二**********************************************/**
* 從兩邊開始找,找到之後再找中間
* 技巧,注意到只刪除3個元素,又因為要第一分組與第四分組相等.
* 設等分值為v,第一分組n1與第二分組元素n4個數共為n,則2<=N-3-n<=2v;
* 此方問題,能夠解決方法一的問題*/staticbooleanresolve2(int[]
A) {if(A==null
|| A.length==0){returnfalse;}int[]
re=findValLocate(A);
System.out.println("尋找完畢,開始檢查:
"+Arrays.toString(re));
re[2]=checkingFind(A,re[0],re[1]+1,re[3]-1);//減1是由於有4部分,最後一部分至少佔用1個位置。
System.out.println("檢查:
"+Arrays.toString(re));int
v3=checkingFind(A,re[0],re[2]+1,re[3]);//檢查第四部分,的分割點是否為re[3]if(v3==re[3]){returntrue;
} returnfalse;
} staticintcheckingFind(int[]
A ,int
val,int
begin,int
end){int
s=0;for(int
i=begin;i<end;++i){ s=s+A[i]; if(s==val){//返回要去除那個點。return
i+1;
} } return
-1;
} /*返回均分值,與要去除的第一個和第三個位置*/staticint[]findValLocate(int[]
A){ int
v1=0,v4=0;for(int
i=0,j=A.length-1;i<j;){if(v1<v4){
v1=v1+A[i]; ++i; }elseif(v1>v4){
v4=v4+A[j]; --j; }else{/*驗證:2<=N-3-n<=2v*/int
m=A.length-3-(i+1+A.length-j);if(m>=2
&& m<=2*v1
){ /*這裡返回的是去除點的位置,i,j沒有加減,
是因為以前的操作都讓它向後移了一位了,
現在指的就是要去除的點*/int
re[]={v1,i,0,j};return
re; }else{
v1=v1+A[i]; ++i; } } } returnnull;
} //方法二結束**********************************************//方法一(此方有問題)**********************************************staticbooleanresolve(int[]
A) {if(A==null
|| A.length==0){returnfalse;}int
v2=chooseRemove(A,0,A.length-1);int
v1=chooseRemove(A,0,v2-1);int
v3=chooseRemove(A,v2+1,A.length-1);int
s1=sumArr(A,0,v1-1);int
s2=sumArr(A,v1+1,v2-1);int
s3=sumArr(A,v2+1,v3-1);int
s4=sumArr(A,v3+1,A.length-1);
System.out.println("去除的元素依次是:A["+v1+"]="+A[v1]+"
; " +"A["+v2+"]="+A[v2]+"
; " +"A["+v3+"]="+A[v3]+"
; "); System.out.println("四個部分和是:"+"s1="+s1+"
; " +"s2="+s2+"
; " +"s3="+s3+"
; " +"s4="+s4+"
; ");if(s1==s2&&s3==s4&&s2==s3){returntrue;
} returnfalse;
} staticintsumArr(int[]
A, int
indexBegin, int
indexEnd){int
sum=0;for(int
i=indexBegin; i<=indexEnd;++i){ sum =sum +A[i]; } return
sum; } staticintchooseRemove(int[]
A, int
indexBegin, int
indexEnd){int
ave=sumArr(A,indexBegin,indexEnd)/2;int
val=0;for(int
i=indexBegin;i<=indexEnd;++i){ val=val+A[i]; if(val>ave){return
i; } } return
-1;
} //方法一結束**********************************************publicstaticvoidmain(String[]
args){/*ArrayList<Integer>
inputs = new ArrayList<Integer>();
Scanner in = new Scanner(System.in);
String line = in.nextLine();
while(line != null && !line.isEmpty()) {
int value = Integer.parseInt(line.trim());
if(value == 0) break;
inputs.add(value);
line = in.nextLine();
}
int[] A = new int[inputs.size()];
for(int i=0; i<inputs.size(); i++) {
A[i] = inputs.get(i).intValue();
}*///int[]
A={1,1,1,1,7,1,3,4,1,2,1,5,2,2};int[]
A={1,1,1,1,10,1,3,1,1,2,1,5,2,2};
Boolean res = resolve2(A);
System.out.println(String.valueOf(res));
}}