完美的數組(用了三種優化程度不一樣的方法來寫的)

一個數組被稱爲完美的,當且僅當其中存在一個元素,它的值是除了它之外剩下的所有元素的和。
蒜頭君現在獲得了一個數組。他想去掉數組中的一個元素,使得這個數組變成完美的。
他想知道這個數組有幾種方案可以變成完美的。當去掉的元素在原數組中的位置不同時,即爲不同的方案。

輸入格式:
輸入的第一行包含一個整數n(2<=n<=200000).
輸入的第二行包括n個整數,爲蒜頭君獲得的數組裏面的每個元素ai(2<=ai<=1000000)
輸出格式:
輸出有兩行。
第一行是方案的個數 k。第二行有 k個用單個空格分開的整數,分別表示去掉的元素在原數組中的位置(按照輸入的順序)。
說明:如果沒有方案,輸出一個 0 即可。
示例1:
輸入
5
2 5 1 2 2
輸出:
3
1 4 5
示例2:
輸入:
4
8 3 5 2
輸出:
2
1 4
方法一:這個方法是最容易理解的,但是不夠優化,運行時間過長

`#include<iostream>
#include<cstring>
using namespace std;
int main()
{
    int n;
    cin>>n;
    int a[200000],b[200000];
    int k=0,i,j;
    int sum=0;
    for( i=0;i<n;i++)
    {
        cin>>a[i];
        sum+=a[i];//將所有數相加
    }
    for( i=0;i<n;i++)//這裏a[i]是去掉的數
    {
    for(j=0;j<n;j++)
    {
        if(2*a[j]==(sum-a[i]))//如果一個數的二倍等於剩下數的和,則是完美的
        {
            
           b[k++]=i+1;//這裏是i+1,因爲要的是位置
           break;
        }
        
    }
    }
    cout<<k<<endl;
    for(i=0;i<k;i++)
        cout<<b[i]<<" ";
    return 0;
}
`

方法二:這一種方法對於上一個來說已經優化了些,因爲是完美數組,則剩下數的和一定是等於這個數組中最大的那個數,所以只要判斷最大的數是不是等於剩下數的和就可以。
但這個要判斷去掉的這個數是不是最大值。這個是重點。

#include<iostream>
using namespace std;
int main()
{
    int n,sum=0,a[200000],b[200000];
    cin>>n;
    int i,j,k=0;
    int sum2;
    int max=0;
    for(i=0;i<n;i++)
    {
        cin>>a[i];
        sum+=a[i];
        if(a[i]>max) max=a[i]; //記錄最大值
     }
    for(i=0;i<n;i++)
    {
        sum2=sum-a[i];//a[i]是刪去的數
        //如果去掉的不是最大值
        if(a[i]!=max) 
        {
            if(2*max==sum2)
            {
                b[k++]=i+1;
            }
            continue;//**如果去掉的數不是最大值,就執行這條語句,跳出本次循環,就不會再執行下面的語句了,接着再判斷下面一個去掉的數是不是最大值**
        }
        //如果去掉的是最大值
        for(j=0;j<n;j++)
        {
            if(j==i)  continue;//如果j==i則這次循環不執行,判斷下一個數
            if(2*a[j]==sum2)
            {
                b[k++]=i+1;
                break;
            }
        }
    }
    cout<<k<<endl;
    for(i=0;i<k;i++)
        cout<<b[i]<<' ';
    return 0;
}

方法三:這個可以算是最優的一個方法了,我也就只想到着了。
這個思路是,因爲剩下的數的和是等於數組中最大值,所以把最大的數去掉後,就該考慮次大值了,這個次大值可以等於最大值,就是說這個數組中可以有相同的數,且這相同的數是最大的數。


#include<iostream>
using namespace std;
int main()
{
    int n,sum=0,a[200000],b[200000];
    cin>>n;
    int i,j,k=0;
    int sum2;
    int max1=0,max2=0;//max1>=max2
    for(i=0;i<n;i++)
    {
        cin>>a[i];
        sum+=a[i];
        if(a[i]>max1) 
        {
            max2=max1;
            max1=a[i]; 
        }
        else if(a[i]>max2)//存在一些數小於max1,但大於max2
        {
            max2=a[i];
        }    
     }//最大值次大值都找到
    for(i=0;i<n;i++)
    {
        sum2=sum-a[i];//a[i]是刪去的數
        //如果去掉的不是最大值,則就用最大值比較
        if(a[i]!=max1) 
        {
            if(2*max1==sum2)
            {
                b[k++]=i+1;
            }
    
        }
       else//如果去掉的是最大值,則用次大值比較
       {      
        if(2*max2==sum2)
            {
                b[k++]=i+1;
            }
       }
    }
    cout<<k<<endl;
    for(i=0;i<k;i++)
        cout<<b[i]<<' ';
    return 0;
}

或者這樣寫:

#include<iostream>
using namespace std;
int main()
{
    int n;
    cin>>n;
    int a[200000],b[200000];
    int k=0,i,j;
    int sum=0,Max=0,max=0;//Max爲原數組最大值,max爲除去最大值後的次最大值(可以等於最大值)
    int temp; //用於標記原數組最大值的位置i
    for( i=0;i<n;i++)
    {
        cin>>a[i];
        sum+=a[i];
        if(a[i]>Max) {Max=a[i];temp=i;}
    }
    for(i=0;i<n;i++)
    {
        if(a[i]>max&&temp!=i)
        {
            max=a[i]; //表示次最大值
        }
    }
    double x;
    for(i=0;i<n;i++)
    {
        x=(double)(sum-a[i])/2.0;
        if(a[i]!=Max&&x==Max)//除去的數不是最大值
        {
            b[k++]=i+1;
        }
        if(a[i]==Max&&x==max)//除去的數是最大值則考慮次最大值
        {
            b[k++]=i+1;
        }
    }
         cout<<k<<endl;
    for(i=0;i<k;i++)
        cout<<b[i]<<" ";
    return 0;
}

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