归并|线段树|树状数组

lc315

树状数组应该是最优

暴力的二分..

class Solution {

public:

vector<int> countSmaller(vector<int>& nums) {

vector<int>t,res(nums.size());

/*初始化t,res*/

for(int i=nums.size()-1;i>=0;i--){

int left=0,right=t.size();

/*下面是一个在t数组里二分查找的过程*/

while (left<right){

int mid=left+(right-left)/2;

if(t[mid]>=nums[i]){

right= mid;

}

else{

left=mid+1;

}

}

res[i]=right;

t.insert(t.begin()+right,nums[i]);

}

return res;

}

};

归并

class Solution

{

public:

vector<pair<int, int>> a, b;

vector<int> res;

vector<int> countSmaller(vector<int> &nums)

{

int n = nums.size();

for (int i = 0; i < n; ++i)

a.push_back({nums[i], i});

b.resize(n);

res.resize(n);

dfs(0, n - 1);

return res;

}

void dfs(int l, int r)

{

if (l == r)

return;

int mid = (l + r) >> 1;

// 归并是后序遍历的统计模式 所以我们先递归 再合并。

dfs(l, mid);

dfs(mid + 1, r);

for (int i = l; i <= r; ++i)

b[i] = a[i];

int i = l, j = mid + 1, k = l;

while (i <= mid || j <= r)

{

if (i > mid)

a[k++] = b[j++];

else if (j > r)

a[k++] = b[i++];

else if (b[i].first <= b[j].first)

a[k++] = b[j++];//逆序合并

else

{

res[b[i].second] += r - j + 1;

a[k++] = b[i++];

}

}

}

};

树状数组

const int MAXN = 100007;

int cnt[MAXN],n;

/*数组cnt[i]用于记录出现元素nums[i]的个数*/

class Solution {

public:

inline void add(int k)

{

for(; k <= n; k += -k&k) cnt[k] += 1;

}

int sum(int k)

{

int res = 0;

for(; k; k -= -k&k) res += cnt[k];

return res;

}

vector<int> countSmaller(vector<int>& nums) {

n = nums.size();

vector<int> ans(n);

vector<pair<int, int>> A;

/*建立一个从数组内容到未排序前索引的映射A*/

for(int i = 0; i < n; i ++) {

A.push_back({nums[i], i+1});

}

memset(cnt, 0, sizeof(cnt));

sort(A.begin(), A.end());

/*进行排序*/

for(int i = 0; i < n; i ++) {

int id = A[i].second;

int t = sum(n) - sum(id);

ans[id-1] = t;

add(id);

}

return ans;

}

};

二叉搜索树

struct BSTNode{

int val;

int count;

BSTNode *left;

BSTNode *right;

BSTNode(int x)

: val(x)

, left(NULL)

, right(NULL)

, count(0)

{}

};

/*建立一个二分查找树,每个树结点有四个值,分别是:

int val;这个结点代表的值val

int count;这个val代表的次数也就是在nums数组种比val小的数的个数

left 左子树指针

right 右子树指针

一个构造函数,构造函数如上定义

*/

void BST_insert(BSTNode *node,BSTNode *insert_node,int &count_small)

{

if(node->val >= insert_node->val)

{

/*插入的结点更小,被比较结点(即node)的count++,然后插入到左子树(如果不为空)*/

node->count++;

if(node->left)

{

BST_insert(node->left,insert_node,count_small);

}

else

{

/*左子树为空,插入结点就作为当前结点的左孩子*/

node->left = insert_node;

}

}

else{

/*插入的结点更大,需要在右子树(如果不为空)继续找*/

count_small += node->count + 1;

if(node->right)

{

BST_insert(node->right,insert_node,count_small);

}

else

{

/*当前右子树为空,插入结点作为当前结点右孩子*/

node->right = insert_node;

}

}

}

/*count_small作为一个引用的参数,在递归寻找子树的时候作为一个"类似全局变量"的存在*/

class Solution {

public:

vector<int> countSmaller(vector<int>& nums) {

int n=nums.size();

/*如果数组为空返回空值*/

if(n==0)return {};

vector<int> count;

count.push_back(0);

/*建立一个二叉搜素树*/

BSTNode* node=new BSTNode(nums[n-1]);

int count_small;

for(int i = 1;i < n;i++)

{

count_small = 0;

BST_insert(node,new BSTNode(nums[n-i-1]),count_small);

count.push_back(count_small);

}

/*最后不要忘记删除树节点*/

delete node;

reverse(count.begin(),count.end());

/*push_back的时候是逆序的,此时只要将count数组reverse即可*/

return count;

}

};

相关推荐
xlq223224 小时前
10.string(上)
开发语言·c++
hashiqimiya4 小时前
c++的头文件使用
开发语言·c++·算法
panamera124 小时前
C++中vector
开发语言·c++
拳里剑气4 小时前
C++:string的使用
开发语言·c++·学习方法
Larry_Yanan4 小时前
QML学习笔记(四十八)QML与C++交互:QML中可实例化C++对象
c++·笔记·qt·学习·ui·交互
2301_803554525 小时前
c++调用客户端库与kafka交互
c++·kafka·交互
小年糕是糕手5 小时前
【C/C++刷题集】二叉树算法题(一)
c语言·数据结构·c++·算法·leetcode·学习方法·改行学it
m0_748240259 小时前
Windows编程+使用C++编写EXE加壳程序
开发语言·c++·windows
LoveXming11 小时前
Chapter14—中介者模式
c++·microsoft·设计模式·中介者模式·开闭原则