【数据结构与算法(一)】——数组

这是第一天==> 来自《剑指offer》

数组

1、最简单的数据结构
2、占据连续的内存,然后是按照顺序存储数据的
3、使用数组时,先创建,这个时候需要指定数组的容量大小,这样就根据大小分配内存了,计算机也不管你在这个内存中存储了多少数据,反正就是根据你指定的大小让你这个数据占据这么大的内存。所以数组会有以下缺点:第一个就是空间利用率不好,有时候就是会有空闲的区域占据了但是没有存储数据,没有被利用
4、因为是连续的,所以读/写数据的时间是O(1),时间效率可以说是很高了【一个特殊的hash表(键-值对)】
5、vector:一种动态数组,就是为了避免浪费,先为数组开辟较小的空间,之后再根据需要进行扩容(这个扩容的过程是,扩大为原来容量的两倍,之后把之前的数据复制到新的数组vector中,之后释放原来的内存),这个过程其实很消耗时间的
6、数据与指针:数组的名字就是一个指针,这个指针指向数组的第一个元素;还有就是C++并没有记录数组的大小,这就意味着我们访问数组中的元素时,要确定没有超过边界。

题目

数组中重复的数字

在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

OS:我就面试过那可怜的一两次,这。。复习的第一道题就是我遇到过的~~可以的~可以的?记得当时完全没有思路,就是先想到了用map计数,但是面试官说最好不要一开始就想到C++的STL,用STL一般都会占用很大内存,这道题完全不必要用这么大的“工程”,后面我有想到排序,但面试官好像不是很满意,就提示说可以让数据变为0,问我除了相减,还有什么能使相同的数据变为0,我回到了异或,但其实到现在我还是每相通怎么用异或做这道题。感受就是空间复杂度和时间复杂度是很重要的
###思路:
1、排序:需要时间O(nlogn),从头到尾扫描排序后的数组(先排序+后扫描,这是两个操作)
2、hash表:时间O(n),空间O(n).emmmm,以空间换时间。就是
3、题目说的是数组中的数字都是再0~n-1,这。好像一开始就没被我重视过。这样一来,如果数组中没有重复的数字,那么当数组排序后数字i就只会出现在下标i的位置(所以还是得先排序),所以当有重复的数字时,那个重复的数字就不能再它应在的下标的位置了。举个例子:{2,3,1,0,2,5,3}
①比较第0个:a[0]=2,所以把它和a[2]=1调换 ==> {1,3,2,0,2,5,3}
②再比较第0个:a[0]=1,所以把它和a[1]=3调换 ==> {3,1,2,0,2,5,3}
③再比较第0个:a[0]=3,所以把它和a[3]=0调换 ==> {0,1,2,3,2,5,3}
④再比较第0个,a[0]=0,终于不用换了,a[1]=1……a[3]=3
⑤比较a[4]=2,这个时候,已经比较到第4个位置了,也就是说第二个位置a[2]=2了,所以2就是第一个出现重复的数字
每个元素(是说值,不是说某个下标)最多只要交换两次就能到达自己应到的位置,所以时间为2*n,O(n);空间复杂度的话,它没有开启新的空间,还是利用自己原来占有的空间,所以是O(1)
下面根据思路先自己写一遍代码。之后看看答案:

class Solution {
public:

    bool duplicate(int numbers[], int length, int* duplication) {
        int temp;
        for(int k=0;k<length;k++)
        {
            if(numbers[i]<0 || numbers[i]>length-1)
                return false;
        }
        //下面开始是自己写的部分,虽然通过了测试。但是发现没有测试异常情况就是输入的数值不在0~n-1之间,所以就根据参考答案加了判断部分
        if (numbers != nullptr && length > 1) {
            for (int i = 0; i < length; i++) {
                while ((temp=numbers[i]) != i) {
                    if (numbers[i] == numbers[numbers[i]]) {
                        *duplication = numbers[i];
                        return true;
                    }
                    numbers[i] = numbers[temp];
                    numbers[temp] = temp;
                }
            }
        }
        return false;
    }
};

不修改数组找出重复的数字

在一个长度为n+1的数组里所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。例如输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或者3

思路

1、粗暴的:创建一个辅助数组,之后把原数组中的所有元素都复制到这个辅助数组中,在这个过程中把元素m复制到下标为m的位置(复制过去之前要进行判断,默认为0,如果这个位置不是默认的0,那就是重复了) 空间复杂度O(n)
2、用一种类似二分查找法的方法:举个例子{2,3,5,4,3,2,6,7}——长度为8的数字,都在1~7范围内,统计1~4有5个,所以1~4中有重复的,1~2有2个,3~4有3个,再接着统计3、4各自出现的次数
先想好测试用例
代码:

int countNum(const int* numbers, int begin, int end, int length)
{
    if (numbers != nullptr) {
        int count = 0;
        for (int i = 0; i < length; i++)
            if (numbers[i] >= begin && numbers[i] <= end)
                count++;
        return count;
    }
    return 0;
}

//因为数组是不可以改变的,所以是const
int getDuplication(const int* numbers, int length)
{
    for (int i = 0; i < length; i++)
        if (numbers[i]<1 || numbers[i]>length - 1)
            return -1;

    if (numbers != nullptr && length > 1)
    {
        int start = 1;//最小的元素
        int end = length - 1;   //最大的元素
        while (end >= start) {
            int middle = ((end - start) >> 1 + start);  //>>1表示“÷2”
            int count = countNum(numbers, start, middle,length);
            if (end == start)
            {
                if (count > 1)
                    return start;//就是说这有两个一样的数
                else
                    return -1;   //不包含重复数字
            }
            if (count > (middle - start) + 1)//4-1+1
                end = middle;   //1~4
            else
                start = middle+1;   //5~8
        }
        return -1;
    }
}

二维数组中的查找

在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否包含该整数

思路

首先选取数组右上角的数字。如果该数字等于要查找的数组,则查找过程结束;如果该数字大于要查找的数字,则剔除这个数字所在的列;如果该数字小于要查找的数字,则剔除所在的行。这样每一步都可以缩小查找范围(可以自己画个图分析)
代码:

bool Find(int target, vector<vector<int> > array) 
    {
        if (array.begin() != array.end()) {
            int row = array.size();
            int col = (*array.begin()).size();
            int n = 0;
            int m = col-1;

            while(n<row && m>=0){
                if (array[n][m] == target)
                    return true;
                else if (array[n][m] > target)
                    --m;    //抛弃这一列

                else
                    ++n;    //抛弃这一排

            }
        }    
         return false;
    }

代码出错了,运行不通过,测试用例不通过,但是很迷,就是自己看不出来【eeee~~是大小比较那里错了,也是醉了,粗心得一波】

猜你喜欢

转载自blog.csdn.net/laon_chan/article/details/80241703