Chapter 3 of the Blue Bridge Cup algorithm competition series -- a detailed discussion on the bro divide and conquer of recursion

Welcome back to: meet blue bridge, meet you, not negative code, not negative Qing!

catalogue

1, What is divide and conquer

2, Analysis of classical problems in interview and competition

1. Merge sort

2. Interview question: calculate pow(x, n)

3. Competition question: most elements

3, Thinking problem: maximum sub order sum

4, Blue bridge conclusion: meet blue bridge meet you, not negative code, not negative Qing!

[statement]: this blog post may be a little high, so it's normal for iron juice people to read it a little hard at the beginning, because the author is also very painful when sorting out the blog, but it doesn't matter. It's best to read it twice and three times without understanding it. It's best to implement it in code and draw it step by step.

[preface]: there is still a lot of time before the Blue Bridge Cup. Next, the author may update the basic algorithm module a little slower. He plans to update one basic algorithm a week, which will certainly ensure the quality. He can't live up to the iron juice's trust or waste their time. If so arranged, The main test algorithms of the Blue Bridge Cup will be about the same by early December. Then, the author mainly updates a LeetCode brush question every day for targeted practice. I will select the most meaningful one from the brush questions every day, and lay a solid foundation with you. Remember, don't blindly draw fast, It's better to walk steadily. When the basic algorithm module ends in December, the author will open the Blue Bridge Cup Sprint counseling column to review the common test algorithms over the years, but it will not be as simple as now, and it will be interspersed with real problems over the years and a large number of targeted exercises. Therefore, we should master the basic algorithms by more than 80%, Do not like the author before, after seeing the collection of good articles, put them in the favorites to eat ash.

Come on

Hey, hey, I'm going to start performing. Please see the following.

1, What is divide and conquer

Definition of divide and Conquer: decompose a large problem into several sub problems and solve them in turn

Note: the central idea of divide and conquer is to cut big problems into small ones

Why is divide and conquer recursive bro? Because to solve the problem of divide and conquer, the idea of recursive algorithm is applied: call yourself, so divide and conquer is recursive bro and special recursion. The backtracking algorithm mentioned later is also a special recursion. The author will introduce it in detail later.

Problem solving steps of divide and Conquer: (central idea problem solving)

1. Disassembly:
The original problem is decomposed into several sub problems which are small, independent and the same as the original problem.


2. Solution:
If some sub problems are small and easy to solve, they can be solved directly. Otherwise, they will continue to be decomposed into smaller sub problems until they are easy to solve.


3. Consolidation:
The solutions of the solved sub problems are gradually merged into the solutions of the original problems.

2, Analysis of classical problems in interview and competition

1. Merge sort

For example, a very common sort, that is, merge sort, uses an algorithm idea that is divide and conquer.

Typical examples of merge sort and divide and conquer method:

  • Decompose into subproblems
  • Recursive processing subproblem
  • Merge subproblem
#define N 100

void sortArray(int* nums, int left, int right) 
{
    int tmp[N] = { 0 };//tmp as auxiliary array

    //The subproblem cannot be decomposed
    if (left >= right)
        return;
    //Decompose the subproblem and deal with it recursively
    int mid = (left + right) >> 1;
    sortArray(nums, left, mid);
    sortArray(nums, mid + 1, right);

    //Merge subproblem
    int k = 0;
    int i = left;
    int j = mid + 1;
    while (i <= mid && j <= right)
    {
        if (nums[i] <= nums[j])
        {
            tmp[k++] = nums[i++];
        }
        else
        {
            tmp[k++] = nums[j++];
        }
    }
    //Left half left
    while (i <= mid)
    {
        tmp[k++] = nums[i++];
    }
    //Left in the right half
    while (j <= right)
    {
        tmp[k++] = nums[j++];
    }
}

  Merging and sorting is only briefly introduced here. Iron juice will learn about it first, and there will be a special sorting module later.

Maybe at this point, we still don't quite understand what divide and conquer is. It doesn't matter. The following examples will be explained in detail.

2. Interview question: calculate pow(x, n)

Known: n > = 0, let's solve the problem with divide and Conquer:

int pow(int x, int n)
{
	int sum = 0;
	//Find boundary
	if (n == 0)
	{
		return 1;
	}
	if (n == 1)
	{
		return x;
	}
	//n is an odd number
	if (n & 1)
	{
		sum = pow(x, n / 2) * pow(x, n / 2) * x;
	}
	//n is an even number
	else
	{
		sum = pow(x, n / 2) * pow(x, n / 2);
	}
	return sum;
}

  However, when the interviewer asks you if you have a better solution during the interview, what should I do?

At this time, there is indeed a more efficient writing method, which is written by a big man I saw on the Internet. The principle is the same, but recursion is not used, which saves a lot of expenses. Let's have a brief understanding. When the author has enough ability, we will open a special topic for interview algorithm. However, in the Blue Bridge Cup, we just need to understand the divide and conquer solution above.

int pow(int x, int n)
{
	if (n == 0)
	{
		return 1;
	}
	int p = 1;
	while (n > 0)
	{
        //Come in when n is odd
		if (n & 1)
		{
			p = p * x;
		}
		x = x * x;
		n = n / 2;
	}
	return p;
}

3. Competition question: most elements

Given an array, let you find out the most elements in the array, and the array is always non empty, and there are always most elements. What are most elements? Most elements refer to elements that appear more than n / 2 in the array.  

In fact, to solve this problem with divide and conquer, most elements are the array divided into two... After division, at least half of the elements of the small array are the same as those of the original array. As follows:

 

 

int majorityElement(int* nums, int numsSize){

    return getMajority(nums, 0, numsSize - 1);
}

int getMajority(int* nums, int left, int right)
{
    //When left == right, it means to point to one number at the same time, that is, there is only one number in the small array 
    if(left == right)
    {
        return nums[left];
    }
    int mid = (left + right) >> 1;
    //Most elements on the left
    int leftMajority = getMajority(nums, left, mid);
    //Most elements on the right
    int rightMajority = getMajority(nums, mid + 1, right);
    //When most elements on the left and right sides are equal
    if(leftMajority == rightMajority)
    {
        return leftMajority;
    }
    //Most elements on the left and right sides are not equal. Traverse two small arrays from beginning to end to see who appears more frequently on the left and right sides
    int leftcount = 0;
    int rightcount = 0;
    for(int i = left; i <= right; i++)
    {
        if(nums[i] == leftMajority)
        {
            leftcount++;
        }
        else if(nums[i] == rightMajority)
        {
            rightcount++;
        }
    }
    if(leftcount > rightcount)
    {
        return leftMajority;
    }
    else
    {
        return rightMajority;
    }
}

3, Thinking problem: maximum sub order sum

Because this question needs to be considered more than the previous questions, it is a little around, so it is reserved for thinking here for the time being. After iron juice understands the previous three questions, the author will explain this question in detail in the next blog post. First, explain the general idea:

Topic Description: given an integer array, find a continuous sub array with the maximum sum (the sub array contains at least one number), and return its maximum sum.

Note: this question requires a continuous subarray. Some questions may be disconnected, but this question is not.

The array num is divided into three cases by mid:

1. The largest substring is on the left

2. The largest substring is on the right

3. At the midpoint of the maximum substring span, there are both left and right elements (difficulties in understanding)

  

This thinking topic is introduced here. Wait until it is introduced in detail in the next blog post. Iron juice will think first.

Now let's explain the thinking problem in recursion (Part 2). Please pass the last blog post again.

https://blog.csdn.net/weixin_57544072/article/details/120917038?utm_source=app&app_version=4.17.0

Thinking problem left by recursion: put an apple

Title Description: put m identical apples on n identical plates, and allow some plates to remain empty. How many different methods can be used? Note: 5 1 1 and 1 5 1 are the same classification

Since this topic may be a little windy for those iron juice who have not met before, I will first say the general idea. Pay attention. If you solve this topic, you must pay attention to what you are talking about today.

General idea: suppose that the total number of putting i apples on k plates is f(i, k), then:

1. When k > i, it means that there are more plates than apples, and there must be (k - i) plates empty, so put (k - i) plates aside, and the remaining problem becomes to put i apples on i plates, so when k > i, f(i, k) = f(i, i)

2. When k < = I, the placement method is divided into two types: empty with plate and empty without plate, so its total placement method = empty with plate + empty without plate (empty with plate means that at least one plate is empty, so you can directly take an empty plate to the side without use, and the rest is to put I apples on (k - 1) plates), so when k < = I, f(i, k) = f(i, k - 1) + f(i - k, k). Why is f (I - K, K) when k < = I when no plate is empty? We can think like this: because there are more apples than plates, we can put one apple in each plate first, and then there are (I - K) apples left to ensure that no plate is empty. What can be changed is (I - K) apples.

  If you understand the above clearly, the problem is very simple. Come on, show me the code

int f(int m, int n)
{
	//There are two boundaries
	//It's also a way not to put apples on the plate
	if (m == 0)
	{
		return 1;
	}
	//There's no plate to put
	if (n == 0)
	{
		return 0;
	}
	//When there are fewer apples than the plate
	if (m < n)
	{
		return f(m, m);
	}
	//When there are more apples than plates
	return f(m, n - 1) + f(m - n, n);
}
int main()
{

4, Blue bridge conclusion: meet blue bridge meet you, not negative code, not negative Qing!

OK, that's all for divide and conquer. Divide and conquer itself is no more than other algorithms, and a lot of recursive knowledge is used. You can review and brush questions together. OK, starting from tomorrow, I will send a LeetCode brush question every day. In the early stage, it is mainly aimed at the Blue Bridge Cup algorithm. The question is relatively simple. I work together with you. Oh, hey, hey, I look forward to the comments of iron juice. It would be better if I could use my small hand to give the blogger three consecutive times. Your recognition is my biggest driving force!

Tags: C Algorithm

Posted on Fri, 29 Oct 2021 18:56:29 -0400 by JayNak