日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

求栈中元素个数算法_每日算法系列【LeetCode 315】计算右侧小于当前元素的个数...

發布時間:2025/3/20 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 求栈中元素个数算法_每日算法系列【LeetCode 315】计算右侧小于当前元素的个数... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

給定一個整數數組 nums ,按要求返回一個新數組 counts 。數組 counts 有該性質: counts[i] 的值是 nums[i] 右側小于 nums[i] 的元素的數量。

示例1

輸入: [5,2,6,1] 輸出: [2,1,1,0] 解釋: 5 的右側有 2 個更小的元素 2 和 1 。 2 的右側僅有 1 個更小的元素 1 。 6 的右側有 1 個更小的元素 1 。 1 的右側有 0 個更小的元素。

題解

這題沒有給數據范圍,但是用腳想也知道不能暴力做(

)。

這題其實有多種解法,這里簡單介紹三種解法。

樹狀數組

如果你不熟悉這個數據結構的話,你只需要記住它的功能就行。

樹狀數組是一個數組,有兩種操作。 一個是對某個位置的元素加值或減值,一個是查詢第一個位置到某個位置的元素之和。 暴力的話每次查詢操作復雜度都是

,而樹狀數組可以做到 。

具體細節不介紹了,有現成的模板,會用就行了。

有了這等好東西,就可以把問題這么轉化了: 新建一個數組 bit ,其中 bit[i] 表示i這個數出現的次數。 從右邊最后一個數開始向左遍歷,每遇到一個數 nums[i] ,就把 bit[nums[i]] 加 1 ,表示這個數多了一個。 然后查詢 bit[0] 到 bit[nums[i]-1] 中的所有次數之和,就表明了當前時刻有多少數比 nums[i] 小。 這一步查詢操作正好用到樹狀數組,最后總的時間復雜度為

歸并排序

歸并排序算法想必大家應該很熟悉了。 就是將數組劃分為左右兩個長度相等的子數組,然后分別遞歸排序,得到左右兩個有序的子數組。 然后就是合并了,只要用兩個頭指針,分別指著兩個子數組的開頭,然后分別向右移動合并就行了。

那么在這題中怎么用呢? 假設左右兩個子數組為 a[l], ..., a[m] 和 a[m+1], ..., a[r] ,頭指針分別為 i = l 和 j = m + 1 。 然后開始合并,首先 j 向右移動,直到 a[j] >= a[i] ,也就是在右半部分子數組中找到所有小于 a[i] 的數。 然后把這些數依次放入臨時數組中,并得到結論:右半部分子數組中比 a[i] 小的數有 j - m - 1 個。 然后把 a[i] 也推進臨時數組里,重復進行上述過程,直到 i > m 。 最后如果右半部分數組還剩一些數,說明它們是最大的,推入臨時數組就行了,最后把臨時數組里的數復制進原數組,這部分就排好序了。

要注意的是排序后原來的下標會丟失,所以用一個 pair 類型保存每一個數和它原來的下標。

二叉搜索樹

這種方法也很顯然。 從最右邊一個數開始構建二叉搜索樹,結點保存這個數和右邊比它小的數的數量。 如果新插入一個數,就插入到二叉搜索樹中,沿途記得要更新經過的每個結點的數量。 如果經過一個結點,并且插入的數比結點的數小,那么就在左子樹中繼續尋找插入位置,并且結點數量加 1 。 如果插入的數比結點的數大,那么就在右子樹中尋找,并且插入的數對應的答案加上該結點的數量。

具體這里就不實現了,主要考察的是數據結構,不想寫了。。。

代碼

樹狀數組

class Solution { public:static const int MAXN = 100000;int bit[MAXN], x[MAXN], y[MAXN];vector<int> countSmaller(vector<int>& nums) {int n = nums.size();for (int i = 0; i < n; ++i) {x[i] = y[i] = nums[i];}sort(y, y + n);int len = unique(y, y + n) - y;for (int i = 0; i < n; ++i) {x[i] = lower_bound(y, y + len, x[i]) - y + 1;}memset(bit, 0, sizeof bit);vector<int> res;for (int i = n-1; i >= 0; --i) {res.push_back(sum(x[i]-1));add(x[i], 1);}reverse(res.begin(), res.end());return res;}int lowbit(int x) {return x&(-x);}void add(int i, int x) {while (i < MAXN) {bit[i] += x;i += lowbit(i);}}void sub(int i, int x) {while (i < MAXN) {bit[i] -= x;i += lowbit(i);}}int sum(int i) {int s = 0;while (i > 0) {s += bit[i];i -= lowbit(i);}return s;} };

歸并排序

class Solution { public:static const int MAXN = 100000;int cnt[MAXN];pair<int, int> x[MAXN], y[MAXN];vector<int> countSmaller(vector<int>& nums) {int n = nums.size();for (int i = 0; i < n; ++i) {x[i] = make_pair(nums[i], i);}memset(cnt, 0, sizeof cnt);merge_sort(0, n-1);vector<int> res(cnt, cnt+n);return res;}void merge_sort(int l, int r) {if (l >= r) return;int m = (l + r) >> 1;merge_sort(l, m);merge_sort(m+1, r);int idl = l, idr = m + 1, idx = l;while (idl <= m) {while (idr <= r && x[idr].first < x[idl].first) {y[idx++] = x[idr];idr++;}cnt[x[idl].second] += idr - m - 1;y[idx++] = x[idl];idl++;}for (int i = l; i < idr; ++i) {x[i] = y[i];}} };

總結

以上是生活随笔為你收集整理的求栈中元素个数算法_每日算法系列【LeetCode 315】计算右侧小于当前元素的个数...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。