【算法一则】矩阵置零 【矩阵】【空间复用】

news2024/12/29 9:23:28

题目

给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。

示例 1:
在这里插入图片描述

输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]

示例 2:
在这里插入图片描述

输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]

提示:

m == matrix.length
n == matrix[0].length
1 <= m, n <= 200
-231 <= matrix[i][j] <= 231 - 1

题解

看到这题的时候我们第一时间肯定想申请一个跟原始matrix二维数组一模一样的数组A,遍历matrix来保存而为素组matrix中为0元素的位置。然后再遍历A将martix中对应的行和列的元素置为0。

public void setZeroes(int[][] matrix) {
    boolean[] row = new boolean[matrix.length];
    boolean[] col = new boolean[matrix[0].length];

    for (int i = 0; i < matrix.length; i ++) {
        for (int j = 0; j < matrix[0].length; j ++) {
            if (matrix[i][j] == 0) {
                row[i] = true;
                col[j] = true;
            }
        }
    }

    for (int i = 0; i < matrix.length; i ++) {
        for (int j = 0; j < matrix[0].length; j ++) {
            if (row[i] || col[j]) {
                matrix[i][j] = 0;
            }
        }
    }
}

在这里插入图片描述
看到这种方式空间使用率会很比较高大概O(2mn),这个时候有没有更好的解决办法呢!我用List<Map<String, String>> 包装类型来放为0元素的位置应该会小一点吧? 因为我只需要存特定是0的位置,其他的不为0的位置我不需要存。说干就干,试验一下:

public void setZeroes(int[][] matrix) {
   List<Map<Integer, Integer>> list = new ArrayList<>();
    for (int i = 0; i < matrix.length; i ++) {
        for (int j = 0; j < matrix[0].length; j ++) {
            if (matrix[i][j] == 0) {
                HashMap<Integer, Integer> integerHashMap = new HashMap<>();
                integerHashMap.put(i, j);
                list.add(integerHashMap);
            }
        }
    }

    for (Map<Integer, Integer> data : list) {
        data.forEach((k, v) -> {
            for (int i = 0; i < matrix.length; i++) {
                matrix[i][v] = 0;
            }

            for (int i = 0; i < matrix[0].length; i++) {
                matrix[k][i] = 0;
            }
        });

    }
}

在这里插入图片描述
可以看到空间使用率确实是好了一点,但是我们效率变得非常低了,执行时间只击败了17%的用户。而且空间利用率也不是很完美,主要也是包装类型本身也需要占用一些空间。有没有更好的方案呢?我们接着往下看。

进阶:

一个直观的解决方案是使用 O(mn) 的额外空间,但这并不是一个好的解决方案。
一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
你能想出一个仅使用常量空间的解决方案吗?

public void setZeroes(int[][] matrix) {
    boolean firstRowHasZero = false;
    boolean firstColHasZero = false;

    // 检查第一行是否有零
    for (int i = 0; i < matrix[0].length; i++) {
        if (matrix[0][i] == 0) {
            firstRowHasZero = true;
            break;
        }
    }

    // 检查第一列是否有零
    for (int i = 0; i < matrix.length; i++) {
        if (matrix[i][0] == 0) {
            firstColHasZero = true;
            break;
        }
    }

    // 使用第一行和第一列记录零的位置
    for (int i = 1; i < matrix.length; i++) {
        for (int j = 1; j < matrix[0].length; j++) {
            if (matrix[i][j] == 0) {
                matrix[i][0] = 0;
                matrix[0][j] = 0;
            }
        }
    }

    // 根据第一行和第一列的记录,将对应的行和列置零
    for (int i = 1; i < matrix.length; i++) {
        for (int j = 1; j < matrix[0].length; j++) {
            if (matrix[i][0] == 0 || matrix[0][j] == 0) {
                matrix[i][j] = 0;
            }
        }
    }

    // 如果第一行有零,则将第一行置零
    if (firstRowHasZero) {
        for (int i = 0; i < matrix[0].length; i++) {
            matrix[0][i] = 0;
        }
    }

    // 如果第一列有零,则将第一列置零
    if (firstColHasZero) {
        for (int i = 0; i < matrix.length; i++) {
            matrix[i][0] = 0;
        }
    }
}

在这里插入图片描述

这个优化后的代码使用了两个布尔变量来记录第一行和第一列是否有零。然后,通过遍历矩阵,使用第一行和第一列来记录零的位置。最后,根据这些记录,将对应的行和列置零。最后,根据第一行和第一列的记录,将第一行和第一列本身置零(如果需要)。

通过这种方法,我们只使用了常量级的额外空间来完成操作,将空间复杂度降到了最低。

总结

上述算法是对给定二维矩阵进行优化,以降低空间复杂度的算法。该算法使用常量级的额外空间来实现。

首先,算法通过遍历矩阵,检查第一行和第一列是否存在零,并使用两个布尔变量记录下来。接下来,算法再次遍历矩阵,将零的位置记录在第一行和第一列中,即如果某个元素为零,就将对应的第一行和第一列的元素置零。

然后,算法再次遍历矩阵,根据第一行和第一列的记录,将对应的行和列置零。具体实现时,如果某个元素所在的行的第一列元素或所在的列的第一行元素为零,则将该元素置零。

最后,算法根据最开始记录的两个布尔变量,如果第一行或第一列存在零,则将整行或整列置零。

通过这种优化方法,算法只使用了常量级的额外空间来完成操作,将空间复杂度降到了最低。这种算法的时间复杂度为O(m×n),其中m是矩阵的行数,n是矩阵的列数。

总之,该算法通过巧妙地利用矩阵的第一行和第一列来记录零的位置,并根据这些记录将对应的行和列置零,从而实现了对给定矩阵的优化。这种优化方法在空间复杂度方面非常高效,适用于处理大规模的二维矩阵。

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

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

相关文章

设计模式代码实战-中间者模式

1、问题描述 小明正在设计一个简单的多人聊天室系统&#xff0c;有多个用户和一个聊天室中介者&#xff0c;用户通过中介者进行聊天&#xff0c;请你帮他完成这个系统的设计。 输入示例 3 User1 User2 User3 User1 Hello_All! User2 Hi_User1! User3 How_is_everyone? 输出…

写后端项目的分页查询时,解决分页不更新

写基于VueSpringBoot项目&#xff0c;实现分页查询功能时&#xff0c;改完代码后&#xff0c;发现页数不更新&#xff1a; 更改处如下&#xff1a; 显示如图&#xff1a; 发现页数没有变化&#xff0c;两条数据还是显示在同一页&#xff0c;而且每页都10条。且重启项目也没有更…

【408直通车】C+Python赋能数据结构:从底层原理到高级应用的蜕变之路——线性表

本专栏旨在通过使用C语言和Python分别实现各种考研常见数据结构&#xff0c;从底层原理和应用两个角度深入探索数据结构。通过深入理解数据结构的底层原理和掌握Python的高级特性&#xff0c;读者将能够全面掌握数据结构的知识&#xff0c;并且学会如何在实际应用中灵活运用。 …

查天气(Vue.js,Element UI)

演示图 几点注意 有亿点简陋&#xff0c;凑合能用&#xff0c;button一定要 !important 覆盖原本的 element ui &#xff0c;不然无效axios回调函数中 this 指向改变了&#xff0c;需要额外的保存一份服务器返回的数据比较复杂时&#xff0c;获取的时候需要注意层级结构method…

光伏电站智能勘探:无人机优势及流程详解

随着科技和互联网技术的不断发展&#xff0c;无人机在各个领域的应用越来越广泛&#xff0c;其中之一就是光伏电站智能勘探。利用无人机高清摄像头和传感器等设备&#xff0c;可以对光伏电站周边环境、日照情况、房屋状态进行全方面的勘探和记录&#xff0c;搭配卫星勘探、实地…

自动驾驶(八十四)---------中间件对比分析

很久没有写博客了&#xff0c;CSDN无故非法删了我第82篇&#xff0c;让我很恼火&#xff0c;一直提不起兴趣重新写一遍第82篇。但回初心&#xff0c;知识需要用自己的语言输出&#xff0c;所以今天对比分析自动驾驶中间件&#xff1a; 1. 中间件介绍 在自动驾驶架构中&#xf…

第14章 大数据与数据科学知识点梳理

第14章 大数据与数据科学知识点梳理&#xff08;附带页码&#xff09; ◼ 原则&#xff1a;组织应仔细管理与大数据源相关的元数据&#xff0c;以便对数据文件及其来源和价值进行准确的清单管理。P386 ◼ 大数据&#xff1a;数据量大&#xff08;Volume&#xff09;、数据更新…

嵌入式中C++指针使用方法总结

各位开发者大家好,在分享指针之前,先来看一下int *p[3]和int (*p)[3] 的区别。 int *p[3] p是一个数组,此数组有3个元素,每个元素都是int*类型,也就是指向整型数据的指针类型。 int a=10,b=20,c=30; int*p[3]={&a,&b,&c}; 而int(*p)[3]中的p是一个指向数组的…

浅谈Java的synchronized 锁以及synchronized 的锁升级

在Java中&#xff0c;synchronized关键字用于实现线程间的同步&#xff0c;确保同一时刻只有一个线程能够访问被同步的代码块或方法。当一个线程获得synchronized锁定后&#xff0c;其他试图访问同一锁的线程将被阻塞&#xff0c;直到锁被释放。 synchronized锁有两种基本形式…

计算机网络实验实验之VLAN的配置与分析

实验目的 了解什么是带内管理&#xff1b;熟练掌握如何使用telnet方式管理交换机&#xff1b;熟练掌握如何为交换机设置web方式管理&#xff1b;熟练掌握如何进入交换机web管理方式&#xff1b;了解交换机web配置界面&#xff0c;并能进行部分操作。 (6)了解VLAN原理&#xf…

python pygame事件与事件处理

本期是接上期python pygame库的略学内容最后一个步骤&#xff0c;游戏与玩家交互的内容。 一、什么是事件 游戏需要与玩家交互&#xff0c;因此它必须能够接收玩家的操作&#xff0c;并根据玩家的不同操作做出有针对性的响应。程序开发中将玩家会对游戏进行的操作称为事件&…

微服务架构与Dubbo

一、微服务架构 微服务架构是一种架构概念&#xff0c;旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦。 分布式系统式若干独立系统的集合&#xff0c;但是用户使用起来好像是在使用一套系统。 和微服务对应的是单体式开发&#xff0c;即所有的功能打包在一个WAR…

关于CRMEB 商城系统商业授权的那些事儿

现在&#xff0c;很多时候我们都会听到“授权”这个词&#xff0c;在CRMEB的商城系统产品中&#xff0c;商业授权也是一个重要环节&#xff0c;今天&#xff0c;我们就来了解一下关于CRMEB商城系统授权的那些事儿。 一、为什么要进行商业授权&#xff1f; 正版商业授权是对用户…

【Linux】详解如何利用共享内存实现进程间通信

一、共享内存&#xff08;Shared Memory&#xff09;的认识 共享内存&#xff08;Shared Memory&#xff09;是多进程间共享的一部分物理内存。它允许多个进程访问同一块内存空间&#xff0c;从而在不同进程之间共享和传递数据。这种方式常常用于加速进程间的通信&#xff0c;因…

软考130-上午题-【软件工程】-系统维护

一、系统维护概述 软件维护是软件生命周期中的最后一个阶段&#xff0c;处于系统投入生产性运行以后的时期中&#xff0c;因此不属于系统开发过程。 软件维护是在软件已经交付使用之后为了改正错误或满足新的需求而修改软件的过程&#xff0c;即软件在交付使用后对软件所做的一…

李沐-19 卷积层【动手学深度学习v2】

记录下关于权重下标变换的理解&#xff1a; 从原来的Wi,j到Wi,j,k,l是从二维到四维的过程&#xff0c;如下图所示 对全连接层使用平移不变性和局部性得到卷积层&#xff0c;这是卷积层的引入&#xff0c;下方Vi,j,a,b--->Va,b表示了平移不变性&#xff0c;给a,b限制在||内保…

C语言 【函数】

1.函数概述 函数是一种可重用的代码块&#xff0c;用于执行特定任务或完成特定功能 函数作用&#xff1a;对具备相同逻辑的代码进行封装&#xff0c;提高代码的编写效率&#xff0c;实现对代码的重用 2. 函数的使用 2.1 无参无返回值 #include <stdio.h>// 函数名…

光纤收发器的注意事项

光纤收发器有各种不同的类别&#xff0c;而实际使用中最受关注的是根据光纤收发器的不同类别&#xff1a;SC连接器光纤收发器和FC/ST连接器光纤收发器。 当使用光纤收发器连接到不同的设备时&#xff0c;必须小心使用不同的端口。 1.光纤收发器与100Base TX设备&#xff08;交…

IP定位技术原理详细阐述

IP定位技术原理主要基于IP地址与地理位置之间的关联&#xff0c;通过一系列的技术手段&#xff0c;实现对网络设备的物理位置进行精确或大致的定位。以下是对IP定位技术原理的详细阐述。 首先&#xff0c;我们需要了解IP地址的基本概念。IP地址是互联网协议地址的简称&#xff…

【leetcode】双指针算法技巧——滑动窗口

标题&#xff1a;【leetcode】双指针算法技巧——滑动窗口 水墨不写bug 正文开始&#xff1a; 滑动窗口介绍 滑动窗口是一种常用的算法技巧&#xff0c;用于解决一些涉及 连续子数组或子串 的问题。它的基本思想是 维护一个窗口&#xff0c;通过 在窗口内移动 来寻找满…