【Sword Finger Offer】 —— Binary search related example summary

First, the minimum value of the rotating array

Topic requirements:

Move the first few elements of an array to the end of the array, we call it the rotation of the array.
Input a rotation of a non-decreasing sorted array, and output the smallest element of the rotated array.
For example, the array {3,4,5,1,2} is a rotation of {1,2,3,4,5}, and the minimum value of the array is 1.
NOTE: All the elements given are greater than 0, if the array size is 0, please return 0.

Topic analysis:

First of all, we can make it clear that the array
after the rotation of the rotation array can actually be divided into two sorted sub-arrays, and the elements of the front sub-array are greater than or equal to the elements of the back sub-array,
so we can follow this It ’s time to explore the answers to the questions. We still analyze in a simple and easy-to-understand way with specific examples.

Case 1: The
array {3, 4, 5, 1, 2} is used as a column. First define two pointers to point to the first element and the last element of the array. The shaded part is the second sub-array.
Insert picture description here
Calculate the index of the middle element at this time = (0 + 4) / 2 = 2. The element value of the array with subscript 2 is 5. Since 5> the number 3 pointed to by p1, the middle value is in the first sub-array . Point p1 to the middle number.
Insert picture description here
At this time, the number 1 in the middle of p1 and p2 is smaller than the number pointed by p2. The number in the middle is in the second subarray. Point p2 to the middle number.
Insert picture description here
At this time, p1 and p2 point to two adjacent numbers , then
p2
points to the smallest number in the array .
Why is p2 the smallest number?
Because when the two pointers are only one position apart, it indicates that p1 has already pointed to the last element of the first increasing array, and p2 has pointed to the first element of the second increasing array. So what p2 points to is the smallest element in the array.

Case 2:
When encountering the situation where p1, p2 and the number pointed by the middle pointer are the same, such as the array {0,1,1,1,1}. {1,0,1,1,1} and {1,1,1,0,1} are the rotation of the incremental array
Insert picture description here
as shown in the above figure. In this case, it is not clear to which incremental array the middle element belongs , So you have to take the way of sequential search.

Case 3:
If the first 0 elements of the sorted array are moved to the end, that is, the array itself, this is still a rotation of the array.
In this case, just return the element pointed to by p1. This is why indexMid is assigned to p1.

Code

int MinInOrder(int* numbers, int p1, int p2)
{
    int result = numbers[p1];
    for (int i = p1 + 1; i <= p2; i++)
    {
        if (result > numbers[i])
            result = numbers[i];
    }
    return result;
}
int Min(int* numbers, int length)
{
	if (numbers == nullptr || length <= 0)
		throw new::std::exception("Invalid parameters");

	int p1 = 0;
	int p2 = length - 1;
	int indexmid = p1;
	while (numbers[p1] >= numbers[p2])
	{
		//情况一
		if (p2 - p1 == 1)
		{
			indexmid = p2;
			break;
		}
		indexmid = (p1 + p2) / 2;

		//情况二
		if (numbers[p1] == numbers[p2] == numbers[indexmid])
		{
			return MinInOrder(numbers, p1, p2);
		}
		//缩小范围
		if (numbers[indexmid] >= numbers[p1])
			p1 = indexmid;
		else if(numbers[indexmid] <= numbers[p2])
			p2 = indexmid;
	}
	return numbers[indexmid];
}

Second, find the number in the sorted array

Topic 1: The number of times a number appears in a sorted array

Count the number of times a number appears in a sorted array. For example, input the sorted array {1,2,3,3,3,3,4,5} and the number 3, because 3 appears 4 times in this array, so output 4.

Analysis:
Since the array is ordered, we naturally think of using binary search. It is preferred to use a binary search to find a 3, and then scan sequentially on the left and right sides of 3 to find the first 3 and the last 3 respectively.

Find the first 3 in the array: The
number 3 was found based on the binary search above, but it is not clear whether this 3 is the first 3 in the array. Therefore, we have to judge a number before 3.
Insert picture description here
If X in the figure, if X is not 3, then the first 3 of the array is the one just found 3.
If X in the figure is 3, then the first 3 Must be in the first half of the array, we still need to search in the first half of the array in the next round.
The code is implemented as follows:

int GetFirstK(int* data, int length, int k, int start, int end)
{
    if (start > end)
        return -1;
    int mid = (start + end) / 2;
    int middleData = data[mid];

    if (middleData == k)
    {
        if ((mid > 0 && data[mid - 1] != k) || mid == 0)
            return mid;
        else
            end = mid - 1;
    }
    else if (middleData > k)
    {
        end = mid - 1;
    }
    else
    start = mid + 1;
    return GetFirstK(data, length, k, start, end);
}

Not found 3 returns -1, found the first 3 in the array returns its subscript

Find the last 3 in the array:
The method to find the last 3 is similar to the above, the code written based on recursion is as follows:

int GetLastK(int* data, int length, int k, int start, int end)
{
    if (start > end)
        return -1;
    int mid = (start + end) / 2;
    int middleData = data[mid];
    if (middleData == k)
    {
        if ((mid < length-1 && data[mid + 1] != k) || mid == length-1)
            return mid;
        else
            start = mid + 1;
    }
    else if (middleData < k)
    {
        start = mid + 1;
    }
    else
      end = mid - 1;
    return GetLastK(data, length, k, start, end);
}

After finding the subscripts of the first 3 and the last 3 in the array, the number of occurrences in the array can be calculated. The code is as follows:

int GetNumberOfK(int* data, int length, int k)
{
    int count = 0;
    if (data != nullptr && length > 0)
    {
        int first = GetFirstK(data, length, k, 0, length - 1);
        int last = GetLastK(data, length, k, 0, length - 1);

        if (first > -1 && last > -1)
            count = last - first + 1;
    }
    return count;
}

Topic 2: Missing digits in 0 ~ n-1

All numbers in an increasing array of length n-1 are unique, and each number is in the range 0 ~ n-1, and there are only one number in the n numbers in the range that are not in the array , Please find out this number

Problem analysis:
Method 1:
We can first calculate the sum of all numbers from 0 to n-1 as s1, and then calculate the sum of all numbers in the array as s2, and the difference between s1-s2 is 0 ~ n-1 The missing number in.
But this method is not good, because the rule of increasing the array given in the question is not used, and his time complexity is O (n)

Method 2:
We can use the idea of ​​binary search to solve
because these numbers 0 ~ n-1 are sorted in the array, so the beginning of these numbers is the same as the array index, assuming the number m is the missing number in the array Then the number after m and the subscript are not the corresponding relationship,
Insert picture description here
so this problem is transformed into finding the first element in the sorted array that is not equal to the subscript

1. If the value of the middle element and the subscript are equal, then only need to search for the right part in the next round
2. If the value of the middle element and the subscript are not equal

  1. And the element before him is not equal to his subscript, then the element is the missing element
  2. And the element in front of him is not equal to his subscript, which means that we only need to search on the right for the next round of search

In summary, the code implementation is as follows:

int GetMissingNumbers(const int* numbers, int length)
{
    if (numbers == nullptr || length <= 0)
        return -1;

    int left = 0;
    int right = length - 1;
    
    while (left <= right)
    {
        int mid = (left + length) / 2;
        if (numbers[mid] != mid)
        {
            if (numbers[mid - 1] == mid - 1 || mid == 0)
                return mid;
            else
                right = mid - 1;
        }
        else
            left = mid + 1;
    }
    //缺失的是最后一个数字
    if (left == length)
        return length;

    return -1;
}

Topic 3: Elements with equal values ​​and subscripts in the array

Suppose that each element in a monotonically increasing array is an integer and is unique. Please program a function to find any element in the array whose value is equal to its subscript. For example, in the array {-3, -1, 1, 3, 5}, the number 3 is equal to its subscript.

Problem analysis:
still make full use of the law of increasing arrays, assuming that the value of the i-th number is greater than the subscript i, then the numbers on his right are greater than the corresponding subscript. The next round of searching only needs to search for the number on her left.
Assuming that the value of the i-th number is less than the subscript i, then the numbers on his left are smaller than the corresponding editor. The next round of searching only needs to search among the numbers on her right.
Based on the above statement, the code is implemented as follows:

int GetNumberSameAsIndex( int* numbers, int length)
{
    if (numbers == nullptr || length <= 0)
        return -1;

    int left = 0;
    int right = length - 1;

    while (left <= right)
    {
        int mid = (right - left ) / 2 + left;
        if (numbers[mid] = mid)
            return mid;
        if (numbers[mid] < mid)
            left = mid + 1;
        else
            right = mid + 1;
    }
    return -1;
}
Published 98 original articles · won praise 9 · views 3654

Guess you like

Origin blog.csdn.net/qq_43412060/article/details/105338437