可以采用分治的思想,分成左右两个部分,统计左边和右边的逆序数之后,再统计左右结合的数目。
类似于归并排序,左右两边统计完后都排好序,方便左右结合数目的统计,代码如下:
#include<iostream>
#include<math.h>
#include<time.h>
using namespace std;
int temp[100];
int findreversenum(int *numbers,int beg,int end){
if(beg == end){
return 0;
}
int mid,leftnum,rightnum,num = 0;
mid = (beg+end)>>1;
if(beg<=mid)
leftnum = findreversenum(numbers,beg,mid);
if(mid+1<=end)
rightnum= findreversenum(numbers,mid+1,end);
int i =mid,j=end,pos = end;
while(i>=beg && j>=mid+1){
if(temp[i] >temp[j]){
numbers[pos--] = temp[i--];
num += j-mid;
}
else
numbers[pos--] = temp[j--];
}
while(i>=beg)
numbers[pos--] = temp[i--];
while(j>=mid+1)
numbers[pos--] = temp[j--];
for(int k =beg;k<=end;k++)
temp[k] = numbers[k];
return num+leftnum+rightnum;
}
int main(){
int numbers[] = {7,5,6,4};
for(int i =0;i<4;i++)
temp[i] = numbers[i];
int result = findreversenum(numbers,0,3);
printf("%d",result);
system("PAUSE");
return 0;
}
和为n的两个数字:已知给定某个数组,求数组中和为n的任意两个数字,输出即可。
直观想法是O(n*n)的扫描,但注意到找到一个满足条件的解即可。所以可以将数组排序,一个指针指向头部,一个指向尾部,扫描,如果两个指针的和小于n,则指向头部的向后移动;否则,指向尾部的向前移动。
拓展,和为n的连续正数序列,比如求15的,则结果为1+2+3+4,4+5+6,7+8。可以从上题得到启发,两个指针,一个指向1,一个指向2,如果当前和小于15,则后面的指针向后移动;如果大于,则前面的指针向后移动(相当于减少两个指针之间数字的和)。具体看代码:
#include<iostream>
#include<algorithm>
#include<time.h>
using namespace std;
//和为n的两个数
void findsum(int *numbers,int len,int sum){
int beg =0,end = len;
while(beg <end){
int temp = numbers[beg]+numbers[end];
if(temp == sum){
printf("找到的两个数是%d和%d,和为%d\n",numbers[beg],numbers[end],sum);
return;
}
if(temp<sum)
beg++;
else
end--;
}
printf("没有找到\n");
}
//连续的和为n
void findcsum(int sum){
int beg =1,end =2,mid = sum/2;
int cursum = beg+end;
while(beg<=mid){
if(cursum == sum){
for(int i = beg;i<=end;i++)
printf("%d",i);
printf("\n");
}
while(cursum >sum){
cursum -= beg;
beg++;
if(cursum == sum){
for(int i = beg;i<=end;i++)
printf("%d",i);
printf("\n");
}
}
end++;
cursum +=end;
}
}
int main(){
int numbers[] = {15,4,2,7,11,1};
int sum;
scanf("%d",&sum);
sort(numbers,numbers+6);
findsum(numbers,5,sum);
findcsum(15);
system("PAUSE");
return 0;
}