zoukankan      html  css  js  c++  java
  • 剑指offer自学系列(二)

    题目描述:

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

    题目分析:

    如果我们采用两个变量去找重复的值,需要嵌套两个循环,最坏的情况是,末尾的两个值是重复的,这显然不是我们想要的答案,如果采用排序的方式得到有序数组,然后从头到尾检索,很容易就能找到第一个重复的值,排序我们采用快速排序,排序时间复杂度为o(nlogn),检索重复的值时间复杂度为o(n),我们也可以采用空间换时间,实现一个hash表,时间复杂度为o(n),检索数组,将值存到hash表中,如果hash表里没有出现这个值,就存到hash表中,如果出现过这个值,那就是我们想要的重复的值,每次查找需要o(1)的时间复杂度。

    由于所有数字都在0到n-1的范围内,和数组下标恰好相对应,我们可以用交换的方法快速找到重复的值,以{2,3,1,0,2,5,3}为例:

    首先第一个值为2,与下标为2的1交换,{1,3,2,0,2,5,3}

    第二步交换后的值为1,继续与下标为1的值交换,{3,1,2,0,2,5,3}

    第三步交换后的值为3,与下标为3的值交换,{0,1,2,3,2,5,3}

    第四步,前四个值都有序,第五个值为2,与下标为2的值交换,而第二个值已经是2,结束

    代码如下:

    #include<iostream>
    using namespace std;
    
    bool duplicate(int numbers[],int length,int* duplication) {
        if (numbers == nullptr || length <= 0) {
            return false;
        }
        for (int i = 0; i < length;++i) {
            if (numbers[i]<0 || numbers[i]>length - 1)
                return false;
        }
        for (int i = 0; i < length;++i) {
            while (numbers[i] != i) {
                if (numbers[i] == numbers[numbers[i]]) {
                    *duplication = numbers[i];
                    return true;
                }
                int temp = numbers[i];
                numbers[i] = numbers[temp];
                numbers[temp] = temp;
            }
        }
    }
    
    int main() {
        int A[7] = {2,3,1,0,2,5,3};
        int len = 7;
        int i = 0;
        int duplication;
        bool results = duplicate(A, 7,&duplication);
        cout << results << endl;
        cout << duplication << endl;
    }

    在写的过程中,我碰到了几个问题,算是C++基础问题,在此总结一下,我思索函数为什么要引用&duplication,直接用duplication不行嘛,尝试了一下报错,提示我这是局部变量,值传不回来的,所以通过对地址修改才能得到这个值,还有一点,我原以为会传两个值,2和3,但是return true返回后函数体部分就结束了,所以只会返回一个值,在此做笔记是为了加强自己记忆,不要再犯基础知识上的错误。

    题目描述:

    给定一个数组A[0,1,…,n-1],请你构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]xA[1]x…xA[i-1]xA[i+1]x…xA[n-1],要求不能使用除法

    题目分析:

    对于这个题目,由于要求我们不能采用除法,所以只能采用巧妙的方法计算这些数的乘积,我们首先表示B数组

    B[0] = A[1]xA[2]x…xA[i-1]xA[i]x…xA[n-2]xA[n-1]

    B[1] = A[0]xA[2]x…xA[i-1]xA[i]x…xA[n-2]xA[n-1]

    B[i-1] = A[0]xA[1]x…xA[i-2]xA[i]x…xA[n-2]xA[n-1]

    B[i] = A[0]xA[1]x…xA[i-1]xA[i+1]x…xA[n-2]xA[n-1]

    B[n-2] = A[0]xA[1]…xA[i-1]xA[i]x…xA[n-3]xA[n-1]

    B[n-1] = A[0]xA[1]…xA[i-1]xA[i]x…xA[n-3]xA[n-2]

    为了让它们数组显得更有规律,写成矩阵如下

    这里写图片描述

    我们把被除的那些值用1代替即可以化除法为乘法,符合题目要求,下面是找到一种减少时间复杂度的方法,我们将表分成两部分,以1的斜对角线为分界线,上面从上到下相乘,下面从下往上乘,最后乘到一起即得到需要的值,代码如下:

    #include<iostream>
    #include<vector>
    using namespace std;
    
    void multipy(const vector<double> A,vector<double> B) {
        int lenA = A.size();
        int lenB = B.size();
        if (lenA == lenB && lenB > 1) {
            B[0] = 1;
            for (int i = 1; i < lenA; ++i) {
                B[i] = A[i - 1] * B[i - 1];
            }
            double temp = 1;
            for (int i = lenA - 2; i >= 0; --i) {
                temp = temp * A[i + 1];
                B[i] = B[i] * temp;
            }
            for (int i = 0; i < lenA; ++i) {
                cout << B[i] << endl;
            }
        }
    }
    
    int main() {
        vector<double> A = {1,2,1,2,1,2,1};
        vector<double> B = {1,1,1,1,1,1,1};
        multipy(A, B);
        return 0;
    }

    参考:

    https://blog.csdn.net/qq_33278461/article/details/80144734(矩阵图片)

  • 相关阅读:
    SQL注入原理
    攻防世界-wp
    BUUCTF-warmup
    springboot邮箱验证功能部署到服务器后报25 timeout的解决方式
    关于MySQL建立库表时大写自动转换为小写的解决方案
    springboot格式化timestamp时间
    mysql高级查询
    pip更新一直time out 的解决方法
    关于springboot使用mybatis查询出现空指针,以及debug出现All Elements all Null的解决方法
    抽象工厂模式
  • 原文地址:https://www.cnblogs.com/51selfstudy/p/10603312.html
Copyright © 2011-2022 走看看