可以採用分治的思想,分成左右兩個部分,統計左邊和右邊的逆序數之後,再統計左右結合的數目。
類似於歸併排序,左右兩邊統計完後都排好序,方便左右結合數目的統計,代碼如下:
#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;
}