昨天做了一道很有意思的题,大概是说把一个数组等分,但是不是全部等分,而且要去掉等分之间的那个数。(不方便把题目说清楚啦)
然后重点是要求时间复杂度为O(n),空间复杂度最高不超过O(n)。
当时做的时候很紧急,怕交白卷,直接暴力的用多重循环来做了。主要根本没时间想,紧张起来就没思路。
后来晚上11点半,睡前冥思苦想,最后想到了一种办法,但是无法证明这个方法是不是正确的。
我的思维是这样的,如果要把一个数组N等分,那么需要去掉的的数就有N-1个。
而空间复杂度要求O(N),那么循环套循环是不可取的,但是求和的过程本身就是一个循环,如何一次循环就能求到想要的和呢?
空间复杂度也是O(N),不可能用来存放所有的和的组合可能性。
而且需要判断这个数组能不能N等分,判断不能直接判断,因为去掉的N-1的个可正可负。只能通过不满足一定的条件输出false。
比如给出测试用例:A={3,7,1,2,1,5,2,17,10,1,1,9} 如果把A四分,就是{3,7}{2,1,5,2}{10}{1,9};
我最后最后想到的方法是,设立N-1个标志位,每个标志位上对应的是应该剔除的元素,通过判断每个标志位是否两边相等,移动标志位到能够相等。
如果两个标志位相邻,则输入flase了。
为了避免无限循环的情况,我要求第一个和最后一个标志位只能向内移动,不能回移。
下面是我的代码,边想边写的,写的乱七八糟的,也不改了,表达的就是上面这个思想吧。
/**
*
*/
package ReadyForTest;
import java.util.*;
import java.math.*;
/**
* * @author LilyLee
* @date 2017年3月4日
* @Version
*
*/
public class reserive {
boolean res(int[] A){
int len=A.length;
int flag1=1;
int flag2=(len+1)/2;
int flag3=len-2;
int sum1=0;
int sum2=0;
int sum3=0;
int sum4=0;
sum1 = sum(0, flag1 - 1, A);
sum4 = sum(flag3 + 1, len - 1, A);
sum2 = sum(flag1+ 1, flag2 - 1, A);
sum3 = sum(flag2 + 1, flag3 - 1, A);
while(true){
if(sum1==sum2&&sum1==sum3&&sum1==sum4){System.out.println("true"); return true;}
if((flag1+1==flag2)||(flag2+1==flag3)){System.out.println("false"); return false;}
int aa=Math.abs(sum2-sum1);
int bb=Math.abs(sum3-sum2);
int cc=Math.abs(sum4-sum3);
int max=(aa>bb)?aa:bb;
max=(max>cc)?max:cc;
if(aa==max){
if(sum1<sum2){
sum1+=A[flag1];
flag1=flag1+1;
sum2-=A[flag1];
}
}
if(bb==max){
if(sum2<sum3){
sum2+=A[flag2];
flag2+=1;
sum3-=A[flag2];
}
else {
sum3+=A[flag2];
flag2-=1;
sum2-=A[flag2];
}
}
if(cc==max){
if(sum3>sum4){
sum4+=A[flag3];
flag3-=1;
sum3-=A[flag3];
}
}
}
}
public static void main(String args[]){
int []A={2,5,1,1,1,1,4,1,7,3,7};
//int []A={10,2,11,13,1,1,1,25,1};
//int []A={10,2,11,13,1,1,1,1,1};
//int [] A={3,7,1,2,1,5,2,18,10,1,1,9} ;
//int [] A={9,1,1,10,18,2,5,2,1,1,7,3} ;
reserive se=new reserive();
se.res(A);
}
public static int sum(int i, int j, int[] arr) {
int sum = 0;
for (int k = i; k <= j; k++) {
sum += arr[k];
}
return sum;
}
}