剑指offer-数组

题目一:

给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。

class Solution {
public:
    vector<int> multiply(const vector<int>& A) {
        vector<int> res(A.size(),0);
        res[0]=1;
        for(int i=1;i<A.size();i++)
        {
            res[i]=res[i-1]*A[i-1];
        }
        int temp=1;
        for(int i=A.size()-2;i>=0;i--)
        {
            temp*=A[i+1];
            res[i]*=temp;
        }
        return res;
    }
};

剑指的思路:

B[i]的值可以看作下图的矩阵中每行的乘积。

下三角用连乘可以很容求得,上三角,从下向上也是连乘。

因此我们的思路就很清晰了,先算下三角中的连乘,即我们先算出B[i]中的一部分,然后倒过来按上三角中的分布规律,把另一部分也乘进去。

 

题目二:

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

方案一:

class Solution {
public:
    // Parameters:
    //        numbers:     an array of integers
    //        length:      the length of array numbers
    //        duplication: (Output) the duplicated number in the array number
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    bool duplicate(int numbers[], int length, int* duplication) {
        bool * flag= new bool[length]();
        for(int i=0;i<length;i++)
        {
            if(flag[numbers[i]]==1){
                *duplication=numbers[i];
                return 1;
            }
            flag[numbers[i]]=1;
        }
        delete []flag;
        return 0;
    }
};

此方案需要提供额外的空间来记录。

方案二:

class Solution {
public:
    // Parameters:
    //        numbers:     an array of integers
    //        length:      the length of array numbers
    //        duplication: (Output) the duplicated number in the array number
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    bool duplicate(int numbers[], int length, int* duplication) {
        for(int i=0;i<length;i++)
        {
            int temp=numbers[i]>=length? numbers[i]-length:numbers[i];
            if(numbers[temp]>=length)
            {
                *duplication=temp;
                return 1;
            }
            numbers[temp]=numbers[temp]+length;
        }
        return 0;
    }
};

此方案充分利用了题中的信息,在原数组中进行标记。

不过也会存在一些问题:

牛客320481号 :

如果 numbers[index] + length 非常大,溢出了怎么办?
 

inwhites

这样写不对,你改变了数组中的值,本题有一个条件就是数组中的数从0-n-1,如果数组中出现大于n的数就是不合格的数组,要返回false,你这样加一个长度会导致分不清是原数组是不是有问题

牛客873413号 :

用减去length比较好,不会溢出

whatname :

不管是加length还是减length都有问题,乘以-1肯定没有问题,可以看我的回答哈~

题目三:

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

方案一(暴力求解):

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        int length =data.size();
        if(length<2) return;
        bool num=0;
        for(int i=0;i<length;i++)
        {
            int j=0;
            for(;j<length;j++)
            {
                if(i!=j&&data[j]==data[i])
                    break;
            }
            if(j==length&&num==0){
                *num1=data[i];
                num=1;
            }
            else if(j==length&&num==1)
            {
                *num2=data[i];break;
            }
        }
    }
};

方案二(记录表):

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        map<int ,int> record;
        for(int i=0;i<data.size();i++)
            record[data[i]]++;
        bool num=0;
        for(int i=0;i<data.size();i++){
            if(record[data[i]]==1&&num==0)  {*num1=data[i]; num=1;}
            else if(record[data[i]]==1&&num) {*num2=data[i]; break;} 
        }
    }
};

方案三(位运算):

首先:位运算中异或的性质:两个相同数字异或=0一个数和0异或还是它本身

只有一个数出现一次时,我们把数组中所有的数,依次异或运算,最后剩下的就是落单的数,因为成对儿出现的都抵消了。

依照这个思路,我们来看两个数(我们假设是AB)出现一次的数组。我们首先还是先异或,剩下的数字肯定是A、B异或的结果,这个结果的二进制中的1,表现的是A和B的不同的位。我们就取第一个1所在的位数,假设是第3位,接着把原数组分成两组,分组标准是第3位是否为1。如此,相同的数肯定在一个组,因为相同数字所有位都相同,而不同的数,肯定不在一组。然后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。

class Solution {
public:
    int AllXor(vector<int>& data){
        int res=0;
        for(int i=0;i<data.size();i++){
            res^=data[i];
        }
        return res;
    }
    int Find1Pos(int towXor){
        int res=1;
        while((res&towXor)==0)
            res=res<<1;
        return res;
    }
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        int towXor=AllXor(data);
        int pos1=Find1Pos(towXor);
        *num1=0;*num2=0;
        for(int i=0;i<data.size();i++)
        {
            if((data[i]&pos1)==0)
                *num1^=data[i];
            else
                *num2^=data[i];
        }
    }
};

 

 

 

参考;https://www.nowcoder.com/profile/8898732/codeBookDetail?submissionId=19309621

posted @ 2019-08-13 21:56  DH_HUSTer  阅读(8)  评论(0编辑  收藏  举报