Data structure-sequence table exercise solution (II)

This topic comes from the Wangdao postgraduate entrance examination textbook, combined with the answer to give some personal writing.
1. [Unified Test Questions] An ascending sequence S of length L, the number rounded on L/2 is called its median, for example, if the sequence S1=(11,13,15,17, 19), the median of S1 is 15, and the median of the two sequences is the median of the ascending sequence composed of all their elements. For example, if S2=(2,4,6,8,20), the median of S1 and S2 is 11. Now there are two equal-length ascending sequences A and B. Try to find an algorithm that is as efficient as possible in terms of time and space, and find the median of A and B. Requirements:
1) Give the basic idea of ​​the algorithm
2) Write the code, and give comments on the key points
3) Explain the time complexity and space complexity of this algorithm.

Difficulty: Moderate: The proof of the theorem is hard to think, O(logn) The algorithm is hard to think about, and requires a deeper understanding of the nature and concept of the median.
Thought:
If merge sorting is used, the time complexity is relatively high. The ontology should adopt the idea of ​​subtraction method:
set the median of sequence A to am, and the median of sequence B to bm.
Theorem 1: The middle of A and B The size of the digit cm must be between am and bm. A

brief proof: defined by the median, assuming that there are n numbers in A and B (for convenience, let n be an odd number, and even numbers prove the same), then there must be (n The number of -1)/2 is less than or equal to am, and the number of (n-1)/2 is greater than or equal to bm.
Then analyze:
1. If am=bm, the median must be am (or bm), because at this time there must be (n-1) numbers less than or equal to am, and (n-1) numbers greater than Equal to am, am must be the median.
2. If am<bm(am>bm is the same): if cm<am at this time, there must be cm<am<bm, then there must be (n-1)/2 that does not contain bm at this time. bm, there are (n-1)/2 numbers that do not include am greater than or equal to am, then at least 2*(n-1)/2+1+1 numbers are greater than cm, that is, at least (n+ 1) If a number is greater than cm, cm must not be the median.

From the above proof, let’s think about how to do it the fastest:
we take the median of A’s am, and the median of B’s bm. From the above theorem, we can see that the median of AB must be between am and bm.
1.am=bm, defined by the median, am is the median
2.am<bm, then we can discard the number before am and the number after bm (the number of discarded on both sides must be equal), so as to ensure greater than The median and the number of digits less than the median are equal, and then continue this operation in the new array A'B'after discarding the numbers, until the condition in 1 appears or there is only one element in both arrays, defined by , At this time, just take the smaller element.
3.am>bm, in the same way,
this algorithm reduces the size of the array by half each time, so the time complexity is O(logn) and the space complexity is O(1)

#include <iostream>
using namespace std;
int findMid(int *a, int *b, int n)
{
    
    
	int s1 = 0, s2 = 0, d1 = n - 1, d2 = n - 1;
	//用s表示首指针,d表示尾指针。
	while (s1 != d1 || s2 != d2) 
	{
    
    
		int mid1 = (s1 + d1) / 2;
		int mid2 = (s2 + d2) / 2;
		if (a[mid1] == b[mid2]) return a[mid1];
		if (a[mid1] < b[mid2])
		{
    
    
			if ((d1 - s1+1) % 2 == 0)//当序列个数为偶数个时
			{
    
    
				s1 = mid1 + 1;
				d2 = mid2;
			}
			else//序列个数为奇数个时
			{
    
    
				s1 = mid1;
				d2 = mid2;
			}
		}
		else
		{
    
    
			if ((d2 - s2 + 1) % 2 == 0)
			{
    
    
				s2 = mid2 + 1;
				d1 = mid1;
			}
			else
			{
    
    
				s2 = mid2;
				d1 = mid1;
			}
		}
	}
	return a[s1] < b[s2] ? a[s1] : b[s2];
}
//测试代码
int main()
{
    
    
	int a[] = {
    
     11,13,15,17,19 };
	int b[] = {
    
     2,4,6,8,20 };
	int mid = findMid(a,b,5);
	cout << "中位数为:" << mid;

}

Insert picture description here

2. [Unified Exam Question] Knowing an integer sequence A=(a0,a1,…an-1) where 0<=ai<n(0<=i<n) if there is ap1=ap2=…=apm=x and m>n/2, then x is called the main element of A, for example, A=(0,5,5,3,5,7,5,5) then 5 is the main element, another example is A=(0,5, 5,3,5,1,5,7) Then there is no principal element in A. Assuming that the n elements in A are stored in a one-dimensional array, please design an algorithm that is as efficient as possible to find the principal element of A. If there is a main element, return this element, if there is no main element, return -1.

Difficulty: It is difficult. It is not recommended to spend too much time thinking about the best algorithm in the examination room. It is a good choice to write a quick sort and then count.
Idea: It is nothing more than finding the maximum number of repeated elements and making a judgment. If you scan the position of each element directly from the front to the back, it will reach the time complexity of O(n2), which is obviously not a good practice. If the statistics are sorted, there is at least O(nlogn) time complexity.
We think about the following issues:
1. The main element must be unique: because m>n/2, the number of remaining repeated elements must be less than n/2, that is to say, the number of remaining elements must be less than the number of main elements.
Idea: When
there are primary elements in the array, the sum of all non-primary elements must be less than half. If the main element is "paired" with a non-main element, the last extra element (no element is paired with) is the main element. But how do you know which element is the main element? If you don't know who the main element is, how do you "match"? It's okay. Scan the array elements from front to back, assuming that the current value encountered is selected as the primary element. When encountering it again, the count is increased by 1, and when a value that is not equal to it is encountered, the count is decreased by 1. When the count is reduced to 0, the next value encountered is reselected as the main element. After scanning, the currently selected element (count value greater than 0) may be the main element, but not necessarily the main element. It is also necessary to scan the array again and record the actual number of occurrences to determine whether it is the main element.
The algorithm can be divided into the following two steps:

① Select candidate main elements: scan each integer in the given array in turn, save the first integer Num encountered in c, and record the number of occurrences of Num as 1; if the next integer encountered is still equal to Num , The count is increased by 1, otherwise the count is decreased by 1. When the count is decreased to 0, the next integer encountered is saved to c, and the count is re-recorded as 1, and a new round of counting is started, that is, the above process is repeated from the current position , Until all array elements are scanned.

② Determine whether the element in c is the real main element: scan the array again, count the number of occurrences of the element in c, if it is greater than n/2, then it is the main element, otherwise, there is no main element in the sequence.

int Majority ( int A[], int n )
{
    
         int i, c, count = 1; // c用来保存候选主元素,count用来计数
      c= A[0]; //设置A[0]为候选主元素
      for( i = 1; i < n; i++ ) // 查找候选主元素
        if( A[i] == c )  count++;   // 对A中的候选主元素计数
           else
               if( count > 0 ) 
               count--;  // 处理不是候选主元素的情况
                    else{
    
             // 更换候选主元素,重新计数
                     c= A[i];
                     count= 1;
                         }
            if( count > 0 )
               for( i = 0,count = 0; i < n; i++ )    // 统计候选主元素的实际出现次数
                         if ( A[i] == c )  
                         count++;
            if( count > n/2 )  
              return c;   // 确认候选主元素
             else  return -1;     //不存在主元素
}

3. [Unified Exam Question] Given an array containing n (n>1) integers, please design an algorithm that is as efficient as possible in time and space to find the smallest positive integer that does not appear in the array, for example, the array { The smallest positive integer that does not appear in -5,3,2,3} is 1, and the smallest positive integer that does not appear in {1,2,3} is 4.
Idea: We use space for time, and apply for an n-dimensional Array B, B represents the occurrence of the first n positive integers, the initial value is set to 0, and then the array in A is scanned, if ai>n or ai<=0, the smallest positive integer that does not appear must be in b, if 1 <ai<=n, then replace with 1 in the corresponding position of B, indicating that this number has already appeared. If array B is full after scanning, it proves that array A covers 1-n, and each appears only once, Then the smallest integer that does not appear must be (n+1)

#include <iostream>
using namespace std;
int FindMin(int* a, int n)
{
    
    
	int i = 0;
	int* b;
	b = (int*)malloc(sizeof(int) * n);
	memset(b, 0, sizeof(int) * n);
	for (int i = 0; i < n; i++)
	{
    
    
		if (a[i] > 0 && a[i] <= n)
		{
    
    
			b[a[i] - 1] = 1;
		}
	}
	for  (i = 0; i < n; i++)
	{
    
    
		if (b[i] == 0)
			break;
	}
	return i + 1;
}
int main()
{
    
    
	int a[] = {
    
     -5,3,2,3 };
	int min = FindMin(a, 4);
	cout << "此数组中未出现的最小正整数为" << min;

}

Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_42313342/article/details/108349709