研究生复试上机基本题型及思路总结(上篇)

 

一、暴力求解

1. 枚举法

2. 模拟法 

2.1 图形排版

2.2 日期问题

二、查找与排序

1.排序

2.查找

三、字符串

        1 普通类型

        2 字符串匹配(KMP算法)

N、通用问题

 


/****************************************************/

前言:

总结中题型分类、大体框架来自王道机试指南,同时也参考了算法笔记的内容。我自己的编程基础比较薄弱,在学习刷题的过程中,对算法笔记的直观感受是难度相对机试指南要大一些,但是 PAT 题很强调考虑问题的全面性,尤其是对于边界等特殊情况的考虑,题目都很经典。机试指南习题难度较小,如果从头开始的话,个人建议是 一定的C/C++基础 --》 机试指南 --》算法笔记。

本文写作的侧重点不在于精,主要是想全面的对考研机试的考试范围、考察形式等进行说明,仍处在不断的修正改进之中,若有不同意见,欢迎留言交流。

最后祝看到此文的战友们都能如愿上岸,我们一起在人生的更高处相见吧!

/****************************************************/

 

一、暴力求解

1.1 枚举法

适用于问题规模较小,可以一个答案一个答案试统计所有的结果。一般问题的规模不能超过 10 的 6 次方。

1.2 模拟法 

按照题目的描述,直接编程输出即可。

1.3 图形排版

按照能否直接在输出图形中找到规律,采用两种方法。第一种是直接输出,适用于较为简单的题目,第二种方法是构造矩阵,改变矩阵直接输出,好处是可以从各个方向进行访问修改,直接输出的方法仅适用于从上到下,从左到右的情况。

1.3.1 直接输出

观察输出规律,直接输出。

浙江大学真题

1.3.2 构造矩阵

构造并修改矩阵最后输出。

PAT B 1050

1.4 日期问题

1.4.1 给出日期,求是此年的第几天,此类问题直接累加即可,不要要注意平年和闰年的二月的区别。

判断平闰年并不是采用是否能被 4 整除的方法,要用以下方法:  

bool isLeap(int year){
    return ((year % 4 == 0) && (year % 100 != 0)) || year % 400 == 0; 
}

1.4.2 给出第几天,求具体日期。累加即可。

1.4.3 求两个日期之间的隔的天数。

codeup 1928

二、查找与排序

2.1 排序

此类题目务必掌握 c++ 中 sort 函数 或 c 中 qsort 函数详细的使用用法,建议使用 c++ 中 algorithm 库中的 sort 函数,使用方法较为简单,练习题牛客、PAT、leedcode 中均大量涉及。

2.2 查找

建议在掌握线性查找的基础上,能够熟料掌握二分查找的使用方法,需要注意的是,二分查找仅仅适用于查找集合有序的情况,其进行一次查找的量级为 log n,与线性查找的 n 量级具有较大差距,虽然使用二分查找可能会需要额外的排序开销,但若待查找元素数量级过大时,使用线性查找很有可能会超时,二分查找可以在此时救场。以下给出二分查找的代码:

// 二分查找
bool BinarySearch(int n,int x){
    int left = 0;
    int right = n - 1;
    while(left <= right){
        int mid = (left + right) / 2;
        if(arr[mid] < x){
            left = mid + 1;
        }else if(arr[mid] > x){
            right = mid - 1;
        }else{
            return true;
        }
    }
    return false;
}

三、字符串

字符串类型题目所考察的很细致,也是机试中考察频率较高的一个题目类型,可以用 char 数组来进行计算,也可以采用 c++ 中经过封装更为简单的STL 容器 string 来进行计算,建议从一开始就练习使用 string 数据类型,会比 char 方便很多。关于 string 的使用,可以参考此篇博文。

3.1 普通类型

此类问题包含的题目形式比较多样,出题范围也很广,建议着重关注输入/输出格式,边界范围等细致内容。

3.2 字符串匹配(KMP算法)

如果使用暴力方法对求解字符串匹配问题,时间复杂度将达到 m * n(m n 分别为模式串与文本串的长度),但是使用KMP算法之后将使得问题的时间复杂度降低为 m + n。KMP算法的使用流程大致为 获得模式串的 next 数组 -》进行匹配 -》 返回结果,注意不要直接给数组命名next ,容易出现编译错误,可用大小写等区分。题型也基本集中于求第几位开始可以匹配、求匹配上的次数等,关键在于掌握构建next数组的方法以及匹配过程。下面是几道例题:北航上机题、上交上机题。

//KMP 求 next 数组的方法
int nextTable[10000];

void getNextTable(string pattern){
    int j = 0;
    nextTable[j] = -1;
    int i = nextTable[j];
    int m  = pattern.size();
    while(j < m){
        if(i == -1 || pattern[j] == pattern[i]){
            i++;
            j++;
            nextTable[j] = i;
        }else{
            i = nextTable[i];
        }
    }
    return ; 
}

// KMP 匹配的方法
int KMP(string text,string pattern){
    int m = text.size();
    int n = pattern.size();
    getNextTable(string pattern);
    int i = 0;
    int j = 0;
    while(i < m && j < n){
        if(j == -1 || text[i] == pattern[j]){
            i++;
            j++;
        }else{
            j = nextTable[j];
        }
    }
    if(j == n){
        return i - j + 1;   //返回开始匹配的位置
    }else{
        return -1;
    }
}

四、数据结构问题

本章主要介绍线性数据结构在机试题中的常见考察形式。

4.1 向量 Vector

本质为可变长数组,具体的使用方法可点击此篇博文。主要在无法确定数组大小的时候使用,参见清华大学上机题感受一下。

4.2 队列 Queue

队列的具体使用方法可点击此篇博文。使用队列可以很轻松的解决约瑟夫问题等先进先出的问题,要仔细观察题目意思。

4.3 栈 Stack

栈的具体使用方法可点击此篇博文。栈的应用场景相对来说比较广泛,比如模式匹配、表达式求值等,可查看上交复试上机题(表达式求值)、吉林大学(堆栈的使用)。

五、数学问题

此类问题通常不涉及很深奥的算法和数据结构,只与数理逻辑相关,典型的算法有进制转换、最大公约数与最小公倍数、质数、分解质因数、快速幂、矩阵与矩阵快速幂、高精度整数等。

5.1 进制转换问题

传统的进制转换问题求解并不难(此题采用传统求解方法)需要注意对 0 的处理,建议采用 do..while语句,此时不用对 0 进行特判。但若处理高精度的进制转换问题,需要参考高精度整数的运算方法,如清华大学上机题(将高精度十进制转为二进制),以及更近一步(将高精度十进制转为二进制并转为十进制),掌握这两种方法之后绝大部分的题都可以应对。高精度进制转换的关键代码:

#include
#include
#include
#include

using namespace std;


// 十进制转为 x 进制
string devide(string str,int x){
    int remainder = 0;
    for(int i = 0;i < str.size();i++){
        int current = remainder * 10 + (str[i] - '0');
        str[i] = current / x + '0';
        remainder = current % x;
    }
    int pos = 0;
    while(str[pos] == '0'){
        pos++;
    }
    return str.substr(pos);
}


// x 进制转为十进制
string multiple(string str,int x){
    int carry = 0;
    for(int i = str.size() - 1;i >= 0;i--){
        int current = x * (str[i] - '0') + carry;
        str[i] = current % 10 + '0';
        carry = current / 10;
    }
    if(carry != 0){
        str = '1' + str;
    }
    return str;
}

string add(string str,int x){
    int carry = x;
    for(int i = str.size() - 1;i >= 0;i--){
        int current = (str[i] - '0') + carry;
        str[i] = current % 10 + '0';
        carry = current / 10;
    }
    if(carry != 0){
        str = '1' + str;
    }
    return str;
}

int main(){
    string str;
    while(cin >> str){
        vector o;
        while(str.size() != 0){
            int last = str[str.size() - 1] - '0';
            o.push_back(last % 2);
            str = devide(str,2);
        }
        string answer = "0";
        for(int i = 0;i < o.size();i++){
            answer = multiple(answer,2);
            answer = add(answer,o[i]);
        }
    cout << answer << '\n';
    }
    return 0;
}

5.2 最大公约数与最小公倍数

原理比较简单,只需掌握一个求解最大公约数的关键方法,最小公倍数为两数相乘再除以最大公约数即可。

求解最大公约数的递归算法:

int gcd(int a,int b){
    if(b == 0){
        return a;
    }else{
        return gcd(b, a % b);
    }
}

5.3 素数问题

素数问题涉及到素数的判定、素数表的生成等。素数的判定一般采用求根值的方法,判断是否含有小于等于sqrt(n) 的因数,注意要从 2 开始,素数表的生成一般采用“埃氏筛法”,用到的代码如下:

const int maxn = 100010;
int flag[maxn]  = {0};
vector prime;

for(int i = 2;i < maxn;i++){
    if(flag == 0) prime.push_back(i);
    for(int j = i + i;j < maxn;j += i){
        flag[j] = 1;
    }
}

5.4 质因子分解

 质因子分解可能会统计输入数字的质因数个数等,一般的方法是首先生成质数表,质数表生成时的 maxn 上限在 输入数据 n的规模不太大时可以直接设置为 n ,但一般情况下 n 的范围都比较大,此时为了防止数组越界,将 maxn 的值设置为 sqrt(n) + 1,在计算时遍历除以所有的质数表后如果 n 还不是 1,那么直接 ans + 1即可。理论依据: n 至多只存在一个大于 sqrt()的质因数

 清华大学--质因数的个数

 

N、通用问题

N.1 单点测试和多点测试

    单、多点测试有时候平台会直接给出,比如PAT 普遍采用单点测试,每一个测试文件仅包含一个测试用例,通过一个会获得相应的分数,codeup 等大多数OJ都是采用多点测试,一个测试文件包含多个测试用例,全部通过才会获得相应的分数。通俗来说,单点测试写的是一次性程序,需要执行多次程序获得每一个结果,多点测试写的是可循环程序,只要反复执行程序的核心部分。

    在考试的过程中,很多题目会说明输入数据会包含多个测试用例,此时必须要采用多点测试的写法,若题目中没有明确采用单点测试,建议也按照多点测试来写。

    多点测试的几种写法:

// 1. while-EOF  用于不知道几个用例,不知道什么时候结束。

while(scanf("%d",&n) != EOF){
    // 核心部分
}

// 2. while - break  知道结束条件时用,比如输入 0 时结束

while scanf("%d",&n) != EOF){
    if(n == 0) break;
    // 核心部分
}

// 3 . while(T--)  知道一共有几组用例时

while(T --){
    // 核心部分
}

上篇结束,

其他专题请点击:搜索专题,图论专题,动态规划专题。

你可能感兴趣的:(考研复试上机)