算法分析与设计课程02——315. Count of Smaller Numbers After Self (Hard难度)

来源:互联网 发布:python 量化投资 书籍 编辑:程序博客网 时间:2024/05/02 22:34

一、题目描述(中文)

————————————原题链接
任意给一个数组如[5, 2, 6, 1],你需要找出数组中每个数的特征,并返回一个特征数组

特征:这个数后面比这个数小的数 的总和,如第一个数字5,在5后面比5还小的数有2,1**两个数**,所以返回数组第一位是2

所以上面样例数组返回为:[2, 1, 1, 0],见下面具体描述

Given nums = [5, 2, 6, 1]To the right of 5 there are 2 smaller elements (2 and 1).To the right of 2 there is only 1 smaller element (1).To the right of 6 there is 1 smaller element (1).To the right of 1 there is 0 smaller element.

二、题目分析

以上面样例进行分析[5, 2, 6, 1]
考虑对归并排序归并过程进行处理,归并排序递归树如下:
这里写图片描述

先定义一个结构封装数组,这个struct有:
1、数组值
2、索引值
3、计数器【用于储存比它小的数,可以用vector实现】

如图,对归并过程进行处理

在5和2归并时,让5成为左边数组L,让2成为右边数组R
进行归并,5>2,所以将2取出,这个时候将左边数组L的每个数的计数器放入1,然后将5取出,得到归并后数组[2, 5],5的计数器里有个2

同样6和1归并,归并后数组[1, 6],6的计数器里有个1

[2, 5] 和 [1, 6] 归并:
①首先取出右边数组R 中的1,将1放入2和5的计数器中
②取出左边数组L的2,不放入任何计数器
③取出左边数组L的5,不放入任何计数器
④取出右边数组R的6,准备放入左边数组L,但L已经没有数了(因为2和5都被取出来了),所以不能放入计数器中

最后归并结果[1, 2, 5, 6],计数器里数值为
1:计数器里没有值
2:1
5:2,1【首先放入2,再放入1】
6:1

根据上面封装的数据结构里的原始索引下标,对于数组[5, 2, 6, 1]
1–>4
2–>2
5–>1
6–>3

结合索引值和计数器里的数值,我们得到最终返回数组[2, 1, 1, 0]

三、源代码【这个代码能够独立运行,如果需要在题目链接下的网站测试,需要做些修改】

实现细节:

1、 封装数据结构不需要默认构造函数是因为,下面使用到的new操作符不会使用这个默认构造函数

2、在数据结构里重载“=”操作符的时候,需要将原来的计数器清空来接收新的计数器值【具体见源码】

#include <iostream>#include <vector>using namespace std;/*定义一个struct封装数组array这个struct有:1、数组值 2、下标索引 3、smaller_numbers的计数器【一个vector数组】 */ struct my_array{    int value;    int index;    vector<int> smaller_numbers;    my_array &operator = (const my_array& b)    {        value = b.value;        index = b.index;        int size = b.smaller_numbers.size();        smaller_numbers.clear();        for(int i = 0; i < size; i ++)            smaller_numbers.push_back(b.smaller_numbers[i]);        return *this;    }};vector<int> count_smaller_numbers(my_array* array, int n_size);void merge_sort(my_array* array, int start, int end);void merge(my_array* array, int start, int mid, int end);int main(){    //获取数组     int n_size = 0;    cin >> n_size;    my_array* array = new my_array[n_size];    for(int i = 0; i < n_size; i ++)    {        cin >> array[i].value;        array[i].index = i;    }    vector<int> result = count_smaller_numbers(array, n_size);    for(int i = 0; i < result.size(); i ++)        cout << result[i] << " ";    return 0;}vector<int> count_smaller_numbers(my_array* array, int n_size){    merge_sort(array, 0, n_size - 1);    //根据struct里的索引值和vector大小创建一个数组存储结果    vector<int> result = vector<int>(n_size, 0);//创建一个大小为 n_size 的 vector 并将其全初始化为 0    for(int i = 0; i < n_size; i ++)        result[array[i].index] = array[i].smaller_numbers.size();    return result;}void merge_sort(my_array* array, int start, int end){    if(start < end)    {        int mid = (start + end) / 2;        merge_sort(array, start, mid);        merge_sort(array, mid + 1, end);        merge(array, start, mid, end);    }}void merge(my_array* array, int start, int mid, int end){    /*将左边数组与右边数组归并,原则如下:     只有右边数组归并到结果数组中时,才使剩下的左边数组中的smaller_numbers计数     */    //将其分为左边数组和右边数组,并赋值     int left_size = mid - start + 1;    int right_size = end - mid;    my_array* left = new my_array[left_size];    my_array* right = new my_array[right_size];    for(int i = 0, k = start; k <= mid; k ++)        left[i ++] = array[k];    for(int i = 0, k = mid + 1; k <= end; k ++)        right[i ++] = array[k];    //进行归并    int left_count = 0;    int right_count = 0;     int a_count = start;//记录array数组的起始位置     while(left_count < left_size && right_count < right_size)    {        if(left[left_count].value > right[right_count].value)        {            array[a_count ++] = right[right_count];            int select = right[right_count].value;            for(int i = left_count; i < left_size; i ++)                left[i].smaller_numbers.push_back(select);            right_count ++;        }        else        {            array[a_count ++] = left[left_count ++];        }    }    while(left_count < left_size)        array[a_count ++] = left[left_count ++];    while(right_count < right_size)        array[a_count ++] = right[right_count ++];    delete [] left;    delete [] right; }
0 0
原创粉丝点击