矩阵置零
题目描述:
给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。
示例 1:
输入: [ [1,1,1], [1,0,1], [1,1,1] ] 输出: [ [1,0,1], [0,0,0], [1,0,1] ]
示例 2:
输入: [ [0,1,2,0], [3,4,5,2], [1,3,1,5] ] 输出: [ [0,0,0,0], [0,4,5,0], [0,3,1,0] ]
进阶:
一个直接的解决方案是使用 O(mn) 的额外空间,但这并不是一个好的解决方案。
一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
你能想出一个常数空间的解决方案吗?
分析:
这道题可谓是一波三折,对于O(m*n)的方法不谈了,没啥好讲了。
从O(m+n)的方法说起,一维空间,只要出现0,那么这一行或者这一列就全部变成0,那么就可以用两个boolean数组解决,一个标记行,一个标记列,遍历的时候遇到0就把该行和该列标记为true。最终根据两个boolean数组进行赋值即可。
实现代码为:
class Solution { public void setZeroes(int[][] matrix) { boolean hang[]=new boolean[matrix.length]; boolean lie[]=new boolean[matrix[0].length]; for (int i=0;i<matrix.length;i++) { for(int j=0;j<matrix[i].length;j++) { if(matrix[i][j]==0) { hang[i] = true; lie[j] = true; } } } for(int i=0;i<hang.length;i++) { if(hang[i]) { for(int j=0;j<lie.length;j++) { matrix[i][j]=0; } } } for(int j=0;j<lie.length;j++) { if(lie[j]) { for(int i=0;i<hang.length;i++) { matrix[i][j]=0; } } } } }
题目有说到要使用常数级别的额外空间,而这种情况就要考虑空间的复用!这个就想了一下谈谈我的想法:
这题的核心问题是在根据行或者列遍历的时候不能第一次遇到就把改行和列置零,说说我的错误想法:
- 第一趟按行遍历,遇到0那么将这一行所有数据特殊的标记起来。 我首先想到的是除0以外标记成负数。
- 第二趟按列遍历,遇到0直接将该列置为0(行已经遍历过)。遇到负数的时候置为0.
如果所有数据是正数,那么这是可行的,但是很可疑测试数据有负数,over。。
后来又想逃巧将所有数据换成int的最大值或者最小值,但是不幸的是测试有这两组数据,把我卡的死死的。
后来只能先用枚举的方法找到一个数组中不存在的数,因为二维数组是有大小范围int [m][n]
的,所以在[1,m*n+1] 范围内一定有一个不存在的数可以作为临时标记。
第二趟按照列遍历,遇到0直接将该列置为0(行已经遍历过)。遇到标记的那个数将那个位置数字为0.
实现代码为:
class Solution { public void setZeroes(int[][] matrix) { boolean jud=false;// int num=1; //找到一个合适的数字用于临时替换 for(int q=1;q<matrix.length*matrix[0].length+2;q++) { jud=false; outer: for (int i=0;i<matrix.length;i++) { for(int j=0;j<matrix[i].length;j++) { if(matrix[i][j]==q) { jud=true; break outer; } } } if(!jud) { num=q;break; } } //遍历行 for (int i=0;i<matrix.length;i++) { for(int j=0;j<matrix[i].length;j++) { if(matrix[i][j]==0) { for(int q=0;q<matrix[0].length;q++) { if(matrix[i][q]!=0) matrix[i][q]=num; } break; } } } for(int j=0;j<matrix[0].length;j++)//列 { for (int i=0;i<matrix.length;i++) { if(matrix[i][j]==0) { for(int q=0;q<matrix.length;q++) { matrix[q][j]=0; } break; } if(matrix[i][j]==num) matrix[i][j]=0; } } } }
搜素二维矩阵
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
示例 1:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,50]], target = 3 输出:true
示例 2:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,50]], target = 13 输出:false
示例 3:
输入:matrix = [], target = 0 输出:false
提示:
m == matrix.length n == matrix[i].length 0 <= m, n <= 100 -104 <= matrix[i][j], target <= 104
分析:
这题可以根据数据进行两次二分,第一次二分对第一列找到对应的行,第二次对对应的行进行二分找到对应的位置。
具体代码为:
class Solution { public boolean searchMatrix(int[][] matrix, int target) { if(matrix.length==0||matrix[0].length==0)return false; //先对第一行进行二分定位到该列 if(matrix[0][0]>target) return false; int l=0,r=matrix.length; while (l<r) { int mid=(l+r)/2; if(matrix[mid][0]==target) return true; if(matrix[mid][0]<target) { l=mid+1; } else { r=mid; } } int index=l-1; l=0;r=matrix[0].length; while (l<r) { int mid=(l+r)/2; if(matrix[index][mid]==target) return true; if(matrix[index][mid]<target) { l=mid+1; } else { r=mid; } } return false; } }
颜色分类
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
进阶:
你可以不使用代码库中的排序函数来解决这道题吗?
你能想出一个仅使用常数空间的一趟扫描算法吗?
示例 1:
输入:nums = [2,0,2,1,1,0] 输出:[0,0,1,1,2,2]
示例 2:
输入:nums = [2,0,1] 输出:[0,1,2]
示例 3:
输入:nums = [0] 输出:[0]
示例 4:
输入:nums = [1] 输出:[1]
提示:
n == nums.length 1 <= n <= 300 nums[i] 为 0、1 或 2
分析:
方法比较灵活,可以用双指针,一个在左,一个在右,遍历的时候遇到0和2分别分配在左侧和右侧。
具体实现可用一个left,right标记左右往中间扩散,left左侧都是0,right右侧都是2,遍历的时候遇到需要交换的则交换,和快排的思想有些相似。
实现代码:
class Solution { public void sortColors(int[] nums) { int left=0; int right=nums.length-1; for(int i=0;i<right+1;i++) { if(nums[i]==0) { int team=nums[left]; nums[left++]=0; nums[i]=team; } else if(nums[i]==2) { int team=nums[right]; nums[right--]=2; nums[i]=team; i--; } } } }
结语
原创不易,bigsai请你帮两件事帮忙一下:
- star支持一下, 您的肯定是我在平台创作的源源动力。
- 微信搜索「bigsai」,关注我的公众号,不仅免费送你电子书,我还会第一时间在公众号分享知识技术。加我还可拉你进力扣打卡群一起打卡LeetCode。