机试题——最小矩阵宽度

题目描述

给定一个矩阵,包含 N * M 个整数,和一个包含 K 个整数的数组。

现在要求在这个矩阵中找一个宽度最小的子矩阵,要求子矩阵包含数组中所有的整数。

输入描述

第一行输入两个正整数 N,M,表示矩阵大小。

接下来 N 行 M 列表示矩阵内容。

下一行包含一个正整数 K。

下一行包含 K 个整数,表示所需包含的数组,K 个整数可能存在重复数字。

所有输入数据小于1000。

输出描述

输出包含一个整数,表示满足要求子矩阵的最小宽度,若找不到,输出 -1。

用例输入

bash 复制代码
2 5
1 2 2 3 1
2 3 2 3 2
3
1 2 3
bash 复制代码
2

我们需要找到一个子矩阵,包含数字 1、2 和 3,并且每个数字的频率都至少是它在数组中出现的次数。

当窗口的列范围为 3, 4 时:

窗口包括列:3, 1 和 3, 2,仍然包含数字 1、2 和 3。

bash 复制代码
2 5
1 1 3 2 3
1 3 2 3 4
3
1 1 4
bash 复制代码
5

解题思路

宽度最小,长度不限。其实就是找一个列区间。

  1. 滑动窗口法:使用滑动窗口在矩阵的列中查找子矩阵,保证窗口内包含所有需要的数字。窗口宽度从小到大逐步尝试,以找到最小的有效宽度。

  2. 具体步骤:

    • 对于每一行,记录每列的数字出现情况。
    • 维护一个滑动窗口,该窗口内的列包含所有需要的数字及其频率。随着窗口的扩大,检查该窗口是否满足条件。
    • 如果满足条件,尝试收缩窗口以找到最小宽度。
  3. 最终结果:输出最小宽度,如果没有找到有效的子矩阵,输出 -1。

代码

cpp 复制代码
#include <iostream>
#include <vector>
#include <map>
#include <climits>
#include <algorithm>
using namespace std;


int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> matrix(n, vector<int>(m));
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            cin >> matrix[i][j];
        }
    }
    int k;
    cin >> k;
    map<int, int> re;  // 存储所需的数字及其频率
    for (int i = 0; i < k; ++i) {
        int num;
        cin >> num;
        re[num]++;
    }
    int min_width = INT_MAX;// 初始化最小宽度为最大值
    // i 为列区间的起始
    for (int i = 0; i < m; ++i) {
        map<int, int> cur;// 当前窗口内的数字频率
        int ok = 0;  // 当前窗口包含的满足条件的数字个数
        // 滑动窗口的右边界
        for (int j = i; j < m; ++j) {
            // 更新当前窗口的数字频率 把j列的数据加进去
            for (int t = 0; t < n; t++) {
                int num = matrix[t][j];
                if (re.count(num)) {
                    cur[num]++;
                    // 当数字的频率达到了要求的数量时
                    if (cur[num] == re[num]) {
                        ok++;
                    }
                }
            }
            // 当前窗口包含所有需要的数字,更新最小宽度
            if (ok == re.size()) {
                min_width = min(min_width, j - i + 1);
            }
        }
    }
    // 输出结果
    if (min_width == INT_MAX) {
        cout << -1 << endl;
    }
    else {
        cout << min_width << endl;
    }
}
相关推荐
布莱克6051 分钟前
理解 = delete 与 = default:两种赋值语义的差异
c++
zhuhai_xigedian1 小时前
源网荷储一体化柜通信层:网络架构与协议矩阵设计
网络·矩阵·架构
物联网软硬件开发-轨物科技1 小时前
【轨物方案】深度解读开关柜智能感知及一键顺控专家系统
大数据·运维·网络·人工智能·算法·机器人
小小、码农1 小时前
[特殊字符]【C++11】类的新功能全面解析:移动构造、移动赋值、default、delete、final 与 override
linux·开发语言·网络·c++
行者全栈架构师1 小时前
我用 TRAE Work 把桌游之夜搬进了浏览器:一个计分器的从创意到上线
前端·算法·架构
YFJ_mily1 小时前
【10-12月优质学术会议合集】会议覆盖人工智能、大数据、高端装备、软件与网络安全 、计算机视觉技术等热门方向
算法·安全·web安全·网络安全·软件·rdlink研发家
库玛西2 小时前
外部排序全解析:败者树、置换-选择排序与最佳归并树
c语言·数据结构·c++·笔记·考研·算法
库玛西2 小时前
计算机网络第三章:数据链路层
服务器·网络·计算机网络·考研·算法·面试
邹霍梁@开源软件GoodERP2 小时前
【出海 ERP】本地没库存时:自产自销还是转口贸易?一张决策树给财务和 IT
算法·决策树·机器学习
程序 代码狂人2 小时前
经典 SQL 面试题:连续登录问题的两种经典解法
java·开发语言·算法