題目細節描述參看leetcode。java
今天的重頭戲 LC315 Count of Smaller Numbers After Self.
在講這個題目以前,請思考這個問題。在BST找到全部比Node P小的節點個數。
利用inorder tarvseral咱們一直走BST並計數,找到p點就返回計數獲得的值。時間複雜度worst case O(n).若是咱們要找到的是好多節點的值,若是還用這種方法,時間複雜度就是O(k*n).
這裏咱們有大量重複的工做,每次都從leftmost走,直到找到這個node Pi. 實際上咱們能夠預處理這個BST。把每一個節點小於它的個數記錄下來。綜合的時間複雜度就是O(n+klogn).node
要快速找到比本身小的數,就能夠創建一個BST來幫助咱們。
咱們創建的Node(int val, int dup, int leftsum,Node left, Node right) 其中dup解決重複值的問題,leftsum記錄左子樹的節點數。
給一個[3,2,2,6,1],構建出的樹長這樣,其中Node.val(dup, leftsum)表示每一個節點。ui
1(1,0) \ 6(1,3) / 2(2,0) \ 3(1,0)
創建的細節待會兒再講。
假如咱們的輸入變爲[5,3,2,2,6,1]要找比5小的怎麼辦?
首先1比5小,total = 1+0. 走到6發現比5大,去到2,發現5比2大,total += 2 +0。去到3,發現5比3大,total += 1+0, 最後total = 4.
假如咱們的輸入變爲[7,3,2,2,6,1]要找比5小的怎麼辦?
首先1比7小,total = 1+0. 走到6發現比7發,total += 1+3, total = 5。code
給定要找的點P,這裏的規律就是,往右下走,說明當前點和當前的的左子樹的值所有比P.val小。咱們計數。
往左下走,咱們不知道下面節點是否比p小,須要再重複上面的判斷。直到找到全部比p小的節點數。leetcode
給定一個這樣咱們自定義的BST,咱們直到如何找到。下面就是如何構造了。
仍是上面那個圖。咱們加入5這個點,在走到6的時候,是走到6的左子樹,這是6的左子樹應該+1,變成:get
1(1,0) \ 6(1,4) / 2(2,0) \ 3(1,0) \ 5(1,0)
這是加入左子樹的狀況,如今再繼續加入7這個點。咱們走到6要向右,這是左子樹沒變化,6這裏也不變。
和上面的例子稍有不一樣,咱們連續加入了5,7這兩個點。io
1(1,0) \ 6(1,4) / \ 2(2,0) 7(1,0) \ 3(1,0) \ 5(1,0)
咱們能夠試着返回小於7的節點數,也就是每次向右走的時候,node上的值求和。total = 1+0 + 1+4 = 6。class
代碼以下。List
public class Solution { class Node { Node left, right; int val, sum, dup = 1; public Node(int v) { val = v; } } public List<Integer> countSmaller(int[] nums) { Integer[] ans = new Integer[nums.length]; Node root = null; for (int i = nums.length - 1; i >= 0; i--) { root = insert(nums[i], root, ans, i, 0); } return Arrays.asList(ans); } private Node insert(int num, Node node, Integer[] ans, int i, int preSum) { if (node == null) { node = new Node(num); ans[i] = preSum; } else if (node.val == num) { node.dup++; ans[i] = preSum + node.sum; } else if (node.val > num) { node.sum++; node.left = insert(num, node.left, ans, i, preSum); } else { node.right = insert(num, node.right, ans, i, preSum + node.dup + node.sum); } return node; } }
代碼來源: leetcode mayanist
https://discuss.leetcode.com/...方法