Derived from the Light and Shadow Cutting Problem in the beauty of programming -- returns the number of reverse Arrays

Source: Internet
Author: User

The beauty of programming is a light and shade cutting problem. After analysis, it can be simplified to a problem of finding the number of reverse orders. Of course, the number of reverse orders can be very violent O (N ^ 2) however, if you are taking an interview and give an O (N ^ 2) solution, the interviewer will not be satisfied with it, and the impression on you will be compromised, so here we will mainly explain some efficient methods to calculate the number of reverse orders.

Take a question on poj as an example http://poj.org/problem? Id = 2299

Method 1: grouping Algorithm

We know that an efficient sorting algorithm in sorting is Merge Sorting, Which is O (nlogn) in the worst case and requires O (n) space. The divide and conquer algorithm is a versatile and efficient algorithm. Many problems can be solved using the divide and conquer idea. To find the reverse order number, you can also use the divide and conquer idea. For arrays A1, A2, a3 ............ an. The array is divided into two subproblems for solving A1, a2 ..... the number of backward orders of A (1 + N)/2, and the number of backward orders of A (3 + N)/2, and then the number of backward orders formed between the two sub-arrays. Here we need to use Merge Sorting. Here we assume that the child number array on the left and right is already ordered after recursion (when there is only one element, the Child array has a reverse order of 1 ), then merge the two sub-arrays. For each element in the sub-array on the right, when this element is added to the temporary array, you only need to find the number of elements on the left that are larger than it, then, the sum of all these numbers is the answer. The number of elements on the left greater than this element is mid-I + 1, and I is the subscript of the array on the left.

#include<stdio.h>#define MAX_NUM 500000int N;int sequence[MAX_NUM];int copy[MAX_NUM];long long merge(int p1_start,int p1_end, int p2_start,int p2_end);long long  reverse_num(int left,int right);intmain(void){int i;while(scanf("%d",&N) && N){for(i = 0;i<N;i++)scanf("%d",&sequence[i]);printf("%lld\n",reverse_num(0,N-1));}return 0;}long long  merge(int p1_start,int p1_end, int p2_start,int p2_end){int i = p1_start,j = p2_start;int count = 0;long long ans_count = 0;while(i <= p1_end && j <= p2_end){if(sequence[i] <= sequence[j])copy[count++] = sequence[i++];else{copy[count++] = sequence[j++];ans_count += p1_end - i + 1;}}while(i<=p1_end)copy[count++] = sequence[i++];while(j <= p2_end)copy[count++] = sequence[j++];int k = 0;while(k<count)sequence[p1_start+k] = copy[k++];return ans_count;}long long  reverse_num(int left,int right){if(left == right)return 0;int mid = (left+right)>>1;return reverse_num(left,mid) + reverse_num(mid+1,right) + merge(left,mid,mid+1,right);}

Operation Efficiency

Method 2: Line Segment tree + discretization

This question can be done using the line segment tree. We know that it is convenient and efficient for the line segment tree to process the interval problem. Therefore, the line segment tree is also called the Interval Tree, however, this question is 0 <= A [I] <999999999, but there are no more than 500000 data records. Therefore, it is clear that data discretization is required, the so-called discretization is to map the data to the following table after sorting, that is, the number of small. After discretization, it stores the array hash, inserts each number in the array into the line segment tree, and adds the ANS value of the range (hash [I] + 1, n ).

#include<cstdio>#include<iostream>#include<cstdlib>#include<algorithm>using namespace std;#define MAX_NUM 500010struct node{int value;int id;};int cmp(struct node a, struct node b){return a.value < b.value;}struct node values[MAX_NUM];int hash[MAX_NUM];struct tree_node{int left,right;long long times;};struct tree_node seg_trees[MAX_NUM<<2];void build_tree(int root,int left,int right){seg_trees[root].left = left;seg_trees[root].right = right;seg_trees[root].times = 0;if(left == right){return;}int mid = (left + right)>>1;build_tree(root*2,left,mid);build_tree(root*2+1,mid+1,right);}void insert(int root,int id){if(seg_trees[root].left == seg_trees[root].right){seg_trees[root].times +=1;return ;}int mid = (seg_trees[root].left + seg_trees[root].right)>>1;if(id <= mid)insert(root*2,id);elseinsert(root*2+1,id);seg_trees[root].times +=1;}long long query(int root,int left, int right){if(seg_trees[root].left == left && seg_trees[root].right == right)return seg_trees[root].times;int mid = (seg_trees[root].left + seg_trees[root].right)>>1;if(right <= mid)return query(root*2,left,right);else if(left > mid)return query(root*2+1,left,right);else{return query(root*2,left,mid)+query(root*2+1,mid+1,right);}}intmain(void){int N;while(scanf("%d",&N) && N){int i,j,k;for(i = 0;i<N;i++){scanf("%d",&values[i].value);values[i].id = i+1;}sort(values,values+N,cmp);for(i = 1;i<=N;i++){hash[values[i-1].id] = i;}build_tree(1,1,N);long long ans = 0;insert(1,hash[1]);for(i = 2;i<=N;i++){insert(1,hash[i]);if(hash[i] ==  N)continue;ans += query(1,hash[i]+1,N);}printf("%lld\n",ans);}return 0;}


Efficiency

Method 3: Tree Array

We can see from the above that the use of line tree encoding is large, the encoding is difficult, a waste of memory, and the operating efficiency is not high. Therefore, we can naturally think of using a tree array. The tree array method is very similar to the line tree method. We will not detail it here.

#include<cstdio>#include<string.h>#include<iostream>#include<cstdlib>#include<algorithm>using namespace std;#define MAX_NUM 500010struct node{int value;int id;};int cmp(struct node a, struct node b){return a.value < b.value;}struct node values[MAX_NUM];int hash[MAX_NUM];long long tree_arr[MAX_NUM];int lowbit(int x){return x&(-x);}void update(int pos,int up){while(pos<=up){tree_arr[pos] +=1;pos = pos + lowbit(pos);}}int get_sum(int pos){long long ans = 0;while(pos>0){ans +=tree_arr[pos];pos -= lowbit(pos);}return ans; }intmain(void){int N;while(scanf("%d",&N) && N){int i;long long ans = 0;for(i = 0;i<N;i++){scanf("%d",&values[i].value);values[i].id = i+1;}sort(values,values+N,cmp);for(i = 1;i<=N;i++){hash[values[i-1].id] = i;}memset(tree_arr,0,sizeof(tree_arr));update(hash[1],N);for(i = 2;i<=N;i++){update(hash[i],N);if(hash[i] == N)continue;ans += get_sum(N)- get_sum(hash[i]);}printf("%lld\n",ans);}return 0;}

Efficiency

Summary:

From the above methods, we can see that the splitting algorithm has the highest efficiency (there is no sort discretization preprocessing in the line tree or tree array), which consumes the lowest memory and has the best method. We recommend this method. Line Segment tree coding is the most difficult, and memory consumption is huge, and the efficiency is not high. This method is not recommended. The tree array efficiency and memory are both located in the center of the grouping algorithm and tree array. The tree array has a small amount of encoding.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.