PKU 1007 DNA Sorting/2299 Ultra-QuickSort
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1007
http://acm.pku.edu.cn/JudgeOnline/problem?id=2299
思路:
求逆序对的个数
这两题的基本问题是一致的,给定一个数组(包括字符串),求出逆序对的个数
1. 最简单的方法
两层循环,复杂度O(n^2)
2. 归并排序&分治思想
其实,只要将归并排序稍加修改,就是一个求解逆序对个数问题的O(nlgn)方法
要理解的是这其中涉及的分治思想(三步骤):
a. 分解为子问题
b. 求解子问题
c. 合并子问题的解来得到原问题的解
具体对应到求逆序对个数的问题:
a. 将原数组分解为前后两个子数组
b. 求解子数组的逆序对个数
c. 合并前后子数组,同时计算逆序对个数(这个是指逆序对的第一个数在前子数组中,而第二个数在后子数组中)
3. 特例方法
针对PKU 1007该题的特殊性: 字符串中只包含A, G, T, C四个字母,还有一种更加简单的O(n)方法
http://acm.pku.edu.cn/JudgeOnline/problem?id=1007
http://acm.pku.edu.cn/JudgeOnline/problem?id=2299
思路:
求逆序对的个数
这两题的基本问题是一致的,给定一个数组(包括字符串),求出逆序对的个数
1. 最简单的方法
两层循环,复杂度O(n^2)
1
int
2 inversion_cal( char * str)
3 {
4 int i, j, count = 0 ;
5 int len = strlen(str);
6 for (i = 0 ; i < len; i ++ )
7 for (j = i + 1 ; j < len; j ++ )
8 if (str[i] > str[j])
9 ++ count;
10 return count;
11 }
2 inversion_cal( char * str)
3 {
4 int i, j, count = 0 ;
5 int len = strlen(str);
6 for (i = 0 ; i < len; i ++ )
7 for (j = i + 1 ; j < len; j ++ )
8 if (str[i] > str[j])
9 ++ count;
10 return count;
11 }
2. 归并排序&分治思想
其实,只要将归并排序稍加修改,就是一个求解逆序对个数问题的O(nlgn)方法
要理解的是这其中涉及的分治思想(三步骤):
a. 分解为子问题
b. 求解子问题
c. 合并子问题的解来得到原问题的解
具体对应到求逆序对个数的问题:
a. 将原数组分解为前后两个子数组
b. 求解子数组的逆序对个数
c. 合并前后子数组,同时计算逆序对个数(这个是指逆序对的第一个数在前子数组中,而第二个数在后子数组中)
1
long
long
2 merge_count( long * arr, long * temp, long begin, long end)
3 {
4 if (begin >= end)
5 return 0 ;
6 long i, j, k, mid = (begin + end) / 2 ;
7 long long rt = 0 ;
8 rt += merge_count(arr, temp, begin, mid);
9 rt += merge_count(arr, temp, mid + 1 , end);
10 i = k = begin;
11 j = mid + 1 ;
12 while (i <= mid && j <= end) {
13 if (arr[i] <= arr[j])
14 temp[k ++ ] = arr[i ++ ];
15 else {
16 temp[k ++ ] = arr[j ++ ];
17 rt += (mid - i + 1 );
18 }
19 }
20 for ( ; i <= mid; i ++ )
21 temp[k ++ ] = arr[i];
22 for ( ; j <= end; j ++ ) {
23 temp[k ++ ] = arr[j];
24 rt += (mid - i + 1 );
25 }
26 /* copy */
27 for (k = begin; k <= end; k ++ )
28 arr[k] = temp[k];
29 return rt;
30 }
2 merge_count( long * arr, long * temp, long begin, long end)
3 {
4 if (begin >= end)
5 return 0 ;
6 long i, j, k, mid = (begin + end) / 2 ;
7 long long rt = 0 ;
8 rt += merge_count(arr, temp, begin, mid);
9 rt += merge_count(arr, temp, mid + 1 , end);
10 i = k = begin;
11 j = mid + 1 ;
12 while (i <= mid && j <= end) {
13 if (arr[i] <= arr[j])
14 temp[k ++ ] = arr[i ++ ];
15 else {
16 temp[k ++ ] = arr[j ++ ];
17 rt += (mid - i + 1 );
18 }
19 }
20 for ( ; i <= mid; i ++ )
21 temp[k ++ ] = arr[i];
22 for ( ; j <= end; j ++ ) {
23 temp[k ++ ] = arr[j];
24 rt += (mid - i + 1 );
25 }
26 /* copy */
27 for (k = begin; k <= end; k ++ )
28 arr[k] = temp[k];
29 return rt;
30 }
3. 特例方法
针对PKU 1007该题的特殊性: 字符串中只包含A, G, T, C四个字母,还有一种更加简单的O(n)方法
1
int
2 inversion_cal2( char * str)
3 {
4 int i, temp[ 4 ], count = 0 ;
5 int len = strlen(str);
6 memset(temp, 0 , sizeof (temp));
7 for (i = len - 1 ; i >= 0 ; i -- ) {
8 switch (str[i]) {
9 case ' A ' :
10 ++ temp[ 0 ];
11 break ;
12 case ' C ' :
13 ++ temp[ 1 ];
14 count += temp[ 0 ];
15 break ;
16 case ' G ' :
17 ++ temp[ 2 ];
18 count += (temp[ 0 ] + temp[ 1 ]);
19 break ;
20 case ' T ' :
21 ++ temp[ 3 ];
22 count += (temp[ 0 ] + temp[ 1 ] + temp[ 2 ]);
23 break ;
24 }
25 }
26 return count;
27 }
2 inversion_cal2( char * str)
3 {
4 int i, temp[ 4 ], count = 0 ;
5 int len = strlen(str);
6 memset(temp, 0 , sizeof (temp));
7 for (i = len - 1 ; i >= 0 ; i -- ) {
8 switch (str[i]) {
9 case ' A ' :
10 ++ temp[ 0 ];
11 break ;
12 case ' C ' :
13 ++ temp[ 1 ];
14 count += temp[ 0 ];
15 break ;
16 case ' G ' :
17 ++ temp[ 2 ];
18 count += (temp[ 0 ] + temp[ 1 ]);
19 break ;
20 case ' T ' :
21 ++ temp[ 3 ];
22 count += (temp[ 0 ] + temp[ 1 ] + temp[ 2 ]);
23 break ;
24 }
25 }
26 return count;
27 }