您的位置:首页 > 其它

LeetCode 315. Count of Smaller Numbers After Self

2017-09-10 23:10 495 查看

分治算法练习

本周选择LeetCode第315题Count of Smaller Numbers After Self,难度为hard。

题目描述如下:

You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].

Example:

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.

Return the array [2, 1, 1, 0].

使用分治算法进行解题。

1. 考虑对于第i个元素,所求的counts[i]的值仅与nums[i]右侧的值有关,若nums[i]右侧的值已排序,则求大于nums[i]的值的数目将变得十分容易。因此可以从排序的的角度思考解题方法。

2. 归并排序是将一个大的数组,不断拆分成小数组,对小数组进行排序,并将有序的小数组合并成大的数组。对于此题,将nums[]拆分成不断左右两子数组,最终使得子数组有序,将有序子数组合并时,将右边数组中小于左边数组的元素数目加到counts[]中,最终得到counts[]。

3. 上述解法近似于对数组进行归并排序,时间复杂度为O(nlogn),需要记录counts,nums,和排序后的index,空间复杂度为O(n)。

具体代码如下:

Solution类有3个私有变量vector分别储存传入的nums,结果的counts,和排序后元素的index。

公有函数countSmaller传入nums并返回结果counts。

divide将数组其中一段分成左右两部分,并调用sort进行合并及排序。

class Solution {
public:
vector<int> countSmaller(vector<int>& nums);

void divide(int head, int length);

void sort(int head1, int head2, int length);

private:
vector<int> counts;
vector<int> index;
vector<int> nums;
};


各个函数的实现:

vector<int> countSmaller(vector<int>& nums) {
this->nums = nums;
for (int i = 0; i < nums.size(); i++) {
index.push_back(i);
counts.push_back(0);
}
if (nums.size() != 0)
divide(0, nums.size());
return counts;
}
void divide(int head, int length) {
if (length == 1) return;
divide(head, length/2);
divide(head + length/2, length-length/2);
sort(head, head+length/2, length);
return;
}

void sort(int head1, int head2, int length) {
int length1 = head2-head1;
int length2 = length-length1;
int i = 0,
j = 0;

// copies of indexes
int* left = new int[length1];
int* right = new int[length2];
for (int k = 0 ; k < length1; k++) {
left[k] = index[head1+k];
}
for (int k = 0 ; k < length2; k++) {
right[k] = index[head2+k];
}

// record the count of current max num of right[]
int maxCount = 0;

// merge sort
while (i != length1 && j != length2) {
if (nums[left[i]] <= nums[right[j]]) {
index[i+j+head1] = left[i];
counts[left[i]] += maxCount;
i++;
} else {
index[i+j+head1] = right[j];
maxCount += 1;
j++;
}
}
for (i; i < length1; i++) {
index[i+j+head1] = left[i];
counts[left[i]] += maxCount;
}
for (j; j < length2; j++) {
index[i+j+head1] = right[j];
}

delete [] left;
delete [] right;

}


运行结果:

16 / 16 test cases passed.

Status: Accepted

Runtime: 33 ms

Your runtime beats 61.10 % of cpp submissions.

这说明还有更优的方法解决此问题,有待进一步探究。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: