文章目錄
- 1. 題目
- 2. 解題
- 2.1 二叉查找樹
- 2.2 二分插入
- 2.3 歸并排序
1. 題目
給定一個整數數組 nums,按要求返回一個新數組 counts。數組 counts 有該性質: counts[i] 的值是 nums[i] 右側小于 nums[i] 的元素的數量。
示例
:
輸入
: [5,2,6,1]
輸出
: [2,1,1,0]
解釋
:
5 的右側有
2 個更小的元素
(2 和
1).
2 的右側僅有
1 個更小的元素
(1).
6 的右側有
1 個更小的元素
(1).
1 的右側有
0 個更小的元素
.
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self
著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。
2. 解題
2.1 二叉查找樹
我的博客 二叉查找樹
- 每個節點增加一個數據count(記錄比這個節點小的元素個數)
- 如果新加入的節點小于當前節點cur,cur->count++
- 從根節點root向下查找,滿足條件則累加count值&&路過的比自己小的元素個數
- 特別注意,將原數組逆向(從右向左)插入BST(題目要求找的是右邊比我小的)
- 時間復雜度O(nlgn)
- 最壞情況下,BST退化成鏈表,時間復雜度變成O(n2)
class Node
{
public:int val
;int count
;Node
*left
, *right
;Node(int v
): val(v
), count(0), left(NULL), right(NULL){}
};
class BST
{Node
*root
;
public:BST():root(NULL){}int insert(int n
){return insert(n
, root
);}
private:int insert(int n
, Node
* &cur
){if(!cur
){cur
= new Node(n
);return 0;}else{if(n
> cur
->val
)return 1 + cur
->count
+ insert(n
,cur
->right
);if(n
< cur
->val
){ cur
->count
++; return insert(n
,cur
->left
);}elsereturn cur
->count
+ insert(n
,cur
->right
);}}
};
class Solution {
public:vector
<int> countSmaller(vector
<int>& nums
) {vector
<int> ans(nums
.size());BST tree
;for(int i
= nums
.size()-1; i
>= 0; --i
)ans
[i
] = tree
.insert(nums
[i
]);return ans
;}
};
2.2 二分插入
- 開辟一個空的數組,用于存放已排序的數據
- 將原數組,從右向左,二分插入至新數組,記錄插入的位置(前面有多少小于我的)
class Solution {
public:vector
<int> countSmaller(vector
<int>& nums
) {if(nums
.empty())return {};vector
<int> ans
, sorted
;int pos
;vector
<int>::iterator it
;for(int i
= nums
.size()-1; i
>= 0; --i
){pos
= binaryInsert(sorted
,nums
[i
]);it
= sorted
.begin()+pos
;sorted
.insert(it
,nums
[i
]);ans
.push_back(pos
);}reverse(ans
.begin(),ans
.end());return ans
;}int binaryInsert(vector
<int>& sorted
, int num
){int left
= 0, right
= sorted
.size()-1, mid
;while(left
<= right
){mid
= left
+((right
-left
)>>1);if(sorted
[mid
] < num
)left
= mid
+1;else if(sorted
[mid
] >= num
)right
= mid
-1;}return left
;}
};
- 時間復雜度也是O(nlgn)
- 以下結果時間偏長,可能是在vector中間插入數據導致的數據搬移,消耗了時間
2.3 歸并排序
參考分治,歸并求逆序度
借一張圖理解一下
- 需要歸并求解,但是歸并排序過程中,數據下標變動了,需要建立一個下標數組
- 對下標數組idx進行排序(比較大小的時候用nums數組代入比較)
- 計算逆序數方法(只能取一種,不要同時用)
- 1、當前序數組寫入時,計算后序中已經出列的個數(它們均小于剛寫入的),j-(mid+1),有后續操作(前序沒寫完時,繼續累加)
- 2、當后序數組寫入時,計算前序中還有多少沒有出隊(它們均大于剛寫入的),mid-i+1,無后序操作(因為,前序出隊完畢,剩余0,或者,后序寫入完畢)
再借兩張圖總結下
class Solution {vector
<int> ans
;vector
<int> temp
;vector
<int> idx
;
public:vector
<int> countSmaller(vector
<int>& nums
) {if(nums
.empty())return {};ans
.resize(nums
.size());temp
.resize(nums
.size());idx
.resize(nums
.size());for(int i
= 0; i
< nums
.size(); ++i
){idx
[i
] = i
;ans
[i
] = 0;}mergeSort(nums
,0,nums
.size()-1);return ans
;}void mergeSort(vector
<int> &nums
, int l
, int r
){if(l
== r
)return;int mid
= l
+((r
-l
)>>1);mergeSort(nums
,l
,mid
);mergeSort(nums
,mid
+1,r
);merge(nums
,l
,mid
,r
);}void merge(vector
<int>& nums
, int l
, int mid
, int r
){int i
= l
, j
= mid
+1, k
= l
;while(i
<= mid
&& j
<= r
){if(nums
[idx
[i
]] <= nums
[idx
[j
]]){ans
[idx
[i
]] += j
-(mid
+1);temp
[k
++] = idx
[i
++];}else{temp
[k
++] = idx
[j
++];}}while(i
<= mid
){ans
[idx
[i
]] += j
-(mid
+1);temp
[k
++] = idx
[i
++];}while(j
<= r
){temp
[k
++] = idx
[j
++];}for(i
= l
; i
<= r
; ++i
)idx
[i
] = temp
[i
];}
};
總結
以上是生活随笔為你收集整理的LeetCode 315. 计算右侧小于当前元素的个数(二叉查找树二分查找归并排序逆序数总结)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。