目前为止,PAT初级题目和题解已经全部发完了。 鼓掌!撒花!
初级题目几乎不需要用到复杂的数据结构,只需要基础的编程知识和简单的逻辑就可以完成。按姥姥的话说,“排序就是最复杂的了”(原话不记得了,不过是这个意思)。为了完成PAT的填坑大业,为了在9月份的PAT甲级比赛中不被题虐名列前茅并被优秀公司免试录取出任CEO迎娶白富美走上人生巅峰,果断开始走上备考甲级的不归之路!
甲级涉及的知识点比较多,要求的能力比较高,更需要一些稍微复杂一些的编程思想。参考biaobiaoqi前辈的文章,可以发现,涉及的数据结构有链表(List)、栈(Stack)、映射(Map)、树(Tree)、图(Graph)等,涉及的编程思想和算法有Hash、游标、倒排索引、排序、递归、搜索(广度优先、深度优先、二分搜索)、最短路径算法、并查集等。当时学DS和ADS的时候上课尽顾着睡觉了,所以现在不得不重新拿起尘封已久的《数据结构与算法分析(C语言版)》(Mark Allen Weiss著 陈越姥姥改编),复习一下基本的东西,就把复习笔记发在这里好了,以便学完以后什么都不记得了。给出的示例代码有的是书上的代码,大部分是自己编写的测试代码,以便更深入理解。
第一章为“简介”,介绍了递归的基本概念。此处省略。
第二章“算法分析”,介绍算法的时间复杂度和空间复杂度的计算方法。作为例子书中介绍了四种常见的问题,分别是二分搜索、求最大公约数的欧几里得算法、最大子序列和问题、求幂问题。分别记录如下:
1. 二分搜索
二分搜索充分利用数组已经排过序的特性,将搜索的时间复杂度降为O(log2(n))。
【示例代码】
#include
using namespace std;
int BinarySearch(const int A[], int x, int n)
{
int left = 0;
int right = n - 1;
while (left <= right){
int middle = (left + right) / 2;
if (x < A[middle]){
right = middle -1;
}
else if (x > A[middle]){
left = middle + 1;
}
else{
return middle;
}
}
return -1;
}
int main()
{
int n = 8;
int A[] = {1, 5, 8, 9, 11, 13, 14, 18};
cout << BinarySearch(A, 11, n) << endl;
cout << BinarySearch(A, 10, n) << endl;
system("pause");
return 0;
}
即辗转相除法。下面给出的示例是Gcd的一个应用,即求任意两数互质的概率。
【示例代码】
#include
using namespace std;
unsigned int Gcd(unsigned int M, unsigned int N)
{
unsigned int Rem;
while (N > 0){
Rem = M % N;
M = N;
N = Rem;
}
return M;
}
void PrimePair(unsigned int N)
{
int Rel = 0;
int Tot = 0;
for (int i = 1; i <= N; ++i){
for (int j = i + 1; j <= N; ++j){
++Tot;
if (Gcd(i, j) == 1){
++Rel;
}
}
}
cout << "The probability that two random numbers are relatively prime is about:"
cout << (double)Rel / Tot << endl;
}
int main()
{
cout << Gcd(1989, 1590) << endl;
unsigned int N = 10000;
PrimePair(N);
system("pause");
return 0;
}
3. 最大子序列和问题
【示例代码】
#include
/* method 1*/
int MaxSubSum1(const int A[], int n)
{
int thissum = 0;
int maxsum = 0;
for (int i = 0; i < n; ++i){
thissum += A[i];
if (thissum > maxsum){
maxsum = thissum;
}
else if(thissum < 0){
thissum = 0;
}
}
return maxsum;
}
/*method 2*/
int MaxSubSum2entry(const int[], int, int);
int MaxSubSum2(const int A[], int n)
{
return MaxSubSum2entry(A, 0, n - 1);
}
int max3(int, int, int);
int MaxSubSum2entry(const int A[], int left, int right)
{
/*base case*/
if (left == right){
if (A[left] > 0){
return A[left];
}
else{
return 0;
}
}
int middle = (left + right) / 2;
int maxleft = MaxSubSum2entry(A, left, middle);
int maxright = MaxSubSum2entry(A, middle + 1, right);
int maxboardsumL = 0;
int thisboardsumL = 0;
for (int i = middle; i >= left; --i){
thisboardsumL += A[i];
if (thisboardsumL > maxboardsumL){
maxboardsumL = thisboardsumL;
}
}
int maxboardsumR = 0;
int thisboardsumR = 0;
for (int i = middle+1; i <= right; ++i){
thisboardsumR += A[i];
if (thisboardsumR > maxboardsumR){
maxboardsumR = thisboardsumR;
}
}
return max3(maxleft, maxright, maxboardsumL+maxboardsumR);
}
int max3(int a, int b, int c)
{
int max = a > b ? a : b;
int res = max > c ? max : c;
return res;
}
int main()
{
int n = 6;
int A[] = {-2, 11, -4, 13, -5, -2};
std::cout << MaxSubSum1(A, n) << std::endl;
std::cout << MaxSubSum2(A, n) << std::endl;
system("pause");
}
4. 求幂问题
如果直接用循环求,时间复杂度为O(n),改用递归实现,复杂度降为O(nlog2(n))。
【示例代码】
#include
using namespace std;
long int pow(long int x, unsigned int n)
{
if (n == 0){
return 1;
}
if (n == 1){
return x;
}
if (n % 2 == 0){
return pow(x*x, n / 2);
}
else{
return pow(x*x, n - 1)*x;
}
}
int main()
{
cout << pow(2, 10) << endl;
system("pause");
return 0;
}
To be continued...