java算法Leecode刷題統(tǒng)計(jì)有序矩陣中的負(fù)數(shù)
leecode 1351. 統(tǒng)計(jì)有序矩陣中的負(fù)數(shù)
【Java 刷題打卡】
那就干吧! 這個(gè)專(zhuān)欄都是刷的題目都是關(guān)于二分法的,我會(huì)由淺入深、循序漸進(jìn),刷題就是這樣需要連續(xù)不斷的記憶--艾賓浩斯記憶法2121112。二分法的內(nèi)容不多,但是都是每個(gè)程序員必備的
給你一個(gè) m * n 的矩陣 grid,矩陣中的元素?zé)o論是按行還是按列,都以非遞增順序排列。
請(qǐng)你統(tǒng)計(jì)并返回 grid 中 負(fù)數(shù) 的數(shù)目。
示例 1
輸入:grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]
輸出:8
解釋?zhuān)壕仃囍泄灿?8 個(gè)負(fù)數(shù)。
示例 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
進(jìn)階:你可以設(shè)計(jì)一個(gè)時(shí)間復(fù)雜度為 O(n + m) 的解決方案嗎?
Morris 遍歷算法整體步驟如下(假設(shè)當(dāng)前遍歷到的節(jié)點(diǎn)為 x):
如果 x 無(wú)左孩子,則訪問(wèn) x 的右孩子,即 x = x.right。
如果 x 有左孩子,則找到 x 左子樹(shù)上最右的節(jié)點(diǎn)(即左子樹(shù)中序遍歷的最后一個(gè)節(jié)點(diǎn),x 在中序遍歷中的前驅(qū)節(jié)點(diǎn)),我們記為 predecessor(前任)。根據(jù)predecessor 的右孩子是否為空,進(jìn)行如下操作。
- 如果predecessor 的右孩子為空,則將其右孩子指向 x,然后訪問(wèn) x 的左孩子,即 x = x.left。
- 如果 predecessor 的右孩子不為空,則此時(shí)其右孩子指向 x,說(shuō)明我們已經(jīng)遍歷完 x 的左子樹(shù),我們將 predecessor 的右孩子置空,然后訪問(wèn) x 的右孩子,即 x = x.right。
重復(fù)上述操作,直至訪問(wèn)完整棵樹(shù)。
其實(shí)整個(gè)過(guò)程我們就多做一步:將當(dāng)前節(jié)點(diǎn)左子樹(shù)中最右邊的節(jié)點(diǎn)指向它,這樣在左子樹(shù)遍歷完成后我們通過(guò)這個(gè)指向走回了 x,且能再通過(guò)這個(gè)知曉我們已經(jīng)遍歷完成了左子樹(shù),而不用再通過(guò)棧來(lái)維護(hù),省去了棧的空間復(fù)雜度。
了解完這個(gè)算法以后,其他地方與方法二并無(wú)不同,我們同樣也是維護(hù)一個(gè) pred 變量去比較即可,具體實(shí)現(xiàn)可以看下面的代碼,這里不再贅述。
參考代碼
定義一顆樹(shù)
class TreeNode { int val; // 頭結(jié)點(diǎn) TreeNode left; // 左子樹(shù) TreeNode right; // 右子樹(shù) TreeNode(int x) { val = x; } } // 測(cè)試方法 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結(jié)果 = " + 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 節(jié)點(diǎn)就是當(dāng)前 root 節(jié)點(diǎn)向左走一步,然后一直向右走至無(wú)法走為止 predecessor = root.left; while (predecessor.right != null && predecessor.right != root) { predecessor = predecessor.right; } // 讓 predecessor 的右指針指向 root,繼續(xù)遍歷左子樹(shù) if (predecessor.right == null) { predecessor.right = root; root = root.left; } // 說(shuō)明左子樹(shù)已經(jīng)訪問(wèn)完了,我們需要斷開(kāi)鏈接 else { if (pred != null && root.val < pred.val) { y = root; if (x == null) { x = pred; } } pred = root; predecessor.right = null; root = root.right; } } // 如果沒(méi)有左孩子,則直接訪問(wèn)右孩子 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刷題統(tǒng)計(jì)有序矩陣中的負(fù)數(shù)的詳細(xì)內(nèi)容,更多關(guān)于java算法統(tǒng)計(jì)有序矩陣負(fù)數(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java循環(huán)練習(xí)的簡(jiǎn)單代碼實(shí)例
本篇文章介紹了,java中循環(huán)練習(xí)的一些簡(jiǎn)單代碼實(shí)例。需要的朋友參考下2013-04-04詳解JavaEE 使用 Redis 數(shù)據(jù)庫(kù)進(jìn)行內(nèi)容緩存和高訪問(wèn)負(fù)載
本篇文章主要介紹了JavaEE 使用 Redis 數(shù)據(jù)庫(kù)進(jìn)行內(nèi)容緩存和高訪問(wèn)負(fù)載,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08解決MyBatis中為類(lèi)配置別名,列名與屬性名不對(duì)應(yīng)的問(wèn)題
這篇文章主要介紹了解決MyBatis中為類(lèi)配置別名,列名與屬性名不對(duì)應(yīng)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11