Acwing 常见笔试面试算法题

Problem 1- Problem 6

1. 蛇形矩阵

题目链接https://www.acwing.com/problem/content/758/
题目描述:用回形针📎的方式输出一个 n 行 m 列的矩阵(给定 n 和 m,输出 1 - n * m),类似如下:

	1 2 3
	8 9 4
	7 6 5

解题思路

  1. 用一个二维数组存储矩阵,枚举 1 - n * m,规定向右为第一个方向,用四个 while 来控制四个方向的推进。
  2. 推进的条件是下一个位置合法,且下个位置上没有元素。

优化思路:用棋盘常用的推进方法,即设置 dx[] 和 dy[],然后用一个 while 和一个变量 d 来控制四个方向的推进,判断条件不变。
代价分析:时间复杂度为 O(mn),空间复杂度为 O(mn),优化仅仅是减少了重复代码。

点击查看代码
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110;

int n, m;
int res[N][N];

int main()
{
    cin >> n >> m;
    
    int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
    
    for (int x = 0, y = 0, k = 1, d = 0; k <= n * m; k ++ ) {
        res[x][y] = k;
        int a = x + dx[d], b = y + dy[d];
        if (a < 0 || a >= n || b < 0 || b >= m || res[a][b]) {
            d = (d + 1) % 4;
            a = x + dx[d], b = y + dy[d];
        }
        x = a, y = b;
    }
    
    for (int i = 0; i < n; i ++ ) {
        for (int j = 0; j < m; j ++ ) {
            cout << res[i][j] << ' ';
        }
        cout << endl;
    }
    return 0;
}

题目延伸
参考:一篇 CSDN 博客
Leetcode 54. 螺旋矩阵 I, 螺旋形遍历,参考本题遍历部分;
Leetcode 59. 螺旋矩阵 II, 螺旋形生成二维数组,和本题基本一模一样,免去输入输出;
Leetcode 885. 螺旋矩阵 III,每个方向固定走两次,然后转向,如果坐标合法直接加入答案,否则继续走,不用判定是否出界;
Leetcode 2021年力扣杯春季编程大赛个人赛P2,与本题基本一模一样,除了数字由 1 - m * n 变成 1 - 9 循环。

这种题目好像还有数学解法,值得探究,暂时不做谈论。

2. 链表排序

题目链接https://www.acwing.com/problem/content/1451/
题目描述:给无序的链表排序
解题思路

  • 第一种思路:归并排序递归写法
  • 第二种思路:归并排序迭代写法
  • 第三种思路:快速排序,时间 O(NlogN), 空间 O(logN)

代价分析:时间复杂度为 O(mn),空间复杂度为 O(mn),优化仅仅是减少了重复代码。

点击查看代码
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110;

int n, m;
int res[N][N];

int main()
{
    cin >> n >> m;
    
    int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
    
    for (int x = 0, y = 0, k = 1, d = 0; k <= n * m; k ++ ) {
        res[x][y] = k;
        int a = x + dx[d], b = y + dy[d];
        if (a < 0 || a >= n || b < 0 || b >= m || res[a][b]) {
            d = (d + 1) % 4;
            a = x + dx[d], b = y + dy[d];
        }
        x = a, y = b;
    }
    
    for (int i = 0; i < n; i ++ ) {
        for (int j = 0; j < m; j ++ ) {
            cout << res[i][j] << ' ';
        }
        cout << endl;
    }
    return 0;
}

题目延伸
暂无

3. 寻找矩阵极小值

题目链接https://www.acwing.com/problem/content/1454/
题目描述:在 N * N 的数字各不相同的矩阵中找到比四个方向值都小的元素。
解题思路

  1. 二分所有的列,以每列的最小值为依据,寻找这样一个列:其最小值比左右两侧元素者都小的,这一列就是答案所在的列。
  2. 遍历此列,返回此列最小值的坐标。

代价分析:

  • 时间复杂度:二分列需要 O(logN), 每一次二分内部需要寻找最小值O(N), 总时间复杂度 O(NlogN)。
  • 空间复杂度:O(1)
点击查看代码
// Forward declaration of queryAPI.
// int query(int x, int y);
// return int means matrix[x][y].

class Solution {
public:
    vector<int> getMinimumValue(int n) {
        typedef long long LL;
        const LL INF = 1e15;
        // 找到极小值所在的列
        int l = 0, r = n - 1;
        while (l < r) {
            int mid = (l + r) >> 1;
            
            int k;
            LL val = INF;
            for (int i = 0; i < n; i ++) {
                int t = query(i, mid);
                if (t < val) {
                    k = i;
                    val = t;
                }
            }
            
            LL left = mid ? query(k, mid - 1) : INF;
            LL right = mid + 1 < n ? query(k, mid + 1) : INF;
            
            if (val < left && val < right) return {k, mid};
            if (val > left) r = mid - 1;
            else l = mid + 1;
        }
        // 找到极小值所在列的最小值
        int k;
        LL val = INF;
        for (int i = 0; i < n; i ++) {
            int t = query(i, l);
            if (t < val) {
                k = i;
                val = t;
            }
        }
        return {k, l};
    }
};

题目延伸
Leetcode 162. 寻找峰值, 一维的峰值,直接二分,明确答案一定在较大的那一侧;
Leetcode 1901. 寻找峰值 II, 与此题一模一样,但是是极大值;
Acwing 901. 滑雪, 看起来更难一些;

4. 鸡蛋的硬度(蓝桥杯扔手机)

题目链接https://www.acwing.com/activity/content/problem/content/1901/
题目描述:寻找一个方案数。
解题思路

  1. dp
    dp 状态表示:f[i][j] 表示 i 层高的楼用 j 个鸡蛋测试,属性是测试出硬度的测试次数。
    dp 状态计算:如果不使用第 j 个鸡蛋,f[i][j] = f[i][j - 1],如果使用第 j 个鸡蛋 f[i][j] = max(f[i - ])

代价分析:

  • 时间复杂度:二分列需要 O(logN), 每一次二分内部需要寻找最小值O(N), 总时间复杂度 O(NlogN)。
  • 空间复杂度:O(1)
posted @ 2023-03-24 13:51  ImproperMelon  阅读(54)  评论(0)    收藏  举报