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

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

矩阵置零



题目描述:


给定一个 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.


20201129184113437.png


实现代码为:


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:


20201129162448358.png


输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,50]], target = 3
输出:true


示例 2:


20201129162459767.png


输入: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,遍历的时候遇到需要交换的则交换,和快排的思想有些相似。


20201129190007772.png


实现代码:


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。


目录
相关文章
|
16天前
|
存储 数据采集 算法
LeetCode题目73:矩阵置零
LeetCode题目73:矩阵置零
|
12天前
|
算法
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
|
12天前
|
算法
【经典LeetCode算法题目专栏分类】【第11期】递归问题:字母大小写全排列、括号生成
【经典LeetCode算法题目专栏分类】【第11期】递归问题:字母大小写全排列、括号生成
|
12天前
|
算法
【经典LeetCode算法题目专栏分类】【第9期】深度优先搜索DFS与并查集:括号生成、岛屿问题、扫雷游戏
【经典LeetCode算法题目专栏分类】【第9期】深度优先搜索DFS与并查集:括号生成、岛屿问题、扫雷游戏
|
12天前
|
算法
【经典LeetCode算法题目专栏分类】【第8期】滑动窗口:最小覆盖子串、字符串排列、找所有字母异位词、 最长无重复子串
【经典LeetCode算法题目专栏分类】【第8期】滑动窗口:最小覆盖子串、字符串排列、找所有字母异位词、 最长无重复子串
|
12天前
|
算法
【经典LeetCode算法题目专栏分类】【第7期】快慢指针与链表
【经典LeetCode算法题目专栏分类】【第7期】快慢指针与链表
|
12天前
|
算法
【经典LeetCode算法题目专栏分类】【第6期】二分查找系列:x的平方根、有效完全平方数、搜索二位矩阵、寻找旋转排序数组最小值
【经典LeetCode算法题目专栏分类】【第6期】二分查找系列:x的平方根、有效完全平方数、搜索二位矩阵、寻找旋转排序数组最小值
|
12天前
|
算法 机器人
【经典LeetCode算法题目专栏分类】【第5期】贪心算法:分发饼干、跳跃游戏、模拟行走机器人
【经典LeetCode算法题目专栏分类】【第5期】贪心算法:分发饼干、跳跃游戏、模拟行走机器人
|
12天前
|
算法
【经典LeetCode算法题目专栏分类】【第4期】BFS广度优先算法:单词接龙、最小基因变化、二进制矩阵中的最短路径
【经典LeetCode算法题目专栏分类】【第4期】BFS广度优先算法:单词接龙、最小基因变化、二进制矩阵中的最短路径
|
12天前
|
算法
【经典LeetCode算法题目专栏分类】【第3期】回溯问题系列:单词搜索、N皇后问题、判断有效数独、解数独
【经典LeetCode算法题目专栏分类】【第3期】回溯问题系列:单词搜索、N皇后问题、判断有效数独、解数独