K番目に小さい値のペア(O(N * logN)を解くためにソート、O(N)を解くためにBFPRT)

長さ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)、つまり、任意の2つの数値には値のペアがあり、あなたとあなた自身も値をカウントします-
値のペアのルール、最初のディメンションデータは小さいものから大きいものへ、最初のディメンションデータは同じであり、2番目のディメンションデータも小さいものから大きいものへ
です。上記の値を並べ替えた結果は次のとおりです:(1、 1)(1、2)(1、3)(
2、1 )(2、2)(2、3)(3、1 )(3、2 )(3、3)配列arrと整数が与えられた場合k、k番目に小さい値のペアを返します

O(N * logN)の複雑さを持つソリューション

/* 思路:对数组进行排序,
        计算第一维数据的位置,
        统计小于和等于第一维数据的值的数量
        计算第二维数据的位置
*/

#include <iostream>
#include <vector>
#include <algorithm>
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;
}

時間計算量O(N)ソリューション

/* 思路:不再对数组进行排序,
        计算第一维数据的位置(利用BFPRT在O(N)时间复杂度内找到该数据)
        统计小于和等于第一维数据的值的数量(时间复杂度:O(N))
        计算第二维数据的位置(利用BFPRT在O(N)时间复杂度内找到该数据) 
*/

#include <iostream>
#include <vector>
#include <algorithm>
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;
}

侵害がある場合は、連絡して削除してください。エラーがある場合は、訂正してください。ありがとうございます。

おすすめ

転載: blog.csdn.net/xiao_ma_nong_last/article/details/105756842