zoukankan      html  css  js  c++  java
  • 剑指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

  • 相关阅读:
    图文详解 Android Binder跨进程通信机制 原理
    支链氨基酸怎么吃
    C#泛型约束
    树状结构 Tree data structure in C#
    wrap ConcurrentDictionary in BlockingCollection
    ConcurrentBag扩展 批量加入
    Dictionary GetOrAdd
    ConcurrentDictionary AddOrUpdate
    object pool
    C# 结构体定义 转换字节数组 z
  • 原文地址:https://www.cnblogs.com/oneDongHua/p/14264026.html
Copyright © 2011-2022 走看看