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

目录
  • leecode 1351. 统计有序矩阵中的负数
    • 示例 1
    • 提示
  • 参考代码
    • 定义一颗树
    • JAVA Morris

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算法统计有序矩阵负数的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java C++算法题解leetcode1592重新排列单词间的空格

    目录 题目要求 思路:模拟 Java C++ Rust 题目要求 思路:模拟 模拟就完了 统计空格数量和单词数量,计算单词间应有的空格数,将它们依次放入结果字符串,若有余数则在末尾进行填补. Java class Solution { public String reorderSpaces(String text) { int n = text.length(), spcnt = 0; List<String> words = new ArrayList<>(); for (int

  • Java 数据结构算法Collection接口迭代器示例详解

    目录 Java合集框架 Collection接口 迭代器 Java合集框架 数据结构是以某种形式将数据组织在一起的合集(collection).数据结构不仅存储数据,还支持访问和处理数据的操作 在面向对象的思想里,一种数据结构也被认为是一个容器(container)或者容器对象(container object),它是一个能存储其他对象的对象,这里的其他对象常被称为数据或者元素 定义一种数据结构从实质上讲就是定义一个类.数据结构类应该使用数据域存储数据,并提供方法支持查找.插入和删除等操作 Ja

  • java实现的统计字符算法示例

    本文实例讲述了java实现的统计字符算法.分享给大家供大家参考,具体如下: 统计字符: 概述:给定字符串,将它们进行分类,分别的去统计它们的个数及其字符 分类的有:字母 数字 中文 空格 等等 算法思路分析: 分别统计即可: 下面给出代码:(代码仅供参考) package javastudy; public class Testit6 { public static void main(String[] args) { String str = "...天2气 :[1] aA"; //

  • Java C++ 算法leetcode828统计子串中唯一字符乘法原理

    目录 题目要求 思路:模拟 java C++ Rust 题目要求 思路:模拟 解题的核心思想在于逆向思维,不考虑每个子数组中的唯一字符个数,转而考虑每个字符可以作为多少个子数组的唯一字符: 所以在计算答案时的算式和示例中给出的是不一样的: 在计算每个字符“贡献”[即当前向左向右分别可组成的答案个数]的时候要用到乘法原理. 对每一个字符s[i]s[i]s[i]都记录其左边和右边的第一个相同字符位置,分别记为l[i]l[i]l[i]和r[i]r[i]r[i],这两个位置中间构成的就是s[i]s[i]

  • Java C++ 算法题解leetcode669修剪二叉搜索树示例

    目录 题目要求 思路一:模拟迭代 Java C++ 思路二:递归 Java C++ Rust 题目要求 思路一:模拟迭代 依次判断每个节点是否合法: 首先找出结果的根,若原根小了就拉右边的过来,大了拉左边的过来做新根: 然后分别判断左右子树的大小,由于二叉搜索树的性质,子树只需要判断一边就好: 左子树判断是否>low,合法就向左下走,不合法往右下: 右子树判断是否<high,合法就向右下走,不合法往左下. Java class Solution { public TreeNode trimBS

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

    目录 leecode 1351. 统计有序矩阵中的负数 示例 1 提示 参考代码 定义一颗树 JAVA Morris leecode 1351. 统计有序矩阵中的负数 [Java 刷题打卡] 那就干吧! 这个专栏都是刷的题目都是关于二分法的,我会由浅入深.循序渐进,刷题就是这样需要连续不断的记忆--艾宾浩斯记忆法2121112.二分法的内容不多,但是都是每个程序员必备的 给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列. 请你统计并返回 grid 中 负

  • 如何在Intellij中安装LeetCode刷题插件方便Java刷题

    一.安装 在 IDEA(2019)的 setting 的 Plugins 的 Marketplace 中搜索 leetcode,即可以找到该插件,安装完成了,重启即可. 二.配置 1.重启完成后,第一次使用的时候,需要一些基本的配制,在 setting 中的 Tools 中可以找到该插件工具,为 leetcode plugin,在里面,可以选择访问的为国际的 LeetCode 还是国内的,以及何种语言,同时,输入自己账户名(LoginName)和密码(Password),则可以和自己帐号关联起来

  • 谷歌师兄的算法刷题笔记

    对于刷题相关的文章,在之前我也推荐过不少,今天在给大家推荐一份谷歌师兄的算法刷题笔记,这份笔记与以往的刷题有所区别,作者把 Leetcode 一千多道题都进行了系统的整理,并且对于每一道题的代码,都要求 beat 100%. 作者把所有题型分成了 13 个类别,截个图给大家看一下 无论是为了面试,为了打比赛还是入门学习一些算法,我还是挺建议前期按照各类题型逐个击破,这份刷题笔记,或许可以给大家带来一些帮忙. 我简单看了一下每一个道题的解答,每个题并没有给出多种答案,基本都是直接给出最优解,代码写

  • java算法入门之有效的括号删除有序数组中的重复项实现strStr

    目录 1.LeetCode 20.有效的括号 题目 小编菜解 思路及算法 大神解法 2.LeetCode 26.删除有序数组中的重复项 题目 小编菜解初版 小编菜解改进版 思路及算法 大神解法 3.LeetCode 28.实现strStr 题目 小编菜解 大神解法 也许,我们永远都不会知道自己能走到何方,遇见何人,最后会变成什么样的人,但一定要记住,能让自己登高的,永远不是别人的肩膀,而是挑灯夜战的自己,人生的道路刚刚启程,当你累了倦了也不要迷茫,回头看一看,你早已不再是那个年少轻狂的少年. 1

  • 剑指Offer之Java算法习题精讲数组与字符串题

    题目一 解法 class Solution { public int thirdMax(int[] nums) { Arrays.sort(nums); if(nums.length<3){ return nums[nums.length-1]; } int p = 1; for(int i =nums.length-2;i>=0;i--){ if(nums[i]==nums[i+1]){ }else{ ++p; if(p==3){ return nums[i]; } } } return n

  • Java C++刷题leetcode1106解析布尔表达式

    目录 题目 思路:栈[计算器] Java C++ Rust 总结 题目 题目要求 思路:栈[计算器] 和计算器原理类似,分别用两个栈存操作数和操作符,然后到)就开始运算前面的内容,括号里运算都相同所以还是比较简单的. 要注意字母t.f和布尔值true.false的转换. Java class Solution { public boolean parseBoolExpr(String expression) { Deque<Character> tfs = new ArrayDeque<

  • Java算法设计与分析分治算法

    目录 一.前言 二.分治算法介绍 三.分治算法经典问题 3.1.二分搜索 3.2.快速排序 3.3.归并排序(逆序数) 3.4.最大子序列和 3.5.最近点对 四.结语 一.前言 在学习分治算法之前,问你一个问题,相信大家小时候都有存钱罐的经历,父母亲人如果给钱都会往自己的宝藏中存钱,我们每隔一段时间都会清点清点钱.但是一堆钱让你处理起来你可能觉得很复杂,因为数据相对于大脑有点庞大了,并且很容易算错,你可能会将它先分成几个小份算,然后再叠加起来计算总和就获得这堆钱的总数了 当然如果你觉得各个部分

  • java 算法之归并排序详解及实现代码

    java 算法之归并排序详解 一.思想 归并排序:将一个数组排序,可以先(递归地)将它分成两半部份分别排序,然后将结果归并起来: 二.概念 归并:将两个有序的数组归并成一个更大的有序数组: 三.特点 优点:能够保证将任意长度为N的数组排序所需要的时间和NlogN成正比: 缺点:需要额外的空间和N成正比: 四.实现方法 将两个不同的有序数组归并到第三个数组中: 先将前半部分排序,在将后半部分排序,然后在数组中移动元素而不需要使用额外的空间: 五.代码 /** * 归并排序 * * @author

  • java算法之二分查找法的实例详解

    java算法之二分查找法的实例详解 原理 假定查找范围为一个有序数组(如升序排列),要从中查找某一元素,如果该元素在此数组中,则返回其索引,否则返回-1.通过数组长度可取出中间位置元素的索引,将其值与目标值比较,如果中间位置元素值大于目标值,则在左部分进行查找,如果中间位置值小于目标值,则在右部分进行查找,如此循环,直到结束.二分查找算法之所以快是因为它没有遍历数组的每个元素,而仅仅是查找部分元素就能找到目标或确定其不存在,当然前提是查找范围为有序数组. Java的简单实现 package me

  • java 算法之希尔排序详解及实现代码

    java 算法之希尔排序 一.思想 希尔排序:使数组中任意间隔为h的元素都是有序的.在进行排序的时候,如果h很大,我们就能将元素移动到很远的地方,为实现更小的h有序创造方便.用这种方式,对任意以1结尾的h序列,我们都能够将数据排序: 二.概念 h有序数组:任意间隔为h的元素都是有序的数组: 三.高效原因 对于大规模乱序数组插入排序很慢,因为它只会交换相邻的元素,因此元素只能一点一点地从数组的一端移动到另一段:   希尔排序更高效的原因:它权衡了子数组的规模和有序性,在排序之初,各个子数组都很短:

随机推荐