【华为OD-E卷-开心消消乐 100分(python、java、c++、js、c)】

【华为OD-E卷-开心消消乐 100分(python、java、c++、js、c)】

题目

给定一个 N 行 M 列的二维矩阵,矩阵中每个位置的数字取值为 0 或 1。矩阵示例如:
1 1 0 0
0 0 0 1
0 0 1 1
1 1 1 1
现需要将矩阵中所有的 1 进行反转为 0,规则如下:
当点击一个 1 时,该 1 便被反转为0,同时相邻的上、下、左、右,以及左上、左下、右上、右下 8 个方向的 1(如果存在1)均会自动反转为 0 进一步地,一个位置上的 1 被反转为0时,与其相邻的 8 个方向的 1(如果存在1)均会自动反转为0 按照上述规则示例中的矩阵只最少需要点击 2 次后,所有值均为 0。
请问,给定一个矩阵,最少需要点击几次后,所有数字均为 0?

输入描述

  • 第一行为两个整数,分别表示句子的行数 N 和列数 M,取值范围均为 [1, 100]

接下来 N 行表示矩阵的初始值,每行均为 M 个数,取值范围 [0, 1]

输出描述

  • 输出一个整数,表示最少需要点击的次数

用例

用例一:
输入:
3 3
1 0 1
0 1 0
1 0 1
输出:
1
用例二:
输入:
4 4
1 1 0 0
0 0 0 1
0 0 1 1
1 1 1 1
输出:
2

python解法

  • 解题思路:
  • 题目描述类似于“计算二维矩阵中连通块的个数”。在一个二维矩阵中,每个元素可能是1或0,其中1表示某个区域的一部分,0表示空白区域。两个1如果在上下左右或对角线相邻,则被视为同一个连通块的一部分。

解题步骤:
使用深度优先搜索(DFS)方法遍历二维矩阵,将属于同一连通块的所有1置为0,避免重复计数。
遍历整个矩阵,如果找到一个1,则说明发现了一个新的连通块,点击次数(clicks)加1,并通过DFS将该连通块标记清空。
最后输出连通块的总数(clicks)。

# 输入矩阵的行数和列数
n, m = map(int, input().split())# 输入矩阵的元素
matrix = [list(map(int, input().split())) for _ in range(n)]# 定义DFS函数,用于深度优先搜索
def dfs(x, y):# 将当前点标记为已访问(置为0)matrix[x][y] = 0# 遍历当前位置的8个方向(上下左右+对角线)for offsetX, offsetY in [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]:newI, newJ = x + offsetX, y + offsetY# 判断新位置是否在矩阵范围内,且为未访问的'1'if 0 <= newI < n and 0 <= newJ < m and matrix[newI][newJ] == 1:dfs(newI, newJ)# 初始化连通块计数器
clicks = 0# 遍历整个矩阵
for i in range(n):for j in range(m):# 如果找到一个未访问的'1',开始DFSif matrix[i][j] == 1:dfs(i, j)  # 深度优先搜索清理连通块clicks += 1  # 连通块数量+1# 输出连通块的数量
print(clicks)

java解法

  • 解题思路
  • 题目是计算二维矩阵中连通块的个数,其中连通块由值为1的元素组成,并且连通规则包括上下左右以及对角线八个方向。我们采用广度优先搜索(BFS)的方法来解决这个问题:

遍历整个矩阵,找到值为1且未被标记的元素,视为一个新的连通块,计数加1。
使用一个队列进行BFS,将该连通块中的所有元素标记为已访问,避免重复计数。
BFS时,从当前元素出发,检查八个方向上的相邻元素,若其值为1且未被标记,则将其加入队列,继续处理。
重复上述过程,直到遍历完整个矩阵,输出连通块的数量

import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);// 输入矩阵的行数和列数int rowCount = input.nextInt();int colCount = input.nextInt();// 初始化矩阵int[][] matrix = new int[rowCount][colCount];for (int i = 0; i < rowCount; i++) {for (int j = 0; j < colCount; j++) {matrix[i][j] = input.nextInt();}}// 调用计算连通块数量的函数并输出结果System.out.println(calculateClicks(matrix, rowCount, colCount));}// 计算连通块数量的函数public static int calculateClicks(int[][] matrix, int rowCount, int colCount) {// 标记矩阵,用于记录某个位置是否已访问boolean[][] marked = new boolean[rowCount][colCount];// 初始化连通块计数器int clickCount = 0;// 遍历矩阵的每个元素for (int i = 0; i < rowCount; i++) {for (int j = 0; j < colCount; j++) {// 如果当前元素是未访问的'1',视为新连通块if (matrix[i][j] == 1 && !marked[i][j]) {clickCount++;// 使用队列进行BFSQueue<int[]> queue = new LinkedList<>();queue.add(new int[]{i, j});marked[i][j] = true; // 标记为已访问// BFS遍历连通块中的所有元素while (!queue.isEmpty()) {int[] point = queue.poll(); // 取出队列头部的坐标int x = point[0];int y = point[1];// 遍历当前位置的八个方向for (int[] dir : new int[][]{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}) {int newX = x + dir[0];int newY = y + dir[1];// 检查新坐标是否在矩阵范围内,且是未访问的'1'if (newX >= 0 && newX < rowCount && newY >= 0 && newY < colCount && matrix[newX][newY] == 1 && !marked[newX][newY]) {marked[newX][newY] = true; // 标记新坐标为已访问queue.add(new int[]{newX, newY}); // 将新坐标加入队列}}}}}}// 返回连通块的数量return clickCount;}
}

C++解法

  • 解题思路
  • 本题使用并查集(Union-Find Set)解决,目标是统计二维矩阵中连通块的数量。每个值为1的元素被视为连通块的一部分,两个1如果在八个方向相邻,则属于同一个连通块。

具体步骤:
并查集初始化:将矩阵中每个元素映射为一维数组中的一个节点,构建并查集,每个节点初始时自成一个集合。
矩阵遍历:
对于每个值为1的元素,检查其八个方向上的相邻元素。
如果相邻元素值为1,将当前元素和相邻元素合并到同一集合中。
如果当前元素为0,则直接减少集合计数。
计数连通块:并查集中最终剩余的集合数即为连通块的数量。
优势:
使用并查集,能够高效处理连通块合并操作。
每次union操作和find操作的时间复杂度接近 O(1)(通过路径压缩和按秩合并优化)。

#include <iostream>
#include <vector>using namespace std;// 并查集类
class UnionFindSet {
public:vector<int> fa;  // 父节点数组int count;       // 连通块计数// 构造函数,初始化并查集UnionFindSet(int n) {fa.resize(n); // 初始化父节点数组count = n;    // 初始时每个节点自成一个集合for (int i = 0; i < n; i++) {fa[i] = i;}}// 查找操作,路径压缩优化int find(int x) {if (x != fa[x]) {fa[x] = find(fa[x]); // 将当前节点直接连接到根节点}return fa[x];}// 合并操作,按秩优化void unionSets(int x, int y) {int x_fa = find(x); // 找到x的根节点int y_fa = find(y); // 找到y的根节点if (x_fa != y_fa) { // 如果不在同一集合fa[y_fa] = x_fa; // 将y的根节点连接到x的根节点count--;         // 连通块数量减少}}
};// 获取连通块数量的函数
int getResult(vector<vector<int>>& matrix, int n, int m) {UnionFindSet ufs(n * m); // 构造一个大小为n*m的并查集// 八个方向的偏移量vector<vector<int>> offsets = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};// 遍历矩阵中的每个元素for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 如果当前元素不是1,减少连通块计数并跳过if (matrix[i][j] != 1) {ufs.count--;continue;}// 遍历8个方向的相邻元素for (const auto& offset : offsets) {int newI = i + offset[0]; // 新位置的行坐标int newJ = j + offset[1]; // 新位置的列坐标// 检查新位置是否在矩阵范围内且为1if (newI >= 0 && newI < n && newJ >= 0 && newJ < m && matrix[newI][newJ] == 1) {ufs.unionSets(i * m + j, newI * m + newJ); // 合并当前节点和相邻节点}}}}return ufs.count; // 返回连通块的数量
}int main() {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];}}// 计算连通块数量并输出cout << getResult(matrix, n, m) << endl;return 0;
}

C解法

  • 解题思路

更新中

JS解法

  • 解题思路

  • 本题是关于统计二维矩阵中连通块的数量,其中连通规则是元素值为1且在上下左右或对角线方向相邻的元素视为同一连通块。采用并查集(Disjoint Set Union, DSU)来解决。

核心思路:
并查集初始化:
将二维矩阵中的每个元素映射到一维数组,构建一个并查集。
初始时,每个元素自成一个集合。
遍历矩阵:
对于矩阵中值为1的元素,检查其八个方向的相邻元素是否也是1。
如果是,将当前元素与相邻元素合并到同一集合。
如果当前元素值为0,则从连通块计数中减1。
返回结果:
遍历完成后,并查集中剩余的集合数量即为连通块的数量。
优点:
并查集通过路径压缩和按秩优化,使find和merge操作的时间复杂度接近 O(1)。
算法整体复杂度为 O(n * m),适合处理大规模矩阵。

const readline = require("readline");const rl = readline.createInterface({input: process.stdin,output: process.stdout,
});let data = [];
let rows, cols;rl.on("line", (input) => {data.push(input);// 读取第一行,获取矩阵的行数和列数if (data.length === 1) {[rows, cols] = data[0].split(" ").map(Number);}// 读取完整矩阵后开始处理if (rows && data.length === rows + 1) {data.shift(); // 去掉第一行const grid = data.map((row) => row.split(" ")); // 解析矩阵console.log(minClicks(grid, rows, cols)); // 输出结果data = [];}
});// 主函数:计算连通块数量
function minClicks(grid, rows, cols) {const dsu = new DisjointSet(rows * cols); // 初始化并查集const directions = [[-1, -1], // 左上[-1, 0],  // 上[-1, 1],  // 右上[0, -1],  // 左[0, 1],   // 右[1, -1],  // 左下[1, 0],   // 下[1, 1],   // 右下];// 遍历矩阵的每个元素for (let r = 0; r < rows; r++) {for (let c = 0; c < cols; c++) {// 如果当前元素不是1,则减少连通块计数并跳过if (grid[r][c] != "1") {dsu.count--;continue;}// 遍历当前元素的八个方向for (let [dr, dc] of directions) {const newRow = r + dr;const newCol = c + dc;// 检查新位置是否在矩阵范围内且值为1if (newRow >= 0 &&newRow < rows &&newCol >= 0 &&newCol < cols &&grid[newRow][newCol] == "1") {dsu.merge(r * cols + c, newRow * cols + newCol); // 合并当前元素与相邻元素}}}}return dsu.count; // 返回连通块数量
}// 并查集类
class DisjointSet {constructor(size) {this.parent = Array.from({ length: size }, (_, i) => i); // 初始化父节点数组this.count = size; // 初始连通块数量}// 查找操作,带路径压缩find(p) {if (this.parent[p] !== p) {this.parent[p] = this.find(this.parent[p]); // 递归查找根节点并路径压缩}return this.parent[p];}// 合并操作merge(p, q) {const rootP = this.find(p); // 找到p的根节点const rootQ = this.find(q); // 找到q的根节点// 如果p和q不在同一集合中,将q的根节点连接到p的根节点if (rootP !== rootQ) {this.parent[rootQ] = rootP;this.count--; // 连通块数量减少}}
}

注意:

如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/63688.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Unity]【图形渲染】【游戏开发】Shader数学基础4-更多矢量运算

在计算机图形学和着色器编程中,矢量运算是核心的数学工具之一。矢量用于描述空间中的位置、方向、速度等各种物理量,并在图形变换、光照计算、纹理映射等方面起着至关重要的作用。本篇文章将详细讲解矢量和标量之间的乘法与除法、矢量的加法与减法、矢量的模与单位矢量、点积…

【漏洞复现】CVE-2023-37461 Arbitrary File Writing

漏洞信息 NVD - cve-2023-37461 Metersphere is an opensource testing framework. Files uploaded to Metersphere may define a belongType value with a relative path like ../../../../ which may cause metersphere to attempt to overwrite an existing file in the d…

Bcrypt在线密码加密生成器

具体前往&#xff1a;在线Bcrypt加密工具--使用bcrypt及生成salt的迭代次数强度参数计算生成哈希(摘要)

Django 模板分割及多语言支持案例【需求文档】-->【实现方案】

Django 模板分割及多语言支持案例 这个案例旨在提供一个清晰的示范&#xff0c;展示如何将复杂的页面分解为多个可复用的模板组件&#xff0c;使代码更加模块化和易于管理。希望这篇案例文章对你有所帮助。 概述 在 Django 项目开发中&#xff0c;使用模板分割和多语言支持能…

wxWidgets使用wxStyledTextCtrl(Scintilla编辑器)的正确姿势

开发CuteMySQL/CuteSqlite开源客户端的时候&#xff0c;需要使用Scintilla编辑器&#xff0c;来高亮显示SQL语句&#xff0c;作为C/C领域最成熟稳定又小巧的开源编辑器&#xff0c;Scintilla提供了强大的功能&#xff0c;wxWidgets对Scintilla进行包装后的是控件类&#xff1a;…

构建高性能异步任务引擎:FastAPI + Celery + Redis

在现代应用开发中&#xff0c;异步任务处理是一个常见的需求。无论是数据处理、图像生成&#xff0c;还是复杂的计算任务&#xff0c;异步执行都能显著提升系统的响应速度和吞吐量。今天&#xff0c;我们将通过一个实际项目&#xff0c;探索如何使用 FastAPI、Celery 和 Redis …

介绍 Html 和 Html 5 的关系与区别

HTML&#xff08;HyperText Markup Language&#xff09;是构建网页的标准标记语言&#xff0c;而 HTML5 是 HTML 的最新版本&#xff0c;包含了一些新的功能、元素、API 和属性。HTML5 相对于早期版本的 HTML&#xff08;比如 HTML4&#xff09;有许多重要的改进和变化。以下是…

【win10+RAGFlow+Ollama】搭建本地大模型助手(教程+源码)

一、RAGFlow简介 RAGFlow是一个基于对文档深入理解的开源RAG&#xff08;Retrieval-augmented Generation&#xff0c;检索增强生成&#xff09;引擎。 主要作用&#xff1a; 让用户创建自有知识库&#xff0c;根据设定的参数对知识库中的文件进行切块处理&#xff0c;用户向大…

qwt 之 QwtPlotPicker

QwtPlotMarker 和 QwtPlotPicker 是 Qwt 库中用于增强 QwtPlot 功能的两个重要类。它们分别用于在图中添加标记和实现交互式的选择或拖动功能。 QwtPlotPicker 提供了交互式的选择工具&#xff0c;它允许用户通过鼠标点击或拖动来选择图表中的数据点或区域。这对于实现缩放、平…

C/C++圣诞树

系列文章 序号直达链接1C/C爱心代码2C/C跳动的爱心3C/C李峋同款跳动的爱心代码4C/C满屏飘字表白代码5C/C大雪纷飞代码6C/C烟花代码7C/C黑客帝国同款字母雨8C/C樱花树代码9C/C奥特曼代码10C/C精美圣诞树11C/C俄罗斯方块12C/C贪吃蛇13C/C孤单又灿烂的神-鬼怪14C/C闪烁的爱心15C…

lua dofile 传参数

cat 1.lua arg[1] 111 arg[2] 222 dofile(./2.lua) cat 2.lua print("First argument is: " .. arg[1]) print("Second argument is: " .. arg[2]) 执行 lua 1.lua&#xff0c;结果为&#xff1a; First argument is: 111 Second argument is: 222 l…

电商数据流通的未来:API接口的智能化与自动化趋势

在数字化时代&#xff0c;电子商务行业正在以前所未有的速度发展&#xff0c;而API&#xff08;应用程序编程接口&#xff09;接口作为电商领域的重要组成部分&#xff0c;其应用和发展趋势也日益受到关注。API接口作为电商系统与外部服务或平台交互的桥梁&#xff0c;对电商数…

投标心态:如何在“标海战术”中保持清醒的头脑?

在竞争激烈的市场环境下&#xff0c;“标海战术”——即大规模参与投标——已经成为许多企业争取市场份额的重要策略。然而&#xff0c;盲目追求投标数量可能导致资源浪费、团队疲劳以及战略目标的模糊化。在这种高强度的竞争模式中&#xff0c;如何保持清醒的头脑&#xff0c;…

【苍穹外卖】学习心得体会-随笔

前言 写了很久&#xff0c;终于可以完整运行项目了&#xff0c;记录下这几天的心得体会回顾一下知识点 第一天、Git 分布式版本控制工具 一、Git概述 定义&#xff1a;是分布式版本控制工具&#xff0c;用于管理软件开发中的源代码文件&#xff0c;像Java类、xml文件、html…

windows C#-使用构造函数

实例化类或结构时&#xff0c;将会调用其构造函数。 构造函数与该类或结构具有相同名称&#xff0c;并且通常初始化新对象的数据成员。 在下面的示例中&#xff0c;通过使用简单构造函数定义了一个名为 Taxi 的类。 然后使用 new 运算符对该类进行实例化。 在为新对象分配内存…

研发效能DevOps: Vite 使用 Element Plus

目录 一、实验 1.环境 2.初始化前端项目 3.安装 vue-route 4.安装 pinia 5.安装 axios 6.安装 Element Plus 7.gitee创建工程 8. 配置路由映射 9.Vite 使用 Element Plus 二、问题 1.README.md 文档推送到gitee未自动换行 2.访问login页面显示空白 3.表单输入账户…

5G 模组 RG500Q常用AT命令

5G 模组 RG500Q常用AT命令 5G 模组 RG500Q常用AT命令 at ATQNWPREFCFG\"mode_pref\",nr5g && sleep 1 at ATQNWPREFCFG\"nr5g_band\",79 && sleep 1 at atqnwlock\"commo…

NVIDIA DeepStream插件之Gst-nvtracker

NVIDIA DeepStream插件之Gst-nvtracker 1. 源由2. 基础知识3. Gst-nvtracker插件3.1 插件参数3.2 插件API接口 4. 分析问题5. 总结6. 参考资料 1. 源由 这篇的主要目的是稍微吐槽下NVIDIA的设计&#xff0c;当然其实他们做的还是不错的&#xff08;从系统架构设计角度看&#…

进程内存转储工具|内存镜像提取-取证工具

1.内存转储&#xff0c;内存转储&#xff08;Memory Dump&#xff09;是将计算机的物理内存&#xff08;RAM&#xff09;内容复制到一个文件中的过程&#xff0c;这个文件通常被称为“内存转储文件”或“核心转储文件”&#xff08;Core Dump&#xff09;,内存转储的主要目的是…

Lua语言入门 - Lua 面向对象

Lua 面向对象 面向对象编程&#xff08;Object Oriented Programming&#xff0c;OOP&#xff09;是一种非常流行的计算机编程架构&#xff0c;通过创建和操作对象来设计应用程序。 以下几种编程语言都支持面向对象编程&#xff1a; CJavaObjective-CSmalltalkC#Ruby Lua 是…