LeetCode 73矩阵置零&74搜素二维矩阵&75颜色分类

新人公众号(求支持):bigsai 专注于Java、数据结构与算法,一起进大厂不迷路!
算法文章题解全部收录在github仓库bigsai-algorithm,求star!
关注回复进群即可加入力扣打卡群,欢迎划水。近期打卡:
打卡LeetCode 65有效数字&66加一 &67二进制求和
LeetCode 67二进制求和&68文本左右对齐&69x的平方根
LeetCode 70爬楼梯&71简化路径&72编辑距离(dp)
如有帮助,记得对本文一键三连!

矩阵置零

题目描述:

给定一个 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请你帮两件事帮忙一下:

  1. star支持一下, 您的肯定是我在平台创作的源源动力。

  2. 微信搜索「bigsai」,关注我的公众号,不仅免费送你电子书,我还会第一时间在公众号分享知识技术。加我还可拉你进力扣打卡群一起打卡LeetCode。

记得关注、咱们下次再见!

image-20201114211553660

Big sai CSDN认证博客专家 数据结构与算法 爬虫 Java
原创公众号:「bigsai」,回复【bigsai】获取珍藏pdf书籍资源,回复【进群】即可加入leetcode打卡群。分享Java,数据结构与算法,python爬虫知识,期待和优秀的你成为朋友!
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页
实付 19.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值