java算法Leecode刷题统计有序矩阵中的负数

 更新时间:2022年10月08日 16:23:45   作者:可口可盐  
这篇文章主要为大家介绍了java算法Leecode刷题统计有序矩阵中的负数示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

leecode 1351. 统计有序矩阵中的负数

【Java 刷题打卡】

那就干吧! 这个专栏都是刷的题目都是关于二分法的,我会由浅入深、循序渐进,刷题就是这样需要连续不断的记忆--艾宾浩斯记忆法2121112。二分法的内容不多,但是都是每个程序员必备的

给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。 

请你统计并返回 grid 中 负数 的数目。

示例 1

输入:grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]
输出:8
解释:矩阵中共有 8 个负数。
示例 2:

输入:grid = [[3,2],[1,0]]
输出:0
示例 3:

输入:grid = [[1,-1],[-1,-1]]
输出:3
示例 4:

输入:grid = [[-1]]
输出:1

提示

m == grid.length
n == grid[i].length
1 <= m, n <= 100
-100 <= grid[i][j] <= 100

进阶:你可以设计一个时间复杂度为 O(n + m) 的解决方案吗?

Morris 遍历算法整体步骤如下(假设当前遍历到的节点为 x):

如果 x 无左孩子,则访问 x 的右孩子,即 x = x.right。

如果 x 有左孩子,则找到 x 左子树上最右的节点(即左子树中序遍历的最后一个节点,x 在中序遍历中的前驱节点),我们记为 predecessor(前任)。根据predecessor 的右孩子是否为空,进行如下操作。

  • 如果predecessor 的右孩子为空,则将其右孩子指向 x,然后访问 x 的左孩子,即 x = x.left。
  • 如果 predecessor 的右孩子不为空,则此时其右孩子指向 x,说明我们已经遍历完 x 的左子树,我们将 predecessor 的右孩子置空,然后访问 x 的右孩子,即 x = x.right。

重复上述操作,直至访问完整棵树。

其实整个过程我们就多做一步:将当前节点左子树中最右边的节点指向它,这样在左子树遍历完成后我们通过这个指向走回了 x,且能再通过这个知晓我们已经遍历完成了左子树,而不用再通过栈来维护,省去了栈的空间复杂度。

了解完这个算法以后,其他地方与方法二并无不同,我们同样也是维护一个 pred 变量去比较即可,具体实现可以看下面的代码,这里不再赘述。

参考代码

定义一颗树

class TreeNode {
    int val;          // 头结点
    TreeNode left;    // 左子树
    TreeNode right;   // 右子树
    TreeNode(int x) {
        val = x;
    }
}
// 测试方法
 public static void main(String[] args) {
        TreeNode treeNode = new TreeNode(1);
        treeNode.left = new TreeNode(2);
        treeNode.right = new TreeNode(3);
        System.out.println("xxxx结果 = " + preorderTraversal(treeNode));
}        

JAVA Morris

class Solution {
    public void recoverTree(TreeNode root) {
        TreeNode x = null, y = null, pred = null, predecessor = null;
        while (root != null) {
            if (root.left != null) {
                // predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
                predecessor = root.left;
                while (predecessor.right != null && predecessor.right != root) {
                    predecessor = predecessor.right;
                }
                // 让 predecessor 的右指针指向 root,继续遍历左子树
                if (predecessor.right == null) {
                    predecessor.right = root;
                    root = root.left;
                }
                // 说明左子树已经访问完了,我们需要断开链接
                else {
                    if (pred != null && root.val < pred.val) {
                        y = root;
                        if (x == null) {
                            x = pred;
                        }
                    }
                    pred = root;
                    predecessor.right = null;
                    root = root.right;
                }
            }
            // 如果没有左孩子,则直接访问右孩子
            else {
                if (pred != null && root.val < pred.val) {
                    y = root;
                    if (x == null) {
                        x = pred;
                    }
                }
                pred = root;
                root = root.right;
            }
        }
        swap(x, y);
    }
    public void swap(TreeNode x, TreeNode y) {
        int tmp = x.val;
        x.val = y.val;
        y.val = tmp;
    }
}

以上就是java算法Leecode刷题统计有序矩阵中的负数的详细内容,更多关于java算法统计有序矩阵负数的资料请关注脚本之家其它相关文章!

相关文章

  • java实现excel自定义样式与字段导出详细图文教程

    java实现excel自定义样式与字段导出详细图文教程

    最近接到一个需求,客户不满意原本导出的csv文件,想要导出Excel文件,下面这篇文章主要给大家介绍了关于java实现excel自定义样式与字段导出详细图文教程
    2023-09-09
  • SpringBoot登录验证码实现过程详解

    SpringBoot登录验证码实现过程详解

    这篇文章主要介绍了SpringBoot登录验证码实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • java中金额元转万元工具类的实例

    java中金额元转万元工具类的实例

    这篇文章主要介绍了java中金额元转万元工具类的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • C++ 归并排序(merge sort)案例详解

    C++ 归并排序(merge sort)案例详解

    这篇文章主要介绍了C++ 归并排序(merge sort)案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • IDEA使用MyBatisCodeHelperPro来generator代码的详细教程

    IDEA使用MyBatisCodeHelperPro来generator代码的详细教程

    这篇文章主要介绍了IDEA使用MyBatisCodeHelperPro来generator代码的详细教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • MyBatis-plus实现逆向生成器

    MyBatis-plus实现逆向生成器

    本文主要介绍了MyBatis-plus实现逆向生成器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • 解决grails服务端口冲突的办法(grails修改端口号)

    解决grails服务端口冲突的办法(grails修改端口号)

    grails中默认的服务端口为8080,当本机中需要同时启动两个不同的项目时,就会造成端口冲突,下面给出解决方法
    2013-12-12
  • SpringBoot如何处理@KafkaListener消息

    SpringBoot如何处理@KafkaListener消息

    Spring通过KafkaMessageListenerContainer、ConcurrentMessageListenerContainer等组件实现Kafka消息的监听和处理,并通过@KafkaListener注解将业务逻辑与Kafka消费者连接起来,Spring Boot自动配置Kafka相关组件,简化了Kafka的使用
    2024-12-12
  • SpringCloud如何搭建一个多模块项目

    SpringCloud如何搭建一个多模块项目

    这篇文章主要介绍了SpringCloud如何搭建一个多模块项目,记录下使用SpringCloud创建多模块项目,一步一步记录搭建的过程,感兴趣的可以了解一下
    2021-05-05
  • jfinal添加jcaptcha验证码实现方法

    jfinal添加jcaptcha验证码实现方法

    这篇文章主要介绍了jfinal的jcaptcha验证码实现方法,大家参考使用吧
    2014-01-01

最新评论