长度为N的数组arr,一定可以组成N^2个数值对
例如:arr = [3, 1, 2],
数值对有(3, 3)(3, 1)(3, 2)(1, 3)(1, 1)(1, 2)(2, 3)(2, 1)(2, 2),也就是任意两个数都有数值对,而且自己和自己也算数值对
数值对的排序规则,第一维数据从小到大,第一维数据一样的,第二维数据也从小到大
上面的数值对排序结果为:(1, 1)(1, 2)(1, 3)(2, 1)(2, 2)(2, 3)(3, 1)(3, 2)(3, 3)
给定一个数组arr,和整数k,返回第k小的数值对
/* 思路:对数组进行排序,
计算第一维数据的位置,
统计小于和等于第一维数据的值的数量
计算第二维数据的位置
*/
#include
#include
#include
using namespace std;
// 时间复杂度为 O(N*logN)
vector<int> getPairKth(vector<int>& arr, int k) {
if (arr.empty() || arr.size() * arr.size() <= k || k < 0) {
return vector<int>();
}
// 排序时间复杂度为 O(N*logN)
sort(arr.begin(), arr.end());
// pair的第一维
int firstDim = k / arr.size();
// 统计小于第一维数据的数量和等于第一维数据的数量
int lessFirst = 0;
int equalFirst = 0;
for (int i = 0; i < arr.size() && arr.at(i) <= arr.at(firstDim); i++) {
arr.at(i) == arr.at(firstDim) ? equalFirst++ : lessFirst++;
}
int secondDim = (k - lessFirst * arr.size()) / equalFirst;
vector<int> res{
arr.at(firstDim), arr.at(secondDim) };
return res;
}
int main() {
vector<int> arr{
3, 1, 2 };
vector<int> pairKth = getPairKth(arr, 5);
if (!pairKth.empty()) {
cout << "(" << pairKth.at(0) << ", " << pairKth.at(1) << ")" << endl;
}
else {
cout << "pairKth.empty() == true" << endl;
}
system("pause");
return 0;
}
/* 思路:不再对数组进行排序,
计算第一维数据的位置(利用BFPRT在O(N)时间复杂度内找到该数据)
统计小于和等于第一维数据的值的数量(时间复杂度:O(N))
计算第二维数据的位置(利用BFPRT在O(N)时间复杂度内找到该数据)
*/
#include
#include
#include
using namespace std;
// BFPRT算法在无序数组中找到第K小(或大)的数时间复杂度为 O(N),前面的文章有详细的解释
class BFPRT {
public:
int getMinKthByBFPRT(vector<int>& arr, int k, int left, int right) {
if (arr.empty() || k >= arr.size() || left > right || k < left || k > right) {
return -1;
}
if (left == right) {
return arr.at(k);
}
int pivot = medianOfMedians(arr, left, right);
vector<int> range = partition(arr, left, right, pivot);
if (k > range.at(0) && k < range.at(1)) {
return arr.at(k);
}
return k <= range.at(0) ? getMinKthByBFPRT(arr, k, left, range.at(0)) :
getMinKthByBFPRT(arr, k, range.at(1), right);
}
int medianOfMedians(vector<int>& arr, int left, int right) {
vector<int> medians;
int offset = (right - left + 1) % 5 == 0 ? 0 : 1;
int groupNums = (right - left + 1) / 5 + offset;
for (int i = 0; i < groupNums; i++) {
int tmpL = left + i * 5;
int tmpR = tmpL + 5;
sort(arr.begin() + tmpL, arr.begin() + min(tmpR, right));
medians.push_back(arr.at(tmpL + ((min(tmpR, right) - tmpL) >> 1)));
}
return getMinKthByBFPRT(medians, medians.size() / 2, 0, medians.size() - 1);
}
vector<int> partition(vector<int>& arr, int left, int right, int pivot) {
int tmpL = left - 1;
int tmpR = right + 1;
int index = left;
while (index < tmpR) {
if (arr.at(index) < pivot) {
swap(arr, index++, ++tmpL);
}
else if (arr.at(index) > pivot) {
swap(arr, index, --tmpR);
}
else {
index++;
}
}
vector<int> res{
tmpL, tmpR };
return res;
}
void swap(vector<int>& arr, int n1, int n2) {
int tmp = arr.at(n1);
arr.at(n1) = arr.at(n2);
arr.at(n2) = tmp;
}
};
// 时间复杂度为 O(N)
vector<int> getPairKth(vector<int>& arr, int k) {
if (arr.empty() || k < 0 || k >= arr.size() * arr.size()) {
return vector<int>();
}
int firstDim = k / arr.size();
// BFPRT获取第K小的数时间复杂度为 O(N)
int firstNum = BFPRT().getMinKthByBFPRT(arr, firstDim, 0, arr.size() - 1);
// 获取小于和等于第一维数据数量 时间复杂度为 O(N)
int lessFirstNums = 0;
int equalFirstNums = 0;
for (int i = 0; i < arr.size() && arr.at(i) <= firstNum; i++) {
arr.at(i) == firstNum ? equalFirstNums++ : lessFirstNums++;
}
int secondDim = (k - lessFirstNums * arr.size()) / equalFirstNums;
// BFPRT获取第K小的数时间复杂度为 O(N)
int secondNum = BFPRT().getMinKthByBFPRT(arr, secondDim, 0, arr.size() - 1);
vector<int> pairKth{
firstNum, secondNum };
return pairKth;
}
int main() {
vector<int> arr{
3, 1, 2 };
vector<int> pairKth = getPairKth(arr, 5);
if (!pairKth.empty()) {
cout << "(" << pairKth.at(0) << ", " << pairKth.at(1) << ")" << endl;
}
else {
cout << "pairKth.empty() == true" << endl;
}
system("pause");
return 0;
}
如有侵权,请联系删除,如有错误,欢迎大家指正,谢谢