【剑指offer】53、在排序数组中查找数字

题目一

统计一个数字在排序数组中出现的次数。

思路一

当然可以无脑用哈希表,空间复杂度O(n),时间复杂度O(1)

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        if (data.size() == 0)
            return 0;
        int length = data.size();
        map<int,int> mp;
        for (int i = 0; i < length; i++)
            mp[data[i]]++;
        return mp[k];
    }
};

思路二

哈希表法其实没有利用排序数组的条件。在排序数组中,可以用二分法来寻找k

但问题出在,就算我们找到了数组中间的数等于k,我们还是需要向左向右遍历找到头和尾,在这一步上会花很大的复杂度,最差O(n)。

 因此,在找第一个k时,首先也是二分找到中间的k,然后和它上一个数字相比,如果还是k,则在前半段数组继续二分,直到找到中间的数为k且前一个不等于k。

用同样的方法,找最后一个k

时间复杂度为O(logn)

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        int length = data.size();
        int count = 0;
        if (length == 0)
            return 0;
        int firstK = GetFirstOfK(data, k, 0, length - 1);
        int lastK = GetLastOfK(data, k, 0, length - 1);
        if (firstK > -1 && lastK > -1)
            count = lastK - firstK + 1;
        return count;
    }
    
    int GetFirstOfK(vector<int> data, int k, int start, int end){
        if (start > end)
            return -1;
        int mid = (start + end) / 2;
        int mid_data = data[mid];
        if (mid_data > k)
            end = mid - 1;
        else if (mid_data < k)
            start = mid + 1;
        else if (mid_data == k)
        {
            if ( (mid_data != data[mid-1] && mid > 0) || mid == 0)
                return mid;
            else
                end = mid - 1;
        }
        return GetFirstOfK(data, k, start, end);
    }
    
    int GetLastOfK(vector<int> data, int k, int start, int end){
        if (start > end)
            return -1;
        int mid = (start + end) / 2;
        int mid_data = data[mid];
        if (mid_data > k)
            end = mid - 1;
        else if (mid_data < k)
            start = mid + 1;
        else if (mid_data == k)
        {
            if ( (mid_data != data[mid+1] && mid < end - 1) || mid == end)
                return mid;
            else
                start = mid + 1;
        }
        return GetLastOfK(data, k, start, end);
    }
};

题目二

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在0~n-1之内。在范围0~n-1内的n个数字有且只有一个不在数组中,找出该数字。

思路一

题目很微妙,相当于0~n-1个数字中只有一个不在数组里。

当然我们求出0~n-1个数字的和为s1,然后求出数组数字之和为s2

s1-s2就是我们要找的数字,但是这也没有利用数组的递增性,时间复杂度为O(n)

思路二

遇到有序数组中的查找,往往要想到二分,因为能把复杂度降到O(logn)

data[index_mid] = data_mid

1、若 index_mid = data_mid,则要找的数字在右半段

2、(a) 若 index_mid != data_mid 且 data[index_mid - 1] = index_mid - 1,也就是当前索引与值不等,但上一个索引与数值相等,则index_mid就是我们要找的数字

   (b) 若  index_mid != data_mid 且 data[index_mid - 1] != index_mid - 1,那么我们要找的数字在左半段

class Solution {
public:
    int GetMissingNumber(vector<int> data)
    {
        int length = data.size();
        if(length == 0)
            return -1;
        int start = 0, end = length - 1;
        while (start <= end)
        {
            int index_mid = (start + end) / 2;
            int data_mid = data[index_mid];
            if (index_mid != data_mid){
                if (data[index_mid-1] == index_mid - 1 || index_mid == 0) //处理了0不在数组里
                    return index_mid;
                else 
                    end = index_mid - 1;
            }
            else
                start = index_mid + 1;
        }
        // 很关键,比如 0 1 2 3 4,每个数字都是对应相等,此时start=5,因此5是要找的数字
        if(start == length)
            return length;
        return -1; // 无效的输入,如数组不是递增,输入数字不在范围
    }
};

题目三

假设单调递增的数组里每个元素都是整数且都是唯一的。请实现函数,找出数组中任意一个数值等于其下标的元素。如

{-3,-1,1,3,5},数字3和下标相等

思路

value -3 0 1 2 4 6
index 0 1 2 3 4 5

很容易发现,在下标和数值相等的左边,索引会大于(或者等于)数值,在下标与数值相等的右边,索引会小于(等于)数值。

根据这个规律就可以二分查找

若Index = value,则找到

若index > value,在右半段

若index < value,在左半段

(代码略,很简单)

猜你喜欢

转载自www.cnblogs.com/shiganquan/p/9348652.html
今日推荐