AcWing basic algorithm

AcWing basic algorithm (I)

Quick sort

subject

Give you a sequence of integers with length nn.

Please use quick sort to sort this sequence from small to large.

And output the ordered sequence in order.

Input format

The input consists of two lines. The first line contains the integer nn.

The second row contains nn integers (all integers are in the range of 1 ∼ 1091 ∼ 109), representing the whole sequence.

Output format

The output consists of one line, including nn integers, representing the ordered sequence.

Data range

1≤n≤1000001≤n≤100000

Input example:

5
3 1 2 4 5

Output example:

1 2 3 4 5

thinking

Find a measurement value, transform the left side of the value into a value less than it, and the right side into a value greater than it, and then traverse.

realization

Now point the pointer to both sides of the data, and then look for an intermediate value.

int l=0;//Pointer to the far left
int r=n-1;//Pointer to the rightmost side (n is the number of data we input)
int x=q[(l+j)/2];//Intermediate value of measurement

If the position of the left pointer is larger than the right pointer at the beginning, we should end directly.

The left pointer finds out the number larger than the measured value and then stops, and the right pointer finds out the number smaller than the measured value and then stops. If the position of the left pointer is smaller than the position of the right pointer at this time, the data pointed by the left and right pointers will be exchanged.

if(l>=r)return;
while(l<r){
	while(q[l]<x)l++;
	while(q[r]>x)r--;
	if(l<r){
		int tmp=q[l];//Intermediate variable
   	 q[l]=q[r];
    	q[l]=tmp;
	}
}

Encapsulate the code as a function for recursive calls, so that all values have the opportunity to be measured.

void quick(int q[],int l,int r){
    if(l>=r)return;
    
    int x=q[(l+r)/2],i=l-1,j=r+1;
    
    while(i<j){
        do i++;while(q[i]<x);
        do j--;while(q[j]>x);
        if(i<j){
            int tmp=q[i];
            q[i]=q[j];
            q[j]=tmp;
        }
    }
    
    quick(q,l,j);
    quick(q,j+1,r);
}

Final code

#include<stdio.h>
#define N 100010 / / constant
int n;
int q[N];

void quick(int q[],int l,int r){
	if(l>=r)return;
	int x=q[(l+r)/2],i=l-1,j=r+1;
	while(i<j){
		do i++;while(q[i]<x);
		do j--;while(q[j]>x);
		if(i<j){
			int tmp=q[i];
			q[i]=q[j];
			q[j]=tmp;
		}
	}
	quick(q,l,j);
	quick(q,j+1,r);
}

int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&q[i]);
	}
	
	quick(q,0,n-1);
	for(int i=0;i<n;i++){
		printf("%d ",q[i]);
	}
}

Merge sort

subject

Give you a sequence of integers with length nn.

Please use merge sort to sort this sequence from small to large.

And output the ordered sequence in order.

Input format

The input consists of two lines. The first line contains the integer nn.

The second row contains nn integers (all integers are in the range of 1 ∼ 1091 ∼ 109), representing the whole sequence.

Output format

The output consists of one line, including nn integers, representing the ordered sequence.

Data range

1≤n≤1000001≤n≤100000

Input example:

5
3 1 2 4 5

Output example:

1 2 3 4 5

thinking

Using the idea of divide and conquer, divide the data into two and compare the minimum values of the two arrays.

realization

Define two pointers to the headers of two separated data.

int mid=(l+r)/2;//l is the left endpoint and r is the right endpoint
int i=l,j=mid+1;

Split the data in two from the middle;

merge(q,l,mid),merge(q,mid+1,r);//Function defined for us by merge

Use the pointer we defined to compare the data just divided into two. From left to right, if which data is small, first store the data in the temporary array tmp. If it is found that some data is not completely stored in the temporary array tmp after the comparison is completed, the data is stored in the temporary array tmp using a loop

int k=0;
while(i<=mid&&j<=r){
    if(q[i]<=q[j])tmp[k++]=q[i++];
    else tmp[k++]=q[j];
}
while(i<=mid)tmp[k++]=q[i++];
while(j<=r)tmp[k++]=q[j++];

Final code

#include<stdio.h>
#define N 100010
int n;
int q[N],tmp[N];

void merge(int q[],int l,int r){
	if(l>=r)return;
	
	int mid=(l+r)/2;
	
	merge(q,l,mid),merge(q,mid+1,r);
	
	int k=0,i=l,j=mid+1;
	while(i<=mid&&j<=r){
		if(q[i]<=q[j])tmp[k++]=q[i++];
		else tmp[k++]=q[j++];
	}
	while(i<=mid)tmp[k++]=q[i++];
	while(j<=r)tmp[k++]=q[j++];
	for(i=l,j=0;i<=r;i++,j++)q[i]=tmp[j];
}

int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&q[i]);
	}
	
	merge(q,0,n-1);
	for(int i=0;i<n;i++){
		printf("%d ",q[i]);
	}
}

Integer dichotomy

subject

Given an array of integers of length n in ascending order and q queries.

For each query, the start and end positions of an element k are returned (the positions are counted from 00).

If the element does not exist in the array, - 1 - 1 is returned.

Input format

The first line contains integers nn and qq, indicating the length of the array and the number of queries.

The second line contains n integers (all in the range of 1 ∼ 100001 ∼ 10000), representing the complete array.

Next q lines, each containing an integer kk, represent a query element.

Output format

There are q rows in total, and each row contains two integers, indicating the starting position and ending position of the element.

If the element does not exist in the array, - 1 - 1 is returned.

Data range

1≤n≤1000001≤n≤100000
1≤q≤100001≤q≤10000
1≤k≤100001≤k≤10000

Input example:

6 3
1 2 2 3 3 4
3
4
5

Output example:

3 4
5 5
-1 -1

thinking

Judge whether the intermediate value of the interval meets a certain condition, and then change the intermediate value of the interval into a left boundary or a boundary for judgment again until the interval length is shortened to one

realization

Under the condition that the left boundary is less than the right boundary, find the middle value of the interval length, and then judge with the condition of the topic. If the middle value is greater than the given condition (the array is arranged in ascending order), the middle value will become the left boundary, and the right boundary will remain unchanged. At this point, we find the left boundary

int x;
scanf("%d",&x);
int l=0,r=n-1;//l is the left boundary, r is the right boundary, and n is the number of input data
while(l<r){
    int mid=(l+r)/2;
    if(q[mid]>=x)r=mid;
    else l=mid+1;
}

If the found left boundary is equal to the given condition, output the value of the boundary and search the right boundary. If the found left boundary is not equal to the given condition, output - 1 - 1, and then end the program.

if(q[l]!=x){
    printf("-1 -1");
}
else{
    while(l<r){
        int mid=(l+r+1)/2;//If you do not add one, when l=r-1, mid is always equal to L, which will become an endless loop
        if(q[mid]<=x)l=mid;
        else r=mid-1;
    }
    printf("%d",r);
}

Final code

#include<stdio.h>

#define N 100010

int n,m;
int q[N];

int main(){
	scanf("%d%d",&n,&m);
	for (int i=0;i<n;i++)scanf("%d",&q[i]);
	
    //Left boundary
	while(m--){
		int x;
		scanf("%d",&x);
		
		int l=0,r=n-1;
		while(l<r){
			int mid=(l+r)/2;
			if(q[mid]>=x)r=mid;
			else l=mid+1;		
		}
		
		if(q[l]!=x){
			printf("-1 -1\n");
		}
        //Right boundary
		else{
			printf("%d ",l);
			
			int l=0,r=n-1;
			while(l<r){
				int mid=(l+r+1)/2;
				if(q[mid]<=x)l=mid;
				else r=mid-1;
			}
			printf("%d\n",r);
		}
	}
	return 0;
}

Decimal dichotomy

subject

Square the input data

thinking

It is the same as integer bisection, but there is no need to deal with the boundary problem.

realization

When the distance between the left and right boundaries is greater than the negative 6th power of 10, the boundary is divided

double x;
sacnf("%lf",&x);
double l=0,r=x;
while(r-l>1e-6){
    double mid=(r+l)/2;
    if(mid*mid>=x)r=mid;
    else l=mid;
}
printf("%lf",l)

Keywords: Algorithm data structure

Added by yaba on Sun, 23 Jan 2022 23:41:46 +0200