头像

Jaryn上岸




离线:4天前


最近来访(47)
用户头像
Highest
用户头像
fdgdf
用户头像
ಠoಠ_3
用户头像
SpecialTree
用户头像
たき
用户头像
NeyScar
用户头像
多线程的this.FrankZhou
用户头像
happinesspill
用户头像
Fearless1015
用户头像
cpy2010
用户头像
Feelme
用户头像
瑾川致知
用户头像
d0ub1edd
用户头像
typhoon42
用户头像
AcWingYyyyyy
用户头像
FD2023
用户头像
Pobz
用户头像
Carry_2
用户头像
acwing_1067
用户头像
简答题

分享 2014机试题

题目链接: https://www.acwing.com/blog/content/30368/

一. 二分查找次数

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/19 4:34 下午
 * Desc :第一行输入一个整数N(N<=10000)。
        第二行输入N个升序整数。
        第三行输入一个待查找的整数(必定在第二行中出现过)。

        输出二分查找该整数时,进行过多少次二分。
 */
const int N = 100010;
int a[N];
int main() {
    int n, target, cnt = 0;
    cin >> n;
    for (int i = 0; i < n; i++) cin >> a[i];
    cin >> target;

    int l = 0, r = n - 1;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (a[mid] >= target) {
            r = mid - 1;
        } else {
            l = mid + 1;
        }
        cnt++;
    }

    cout << cnt;
    return 0;
}

二. 字符串距离编辑

https://www.acwing.com/problem/content/904/

三. 二叉树前中后序遍历

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/19 4:34 下午
 * Desc :输入一棵二叉树,输出树的前、中、后序遍历结果。
          输入一个整数N(N<= 10000),表示树中有N个结点(编号0~N-1)。
          接下来N行,依次为结点0~结点N-1的左右孩子情况。
          每行3个整数,F,L,R。L,R为F的左右孩子。L,R如果为-1表示该位置上没有孩子。
          分三行分别输出树的前中后序遍历。
          同一行中的数字,用一个空格间隔。
 */
typedef struct TreeNode {
    int val;
    TreeNode *left = NULL, *right = NULL, *parent = NULL; // 父节点方便找到root
}TreeNode ;

const int N = 10010;
TreeNode* a[N];

void preOrder(TreeNode * p) {
    if (p == NULL) return;
    cout << p -> val << " ";
    preOrder(p -> left);
    preOrder(p -> right);
}

void inOrder(TreeNode * p) {
    if (p == NULL) return;
    inOrder(p -> left);
    cout << p -> val << " ";
    inOrder(p -> right);
}

void postOrder(TreeNode * p) {
    if (p == NULL) return;
    postOrder(p -> left);
    postOrder(p -> right);
    cout << p -> val << " ";
}

int main() {
    int n; cin >> n;

    // 先将树存在一个数组中,方便后续构造树
    for (int i = 0; i < n; i++) {
        TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode));
        node -> val = i;
        a[i] = node;
    }

    // 建树
    for (int i = 0; i < n; i++) {
        int parent, left, right;
        cin >> parent >> left >> right;
        TreeNode *p = a[parent];
        if (left != -1) {
            p -> left = a[left];
            a[left] -> parent = p;
        }
        if (right != -1) {
            p -> right = a[right];
            a[right] -> parent = p;
        }
    }
    TreeNode *root = a[0];
    while (root -> parent) { // 0不一定是根,所以需要找到根节点
        root = root -> parent;
    }

    preOrder(root); cout << endl;
    inOrder(root); cout << endl;
    postOrder(root);
    return 0;
}

四.hanoi

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/19 4:34 下午
 * Desc :Hanoi 塔问题是印度的一个古老的传说。开天辟地的神勃拉玛在一个庙里留下了三根金刚石的棒,
 * 第一根上面套着64 个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,
 * 庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,
 * 而且大的不能放在小的上面。
 *
    请编写程序,把A 柱上的n 个金片,搬动到C 柱(中间可以使用B 柱),使得搬动的次数最少。
    输入金片的个数n(1<=n<=64),输出总搬动次数,以及最后100 次搬动。如果搬动次数小于等于100 则全部输出;
    每个搬动占一行,加上是这第几次搬动的数字和”:”,格式见示例。
 */


int ans;
int f[70]; // f[i]表示有i个圆环时的搬动总次数
int nn;
void hanoi(int n, char a, char b, char c) { // 将a的通过b搬到c
    if (n == 1) {
        ans++;
        if (f[nn] - ans <= 100)
             cout << ans << ":" << a << "->" << c << endl;
        return;
    }
    hanoi(n - 1, a, c, b); // 把a的前n-1个移到b先
    hanoi(1, a, b, c); // 把a的最后一个移到c
    hanoi(n - 1, b, a, c); // 把b的n-1个移到c
}
int main() {

    cin >> nn;

    // 计算f[i]
    f[1] = 1;
    for (int i = 2; i <= nn; i++) {
        f[i] = f[i - 1] * 2 + 1; // 先把前i-1个搬到b,再把最大的搬到c,再把b的n-1个搬到c。所以是2* + 1
    }
    cout << f[nn] << endl;
    hanoi(nn, 'A', 'B', 'C');

    return 0;
}


分享 2013机试题

题目链接: https://www.acwing.com/blog/content/32375/

一. 字符串匹配

kmp,机试先考虑用find

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/17 3:34 下午
 * Desc :对于主串M和模式串P,找到P在M中出现的所有子串
            的第一个字符在P中的位置。
            P中第一个字符所在的位置为0。
            首行的数字表示有多少组字符串。
 */

int main() {
    string sstr, pstr;
    int x;
    cin >> x;
    while (x--) {
        cin >> (sstr) >> (pstr);
        int n = sstr.size(), m = pstr.size();
        vector<char> s(n + 1), p(m + 1);
        for(int i = 0; i < n; i++) s[i + 1] = sstr[i]; // 转为下标从1开始
        for(int i = 0; i < n; i++) p[i + 1] = pstr[i];
        vector<int> ne(m + 1);

        for (int i = 2, j = 0; i <= m; i++) {
            while (j && p[i] != p[j + 1]) j = ne[j];
            if (p[i] == p[j + 1]) j++;
            ne[i] = j;
        }
        for (int i = 1, j = 0; i <= n; i++) {
            while (j && s[i] != p[j + 1]) j = ne[j];
            if (s[i] == p[j + 1]) j++;
            if (j == m) {
                cout << i - j << " ";
                j = ne[j];
            }
        }
        cout << endl;
    }
    return 0;
}

二. AFamousICPCTeam

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/17 3:34 下午
 * Desc :给出四个正方体箱子的边长,问能装下这四个正方体箱子
    的大正方体边长最小要多大,要求边长最小且必须能装下四个箱子。

 */

int main() {
    int a,b,c,d;
    cin >> a >> b >> c >> d;
    // 22组合的最大值
    int ans = -1;
    ans = max(ans, a + b);
    ans = max(ans, a + c);
    ans = max(ans, a + d);
    ans = max(ans, b + c);
    ans = max(ans, b + d);
    ans = max(ans, c + d);
    cout << ans;
    return 0;
}

三. A famous grid(螺旋矩阵)

http://acm.hdu.edu.cn/showproblem.php?pid=4255
思路:
先用筛法,找出101*101内的素数(因为输入的两点值限制是一万内);之后去填满数组arr[101][101],像图片中那样从arr[50][50](也就是1)开始填起,如果是素数就填-1表示这个路径不通,否则填入相应的数字;之后用bfs找出最短路径
可以用一个数组存储PII,数组下标是对应的值,内容是对应的下标

填满数组的具体思路:观察可知,1先向右边走1步生成2,再向上走1步生成3,| 再向左走2步生成4/5,再向下走2步生成6/7 | 再向右边走3步生成8/9/10,再向上走3步生成11/12/13....
可知:先是右上各走1,左下各走2,右上各走3,可利用一个bool变量表示是右上还是左下,自增变量表示步长,当生成的数大于1万就可以停止。

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/18 6:34 下午
 * Desc :在螺旋矩阵中,问两个位置(不能经过素数位置)之间的最短距离是多少
 * 思路:先用筛法,找出101*101内的素数(因为输入的两点值限制是一万内);
 * 之后去填满数组arr[110][110],像图片中那样从arr[50][50](也就是1的位置)开始填起,
 * 如果是素数就填-1表示这个路径不通,否则填入相应的数字;之后用bfs找出最短路径(走迷宫)
 *
 */
typedef pair<int, int> PII;
const int N = 20010;
int primes[N];
bool flag[N]; // false表示是素数
int g[110][110], cnt;
PII pos[N]; // 数组下标是矩阵的值,内容是对应的下标


void lineSelect() {
    flag[1] = true; // 1不是素数
    for (int i = 2; i <= 10000; i++) {
        if (!flag[i]) primes[cnt++] = i;
        for (int j = 0; i * primes[j] <= 10000; j++) {
            flag[i * primes[j]] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

void generateSpiralArray() {
    // 具体思路:观察可知,1先向右边走1步生成2,再向上走1步生成3,| 再向左走2步生成4/5,再向下走2步生成6/7 | 再向右边走3步生成8/9/10,再向上走3步生成11/12/13....
    // 可知:先是右上各走1,左下各走2,右上各走3,可利用一个bool变量表示是右上还是左下,
    // 自增变量表示步长,当生成的数大于1万就可以停止。
    pos[1] = {50, 50}; // 只要是中心位置就可,49,49也行,通过pos下标已经对应好了
    g[50][50] = 1;
    int num = 1;
    int len = 1; // 步长
    bool direct = true; // true就是右上,false就是左下
    PII start = {50, 50};
    while (num <= 10000) {
        if (direct) { // 右 + 上,走len步
            // 右走len步
            int x = start.first, y = start.second;
            for (int i = 1; i <= len; i++) {
                y++;
                num++;
                pos[num] = {x, y};
                g[x][y] = flag[num] ? num : -1;
            }
            // 上走len步
            for (int i = 1; i <= len; i++) {
                x--;
                num++;
                pos[num] = {x, y};
                g[x][y] = flag[num] ? num : -1;
            }
            start = {x, y};
            direct = false;
            len++;
        } else {
            // 左 + 下
            int x = start.first, y = start.second;
            // 左
            for (int i = 1; i <= len; i++) {
                y--;
                num++;
                pos[num] = {x, y};
                g[x][y] = flag[num] ? num : -1; // 质数存-1
            }
            // 下走len步
            for (int i = 1; i <= len; i++) {
                x++;
                num++;
                pos[num] = {x, y};
                g[x][y] = flag[num] ? num : -1;
            }
            start = {x, y};
            direct = true;
            len++;
        }
    }
}

int bfs(int startNum, int endNum) {
    PII start = pos[startNum];
    PII end = pos[endNum];
    queue<PII> q;
    q.push(start);
    int dist[110][110]; // 存储从 start出发的最短路径
    memset(dist, -1, sizeof dist);
    dist[start.first][start.second] = 0;

    int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, -1, 1};
    while (q.size()) { // 遇到-1就不能通过
        PII c = q.front();
        q.pop();

        int x = c.first;
        int y = c.second;
        if (x == end.first && y == end.second) {
            return dist[x][y];
        }
        for (int i = 0; i < 4; i++) {
            int nX = x + dx[i];
            int nY = y + dy[i];
            if (nX >= 0 && nX < 110 && nY >= 0 && nY < 110 && dist[nX][nY] == -1
                && g[nX][nY] != -1) {
                dist[nX][nY] = dist[x][y] + 1;
                q.push({nX, nY});
            }
        }
    }
    return -1;
}

int main() {
    // 线性筛法
    lineSelect();
    // 生成螺旋数组
    generateSpiralArray();
    // bfs
    int start, end;
    while (cin >> start >> end) {
        int res = bfs(start, end);
        if (res == -1) cout << "impossible";
        else cout << res << endl;

    }
    return 0;
}


分享 2012机试题

题目链接: https://www.acwing.com/blog/content/32376/

一. 1000名求前30

快排,其实应该用堆排的

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/17 3:34 下午
 * Desc :输入10个,按顺序打印3个
10
1 2 0 3 4 9 8 7 5 6
 */
int a[1000];

void quickSort (int a[], int l, int r) {
    if (l >= r) return;
    int mid = a[(l + r) >> 1], i = l - 1, j = r + 1;
    while (i < j) {
        do i++; while(a[i] < mid);
        do j--; while(a[j] > mid);
        if (i < j) swap(a[i], a[j]);
    }
    quickSort(a, l, j);
    quickSort(a, j + 1, r);
}
int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    quickSort(a, 0, n - 1);
    for (int i = 0; i < n / 3; i++) {
        cout << a[i] << " ";
    }
    return 0;
}

二. 二叉树最大叶子间距

先层序建树,再递归求直径

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/17 3:34 下午
 * Desc :最大叶子间距,就是求树的直径
 * 思路:先建树,再递归求直径
 */
typedef struct TreeNode {
    int val;
    TreeNode *left = NULL, *right = NULL;
} TreeNode;

int diameter = 0;

// 求直径
int postOrder(TreeNode* p) {
    if (p == NULL) return 0;
    int lHigh = postOrder(p -> left);
    int rHigh = postOrder(p -> right);
    diameter = max(diameter, lHigh + rHigh + 1);
    return max(lHigh, rHigh) + 1;
}

int main() {
    int val;
    cin >> val;
    TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));
    root -> val = val;
    queue<TreeNode*> q;
    q.push(root);
    int preLeftVal, preRightVal;
    // 建树
    while (q.size()) {

        int leftVal, rightVal;
        cin >> leftVal >> rightVal;
        // 出现两次-1 -1就结束
        if (leftVal == -1 && rightVal == -1 && preLeftVal == -1 && preRightVal == -1) break;

        // 当前结点
        TreeNode *c = q.front();
        q.pop();
        if (leftVal != -1) {
            TreeNode *node = new TreeNode();
            node -> val = leftVal;
            c -> left = node;
            q.push(node);
        } else c -> left = NULL;
        if (rightVal != -1) {
            TreeNode *node = new TreeNode();
            node -> val = rightVal;
            c -> right = node;
            q.push(node);
        } else c -> right = NULL;

        preLeftVal = leftVal;
        preRightVal = rightVal;
    }

    // 求直径
    postOrder(root);
    cout << diameter - 1; // -1是因为diameter求的结点数量,-1就是路径长度
    return 0;
}

三. 字符串的重复输出

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/17 3:34 下午
 * Desc :给一个字符串比如ABC 再给一个整数比如3输出AAABBBCCC就行了。

 */
int main() {
    string res = "";
    string s;
    cin >> s;
    int x;
    cin >> x;
    for (int i = 0; i < s.size(); i++) {
        for (int j = 0; j < x; j++) res += s[i];
    }
    cout << res;
    return 0;
}


分享 2011机试题

题目链接: https://www.acwing.com/file_system/file/content/whole/index/content/8534207/

一. 最长公共子序列LCS

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/17 3:34 下午
 * Desc :输入3个子串, 输出这3个子串的最大公共子串
         输入 : abcd acb abc  输出:ab

 */
const int N = 100;
string f[N][N][N];
int main() {
    string a, b, c;
    cin >> a >> b >> c;

    for (int i = 1; i <= a.size(); i++) {
        for (int j = 1; j <= b.size(); j++) {
            for (int k = 1; k <= c.size(); k++) {
                // 相同时
                if (a[i - 1] == b[j - 1] && b[j - 1] == c[k - 1]) {
                    f[i][j][k] = f[i - 1][j - 1][k - 1] + a[i - 1];
                } else {
                    // 不同时则选长度大
                    if (f[i - 1][j][k].size() > f[i][j - 1][k].size()
                            && f[i - 1][j][k].size() > f[i][j][k - 1].size()) {
                        f[i][j][k] = f[i - 1][j][k];
                    } else if (f[i][j - 1][k].size() > f[i - 1][j][k].size()
                               && f[i][j - 1][k].size() > f[i][j][k - 1].size()) {
                        f[i][j][k] = f[i][j - 1][k];
                    } else {
                        f[i][j][k] = f[i][j][k - 1];
                    }
                }
            }
        }
    }
    cout << f[a.size()][b.size()][c.size()];
    return 0;
}

二. 中序与后序求层次遍历

思路:先建树,再层序遍历

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/17 3:34 下午
 * Desc :输入树的中序和后序排列,输出树的层次遍历
输入:
7
1 2 3 4 5 6 7
2 3 1 5 7 6 4
输出:4 1 6 3 5 7 2
 */

typedef struct TreeNode {
    int val;
    TreeNode *left = NULL, *right = NULL;
} TreeNode;

TreeNode* create(vector<int> &mid, vector<int> &post, int midL, int midR, int postL, int postR) {
    if (midL > midR) return NULL;
    if (postL > postR) return NULL;
    int val = post[postR]; // 当前根节点
    int pos = -1;
    for (int i = midL; i <= midR; i ++) {
        if (val == mid[i]) {
            pos = i;
            break;
        }
    }

    TreeNode *node = (TreeNode*)malloc(sizeof(TreeNode));
    node -> val = val;
    node -> left = create(mid, post, midL, pos - 1, postL, postL + pos - midL - 1);
    node -> right = create(mid, post, pos + 1, midR, postL + pos - midL, postR - 1);
    return node;
}

int main() {
    // 思路:先建树、再层次遍历
    int n;
    cin >> n;
    vector<int> mid(n), post(n);
    for (int i = 0; i < n; i++) cin >> mid[i];
    for (int i = 0; i < n; i++) cin >> post[i];
    TreeNode *root = create(mid, post, 0, n - 1, 0, n - 1);

    queue<TreeNode*> q;
    q.push(root);
    cout << root -> val << " ";
    while (q.size()) {
        auto c = q.front();
        q.pop();

        if (c -> left) {
            cout <<  c -> left -> val << " ";
            q.push(c -> left);
        }
        if (c -> right) {
            cout <<  c -> right -> val << " ";
            q.push(c -> right);
        }
    }
    return 0;
}


分享 2022机试题

题目链接: https://www.acwing.com/blog/content/31261/
全是lc原题,2个hard一个mid

第一题的基本思路:

求最大表现值:至多k个工程师,他们的速度和*最小效率 的最大值

使用排序 + 枚举 + 小根堆(定一个,动一个)

根据效率降序排序,以每一个人为最小效率(枚举),找这个人左边的k-1个较大的速度和的工程师(堆实现)



分享 2021机试题

题目链接: https://blog.csdn.net/weixin_41994332/article/details/115829716

一. 二叉树

两种解法:1.层次构建树,利用后序遍历,存储遍历路径后比较
2.下标从1开始,那么父节点下标:当前下标/2,依次比较即可
这里采取1,本题关键在于输入,没有给长度,所以要先读取一整行,再分隔做!

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/8 11:35 上午
 * Desc :给定一颗二叉树,树的每个节点的值为一个正整数。
 * 如果从根节点到节点 N 的路径上不存在比节点 N 的值大的节点,
 * 那么节点 N 被认为是树上的关键节点。求树上所有的关键节点的个数。
 */
typedef struct TreeNode{
    int val;
    TreeNode *left = NULL, *right = NULL;
} TreeNode;

vector<int> path;
queue<TreeNode *> q;

int res = 1; // 根默认是

void postOrder(TreeNode *p) {
    if (p == NULL) return;
    path.push_back(p -> val);
    postOrder(p -> left);
    postOrder(p -> right);
    bool isKey = true;
    for (int i = 0; i < path.size() - 1; i++) {
        if (path[i] > path[path.size() - 1]) isKey = false;
    }
    if (isKey) res++;
    path.pop_back();
}

// 使用后序遍历,存储 遍历路径上的结点值,每到一个结点只需判断 这些结点值是否都小于等于当前结点值 即是关键结点
int main() {

    string nodeVal;
    vector<string> nodeVals;

    // 先读取根
    cin >> nodeVal;
    TreeNode *root = new TreeNode();
    root -> val = stoi(nodeVal);
    q.push(root);

    string s;
    // 读入一整行,不能用cin >> s,因为遇到空格会结束读取
    getline(cin, s);
    stringstream ss(s);
    // 最后一个参数是分隔符
    while (getline(ss, nodeVal, ' ')) {
        nodeVals.push_back(nodeVal);
    }

    // 层次建树
    int cnt = 1;
    while (q.size()) {
        if (cnt >= nodeVals.size()) {
            break;
        }
        TreeNode *p = q.front();
        q.pop();
        if (p == NULL) {
            q.push(NULL);
            q.push(NULL);
            continue;
        }
        TreeNode *newNode = new TreeNode();
        string val = nodeVals[cnt++];
        if (val != "null") {
            newNode->val = stoi(val);
            p -> left = newNode;
            q.push(newNode);
        } else q.push(NULL);

        TreeNode *newNode2 = new TreeNode();
        val = nodeVals[cnt++];
        if (val != "null") {
            newNode->val = stoi(val);
            p -> right = newNode2;
            q.push(newNode2);
        } else q.push(NULL);

    }

    postOrder(root);
    cout << res;
    return 0;
}


二. 爬楼梯

https://leetcode.cn/problems/climbing-stairs/

三. 目标和

https://leetcode.cn/problems/target-sum/



分享 2020机试题

题目链接: https://www.acwing.com/blog/content/30297/

一. 排队打饭

贪心

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/7 10:49 上午
 * Desc :下课了,有 n 位同学陆续赶到⻝堂进⾏排队打饭,其中第 i 位同学的到达时间为 ai,
          打饭耗时为 ti,等待时间上限为 bi,即如果其在第 ai+bi秒的时刻仍然没有轮到他开
          始打饭,那么他将离开打饭队列,另寻吃饭的地⽅。问每位同学的开始打饭时间,或者
          指出其提前离开了队伍(如果这样则输出 -1)。
 */
const int N = 100010;

struct Student {
    int arrive, consume, wait;
}students[N];

bool cmp(Student a, Student b) {
//    return a.arrive + a.consume < b.arrive + b.consume;
    return a.arrive < b.arrive;
}

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        int a, t, b;
        cin >> a >> t >> b;
        students[i] = {a, t, b};
    }
    sort(students + 1, students + 1 + n, cmp);

    int lastOver = 1;
    for (int i = 1; i <= n; i++) {
        auto stu = students[i];
        if (stu.arrive + stu.wait < lastOver) {
            cout << "-1 ";
        } else {
            cout << lastOver << " ";
            lastOver += stu.consume;
        }
    }

    return 0;
}

二. 斗牛

模拟

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/7 11:04 上午
 * Desc :给定五个 0~9 范围内的整数 a1, a2, a3, a4, a5。如果能从五个整数中选出三个并
        且这三个整数的和为10 的倍数(包括 0),那么这五个整数的权值即为剩下两个没被
        选出来的整数的和对 10 取余的结果,显然如果有多个三元组满⾜和是 10 的倍数,
        剩下两个数之和对 10 取余的结果都是相同的(因为5个元素总和一样);如果
        选不出这样三个整数,则这五个整数的权值为 -1。
        现在给定 T 组数据,每组数据包含五个 0~9 范围内的整数,分别求这 T 组数据中
        五个整数的权值。
 */
vector<int> nums(5);

// 这里可以改为三数之和,三指针,找出三个并且这三个整数的和为10 的倍数
tuple<int, int, int> find() {
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            for (int k = 0; k < 5; k++) {
                if (i != j && j != k && i != k && ((nums[i] + nums[j] + nums[k]) % 10 == 0)) {
                    return {i, j, k};
                }
            }
        }
    }
    return {-1, -1, -1};
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        nums.clear(); // 多组数据
        for (int i = 0; i < 5; i++) cin >> nums[i];
        sort(nums.begin(), nums.end());

        // 找出三个并且这三个整数的和为10的倍数(包括 0)
        auto res = find();
        if (get<0>(res) == -1) {
            cout << -1 << endl;
            continue;
        }

        int sum = 0;
        for (int i = 0; i < 5; i++) {
            if (i != get<0>(res) && i != get<1>(res) && i != get<2>(res)) {
                sum += nums[i];
            }
        }
        cout << sum % 10 << endl;
    }
    return 0;
}


三. 打地鼠

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/7 11:35 上午
 * Desc :给定 n 个整数 a1, a2, …, an 和⼀个 d,你需要选出若⼲个整数,使得将这些整数从⼩到⼤排好序之后,
 *  任意两个相邻的数之差都不⼩于给定的d(>=d),问最多能选多少个数出来。
 */
const int N = 100010;
int a[N];
int main() {
    int n, d;
    cin >> n >> d;
    for (int i = 0; i < n; i++) cin >> a[i];
    sort(a, a + n);

    int cnt = 1; // 默认选了a[0]
    for (int i = 1; i < n; i++) {
        if (a[i] - a[i - 1] >= d) {
            cnt++;
        }
    }
    cout << cnt;
    return 0;
}

四. 序列

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/7 11:35 上午
 * Desc :给定⼀个⻓为 n 的序列 A,其中序列中的元素都是 0~9 之间的整数,对于⼀个⻓度同样为 n 整数序列B
         定义其权值为 |A[i]-B[i]| (1<=i<=n) 之和加上 (B[j]-B[j+1])的平方 (1<=j<n) 之和。
         求所有⻓为 n 的整数序列中,权值最⼩的序列的权值是多少。
 */

// 1. f[i][j]表示前i个数字(也就是1到i),且b[i] == j 的权值和最小值,其中j小于10
int f[100001][10], a[100001];
int main() {
    // 2.定状态转移方程:f[i][j]可由 前i-1个数字,且b[i - 1] == k 的权值和最小值f[i - 1][k]
    //                                                  加上a[i]这一位的权值,最后取min
    // 3.定边界,f[0][0]前0个字符,且 b[0] == j 的权值和最小值(次数),不存在,就是0
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];

    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < 10; j++) { // 这里的j就是b[i]
            f[i][j] = INT_MAX;
            for (int k = 0; k < 10; k++) { // 这里的就是b[i - 1]
                // 转移方程
                f[i][j] = min(f[i][j], f[i - 1][k] + abs(a[i] - j) + (j - k) * (j - k));
            }
        }
    }

    int res = INT_MAX;
    for (int i = 1; i <= n; i++) res = min(f[n][i] ,res);

    cout << res;
    return 0;
}

四. 二叉搜索树

#include <bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/7 11:35 上午
 * Desc :给定⼀个 1~n 的排列 P,即⻓度为 n,且 1~n 中所有数字都恰好出现⼀次的序列。
 * 现在按顺序将排列中的元素⼀⼀插⼊到初始为空的⼆叉搜索树中(左小右大),问最后每个节点的⽗亲节点的元素是什么。
 * 特别地,根节点的⽗亲节点元素视为 0。
 */
const int N = 100010;
int a[N];
typedef struct TreeNode {
    int val;
    TreeNode *l, *r, *p;
} TreeNode;

void midOrder(TreeNode *p) {
    if (p == NULL) return;
    midOrder(p -> l);
    if (p -> p != NULL) cout <<  p -> p -> val << " ";
    else cout << "0 ";
    midOrder(p -> r);
}

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) cin >> a[i];
    TreeNode *root = new TreeNode();
    root -> val = a[0];
    root -> l = NULL;
    root -> r = NULL;
    // 建树
    for (int i = 1; i < n; i++) {
        TreeNode *p = root, *pre;
        bool isLeft = true;
        while (p != NULL) {
            pre = p; // 指向p的前驱
            if (a[i] < p -> val) {
                p = p->l;
                isLeft = true;
            }
            else {
                p = p->r;
                isLeft = false;
            }
        }
        auto *newNode = new TreeNode();
        newNode -> val = a[i];
        newNode -> l = NULL;
        newNode -> r = NULL;
        newNode -> p = pre;
        if (isLeft) pre -> l = newNode;
        else pre -> r = newNode;
    }
    // 中序遍历
    midOrder(root);
    return 0;
}


分享 2019机试题

题目链接: https://www.acwing.com/blog/content/30294/

一. 日期差值

https://www.acwing.com/problem/content/3501/

二. 最大连续子序列

dp

#include<bits/stdc++.h>

using namespace std;

/**
 * Author :Jaryn
 * Time :2023/3/6 6:44 下午
 * Desc :dp,f[i]表示以下标i元素结尾的最大连续子序列和
 */
const int N = 100010;
int a[N], f[N];
int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) cin >> a[i];

    f[0] = a[0];
    for (int i = 1; i < n; i++) {
        // 必须要以a[i]结尾,那么有俩种情况:
        //          之前的最大连续序列包含a[i],这种情况是前i-1个大于0
        //          或者是 a[i]独自成为一个序列,这种情况是前i-1个小于等于0
        if(f[i - 1] > 0) f[i] = f[i - 1] + a[i];
        else f[i] = a[i];
    }
    int ans = -2e9;
    for (int i = 0; i < n; i++) {
        ans = max(ans, f[i]);
    }
    cout << ans;
    return 0;
}

三. 有向树形态

dp,同lc:不同的二叉搜索树
https://www.acwing.com/problem/content/description/3694/



分享 2018机试题

题目链接: https://www.acwing.com/file_system/file/content/whole/index/content/7849705/

一. 求众数

https://www.acwing.com/problem/content/3688/

二. 集合交并

https://www.acwing.com/problem/content/3691/

三. 骨牌

https://www.acwing.com/problem/content/3690/
思路1. 对蒙德里安的猜想的代码进行修改
思路2. f[i]表示前i列的排放种类数量
f[i - 1] + 上摆放1个竖着的骨牌
f[i - 2] + 上摆放2个横着的骨牌(注意若摆放两个竖着的骨牌,包含在上面这种情况了)
所以f[i] = f[i - 1] + f[i - 2]

四.求交点

https://www.acwing.com/problem/content/description/3693/

五.解一元一次方程

记录等式左边x的系数,以及出现的常数
记录等式右边x的系数,以及出现的常数
将右边x的系数变负(移到左边)加上左边x系数,左边x的常数变负(移到右边)加上右边x常数
若x系数为0且常数不为0,那么无解,若都为0则无穷解

六.约数求和

https://www.acwing.com/problem/content/description/3692/



分享 2017机试题

题目链接: https://www.acwing.com/file_system/file/content/whole/index/content/7853602/

一. 求中位数

题目:https://www.acwing.com/problem/content/1508/

#include<bits/stdc++.h>

using namespace std;

const int N = 2 * 100010;

int a[N], b[N];

// 思路1. 合并后排序
// 思路2. 归并排序,找中间那位
int main() {
    int n, m;
    cin >> n;
    for (int i = 0; i < n; i++) cin >> a[i];
    cin >> m;
    for (int i = 0; i < m; i++) cin >> b[i];

    int targetPos = (n + m - 1) / 2; // 中位数下标为(长度 - 1) / 2

    int i = 0, j = 0, k = 0;
    while (i < n && j < m) {
        if (k == targetPos) {
            cout << min(a[i], b[j]);
            return 0;
        }
        if (a[i] <= b[j]) {
            i++;
        } else {
            j++;
        }
        k++;
    }
    while (i < n) {
        if (k == targetPos) {
            cout << (a[i]);
            return 0;
        }
        k++;i++;
    }
    while (j < m) {
        if (k == targetPos) {
            cout << (b[j]);
            return 0;
        }
        k++;j++;
    }
    return 0;
}

二. 求解校验码

模拟

#include <bits/stdc++.h>

using namespace std;

int main() {
    string isbn;
    cin >> isbn;

    int s = 0, cnt = 10;
    for (int i = 0; i < isbn.size(); i++) {
        if (isbn[i] == '-') continue;
        int currentNum = isbn[i] - '0';
        s += currentNum * (cnt--);
    }
    int m = s % 11;
    int subM = 11 - m;

    if (subM >= 1 && subM <= 9) {
        isbn.append("-" + to_string(subM));
    } else if (subM == 10) {
        isbn.append("-X");
    } else { // subM == 11
        isbn.append("-0");
    }
    cout << isbn;
    return 0;
}

三. 无向图-MST

见基础-prim和kruskal