问题描述:长度为n的整形数组,找出其中的任意n-1个数乘积最大的那一组,可以用乘法,但不能用除法,要求对算法处理的 时间复杂度和空间复杂度做出分析。
方法一:
首先能想到的一般方法就是暴力求解法。假设去掉第一个元素,求剩下n-1个乘积赋值给max,同时记录下下标index;然后假设第二个元素去掉,求剩下n-1个的乘积,若比前一个大则max等于当前值,index更新。重复此过程一直到最后一个元素。最后得到的max就是除去下标为index的n-1个元素乘积的最大值。
int max=0;
int index=0;
for(int i=0;i<a.length;i++){
int j=0;
int muti =1;
while(true){
if(j!=i){
mutil *=a[j];
}
j++;
if(j==a.length)
break;
}
if(max<mutil){
max =mutil;
index = i;
}
}
for(int i=0;i<a.length;i++){
if(index!=i)
System.out.print(a[i]+ " ");
}
方法的时间复杂度为O(n^2),空间复杂度为O(1)
方法二:
既然事先给定n给整数,那么其乘积是一定的。不妨设这n个数的乘积为P,那么求n-1个数的乘积的最大值只需求P/a[i]的最大值。而题目要求说不能使用除法,那么转化思路。P/a[i]=(P*a[i])/a[i]^2,其中a[i]^2一定是正数,可以发现P/a[i]和P*a[i]同正负。现在我们可以把P/a[i]跟P*a[i]联系起来。
P的可能取值可能为正、负和0。
a. P值为正的情况。
问题转化求Max(P/a[i]),如果此时有至少一个a[m]为正值,那么Max(P/a[i])必定为正值,所以P*a[i]也必定为正值i(指数组元素为正值的下标)。因为P为正值,且P*a[i]的值越大表明a[i]的值越大,那么P/a[i]的值就会越小;P*a[i]的值越小表明a[i]的值越小,那么P/a[i]的值就会越大。那么问题转化为求P*a[i]的最小正值,即求a[i]的最小正值,剩余n-1个元素的乘积最大。
如果此时a[i]全为负值,那么找出a[i]中最小的那个,剩余n-1个元素的乘积最大。
b.P为负值的情况
问题还是求Max(P/a[i]),那么此时有至少一个a[m]为负值,那么Max(P/a[i])必定为正值,所以P*a[i](i指数组元素为负值的下标)也必定为正值。因为P为负值,且P*a[i]的值越大表明a[i]的值越小,也就是a[i]的绝对值越大,那么P/a[i]的值就会越小;P*a[i]的值越小表明a[i]的值越大,a[i]为负数绝对值越小,那么P/a[i]的值就会越大。那么问题转化为求P*a[i]的最小正值,此处P为负值,所以应该求负数集合a[i]中的最大值,对应绝对值最小。c.P为0的情况
P为0 ,意味着数组中存在至少一个0。
找出为0 的元素,若大于一个,那么n-1个元素的最大值乘积为0此,只要包含0元素的集合均满足条件,也就是任取n-1个元素(题目是说求一组,应该不会出现这种情况);若只有一个,那么求出0元素以外的乘积,若该乘积为负,则n-1个元素的最大乘积为0,只要包含0的元素集合均满足条件。若该乘积为正,则除0元素的外的n-1个满足条件。结论:
n个元素的乘积为正,且有元素为正,那么排除该正整数集中的最小值剩下的n-1个元素即为所求。若n个元素全为负,则找负正整数集中的最小值,排除该元素后剩余的n-1个即为所求。
n个元素的乘积为负,那么找出该负正整数集中最大的元素,排除该元素后,剩余的元素即为所求。
有一个0元素,求其余元素的正负;有两个0元素,任意n-1个元素均满足条件。
public class FindNum{
private static int zero =0;//0元素个数
private static int zeroIndex=0;//0元素所在位置
private static int positiveCounts =0;//正整数个数
private static int negitiveCounts =0;//负整数个数
private static int p=1;//标志N个数的乘积的正负
private static int index =0;//待排除元素的下标
public void init(){
for(int i=0;i<a.length;i++){
if(a[i]==0){
zero++;
zeroIndex=i;
}else if(a[i]>0){
positiveCounts++;
}else {
negitiveCounts++;
}
}
}
//求乘积的正负
public int getP(int zero ,int negitiveCounts){
if(zero!=0) return 0;
if(negitiveCounts%2==0) return 1;
return -1;
}
//flag=1,找正整数集中最小值;flag =-1,找负整数集的最小值;
//flag=0,找负整数集中最大值。
public int getIndex(int flag){
int index=0;
if(flag>=1){
int cmp=0;
for(int i=0;i<a.length;i++){
if(a[i]>0&&cmp>a[i]){
cmp=a[i];
index=i;
}
}
}else if(flag<=-1) {
int cmp=0;
for(int i=0;i<a.length;i++){
if(a[i]<0&&cmp>a[i]){
cmp=a[i];
index=i;
}
}
} else {
int cmp=a[0];
for(int i=0;i<a.length;i++){
if(a[i]<0&&cmp<a[i]){
cmp =a[i];
index=i;
}
}
}
return index;
}
//打印
public void print(int index){
for(int i=0;i<a.length;i++){
if(index!=i)
System.out.print(a[i]+ " ");
}
}
public static void main(String [] args){
FindNum f = new FindNum();
f.init();
p=getP(0,negitiveCounts);
if(zero=1){
if(p>0) print(zeroIndex);
else if(p<0) 包含0的n-1个元素都可以
} else if(zero>1){
任意N-1个元素都可以
} else {
if(p>0){
if(positiveCounts>0){
index =getIndex(1);//返回正整数集中最小值
}else {
index = getIndex(-1);//返回负整数集中最小值
}
}else if(p<0){
index = getIndex(0);//返回负整数中的最大值
}
print(index);
}
}
该算法的时间复杂度为O(n),空间复杂度为O(1)