赞
踩
给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质:counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。示例: 输入: [5,2,6,1] 输出: [2,1,1,0]
力扣(LeetCode)第315题
将两个有序的数组合并成一个有序数组称为归并。归并排序包含了两个过程:
①:从上往下的分解:把当前区间一分为二,直至分解为若干个长度为1的子数组
②:从下往上的合并:两个有序的子区域两两向上合并
如下图所示:
归并排序的一般步骤:
①.分解:把当前区间一分为二,分解点即中间点mid = (left+right)/2
②.求解:分别递归左右两个子区间[left…mid] 和 [mid+1…right]进行归并排序。递归的终结条件是子区间长度为1。
③.合并:把两个有序子数组合并需要占用一个临时空间,依次挪动两个子区间的指针,比较元素值大小,将较小的值存入临时空间的开头。将两个有序区间归并成一个临时有序区间[left…right],并将结果拷贝到原数组的区间[left…right],使原始数组[left…right]变为有序。
当合并左右两个有序区间时,分为以下几种情况:
①.“左区间”、“右区间”都还有元素,当前右区间元素值小时
如上图,右区间中元素 j 小于左区间中元素 i,则元素 j 小于左区间中范围 [i,mid] 中的所有元素。
②.“左区间”元素用完、“右区间”还剩有元素时
如上图,左区间中元素已经排完,此时右区间中还剩余有元素,此时右区间中元素值全部大于左区间中元素值。
③.“右区间”元素用完、“左区间”还剩有元素时
如上图,右区间中元素已经排完,此时左区间中还剩余有元素,此时左区间中元素值全部大于右区间中元素值。
题目中要求的对每个位置求右侧小于改位置的数组的元素个数,若直接对原数组按数值进行排序,则排序后各元素的位置发生变动,无法和原数组中位置进行对应。
因此可以用原数组的索引值建立新数组,排序时根据索引值获取对应数值进行比较,可以只让索引参与排序。
class Solution { public: vector<int> countSmaller(vector<int>& nums) { vector<int> res(nums.size(),0);//保存结果 vector<int> indexs(nums.size(),0);//索引数组 for(int i = 0;i < indexs.size();i++)//索引赋值 { indexs[i] = i; } vector<int> tempindexs(indexs.size(),0);//临时数组 mergeSort(nums,indexs,tempindexs,res,0,nums.size()-1); return res; } void mergeSort(vector<int>& nums,vector<int>& indexs,vector<int>& tempindexs,vector<int>& res,int left,int right) { if( left >= right ) return; int mid = left + (right - left) /2 ; mergeSort(nums,indexs,tempindexs,res,left,mid);//前有序数组 mergeSort(nums,indexs,tempindexs,res,mid+1,right);//后有序数组 int i = left; int j = mid+1; int t = 0; while( i <= mid && j <= right ) { if( nums[indexs[i]] > nums[indexs[j]] ) // 则 j 对应的数,小于从 i 开始的所有数据 { for( int k = i;k <= mid ;k++) { res[indexs[k]] ++; } tempindexs[t++] = indexs[j++]; } else { tempindexs[t++] = indexs[i++]; } } while( i <= mid ) { tempindexs[t++] = indexs[i++]; } while( j <= right ) { tempindexs[t++] = indexs[j++]; } t = 0 ; while( left <= right ) { indexs[left++] = tempindexs[t++]; } } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。