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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

LeetCode 315. 计算右侧小于当前元素的个数(二叉查找树二分查找归并排序逆序数总结)

發布時間:2024/7/5 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LeetCode 315. 计算右侧小于当前元素的个数(二叉查找树二分查找归并排序逆序数总结) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 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 個更小的元素 (21). 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);//創建的新節點cur更新至調用處的參數return 0;//自己等于自己,不用加,返回0}else{if(n > cur->val)//我比當前大,+1,還要 +之前記錄的比它小的個數,+它右側的return 1 + cur->count + insert(n,cur->right);if(n < cur->val){ //我比當前小cur->count++; //比當前小的記錄 +1return insert(n,cur->left);//去左邊子樹里查找}else// ==,+比當前小的個數,+右側里面的return 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]);//可能導致vector數據搬移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;//自己在紙上測試下,只能是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);//or ans[idx[i]] += r-mid;temp[k++] = idx[i++];}while(j <= r){temp[k++] = idx[j++];}for(i = l; i <= r; ++i)idx[i] = temp[i];} };

總結

以上是生活随笔為你收集整理的LeetCode 315. 计算右侧小于当前元素的个数(二叉查找树二分查找归并排序逆序数总结)的全部內容,希望文章能夠幫你解決所遇到的問題。

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