逆序数

用归并排序的归并过程来统计,逆序数=左子问题+右子问题+跨数组逆序数。为统计跨数组逆序数,从数组末开始,一旦左数组末的a[i]>右数组末的b[j](逆序),就知a[i]>b[j]>=b[j-1]>=...>=b[0],关于a[i]的跨组逆序数是j+1。或者从数组头开始,一旦右数组头的b[j]<左数组头的a[i](逆序),就知b[j]<a[i]<=a[i+1]<=...<=a[n1],关于b[j]的跨组逆序数是n1-i+1。

  • https://leetcode.com/problems/reverse-pairs/
int reversePairs(vector<int>& nums) {
	return mergeSort(nums, 0, (int)nums.size() - 1);
}

int mergeSort(vector<int>& nums, int l, int h) {
	if (l >= h) return 0;
	int mid = l + (h - l) / 2;
	int ans = mergeSort(nums, l, mid) + mergeSort(nums, mid + 1, h);

	// 统计组间逆序数
	for (int j = mid + 1; j <= h; j++) {
		// nums[l..mid]中找第一个>2*nums[j]的i
		auto it = upper_bound(begin(nums) + l, begin(nums) + mid + 1, 2l * nums[j]);
		int i = it - begin(nums);
		ans += mid - i + 1;  // 位置[i..mid]与i逆序
	}
	merge(nums, l, mid, h);
	return ans;
}

// 归并已排序的 nums[l..mid] 和 nums[mid+1..h]
void merge(vector<int>& nums, int l, int mid, int h) {
	vector<int> merged(h - l + 1);
	int i = l, j = mid + 1, k = 0;
	while (i <= mid && j <= h) {
		if (nums[i] < nums[j]) {
			merged[k++] = nums[i++];
		} else {
			merged[k++] = nums[j++];
		}
	}
	while (i <= mid) merged[k++] = nums[i++];
	while (j <= h) merged[k++] = nums[j++];
	for (int k = 0; k < merged.size(); k++) {
		nums[l + k] = merged[k];
	}
}

每个数右边比它小的数有多少个

vector<int> countSmaller(vector<int>& nums) {
    // 要看数的右边,所以不能移动数字,在索引数组idx上归并排序
    const int N = nums.size();
    vector<int> idx;
    for (int i = 0; i < N; i++) {
        idx.push_back(i);
    }
    vector<int> ans(N, 0);
    mergeSort(nums, idx, 0, N - 1, ans);
    return ans;
}

void mergeSort(vector<int> &nums, vector<int> &idx, int l, int r, vector<int> &ans) {
    if (l >= r) return;
    int mid = l + (r - l) / 2;
    mergeSort(nums, idx, l, mid, ans);
    mergeSort(nums, idx, mid + 1, r, ans);

    vector<int> merged(r - l + 1);
    // 两指针同向遍历,从两数组末端开始比较
    int i = mid, j = r, k = r - l;
    while (i >= l && j > mid) {
        if (nums[idx[i]] > nums[idx[j]]) {
            ans[idx[i]] += j - mid; // 位置[mid+1..j]与i逆序
            merged[k--] = idx[i--];
        } else {
            merged[k--] = idx[j--];
        }
    }
    while (i >= l) merged[k--] = idx[i--];
    while (j > mid) merged[k--] = idx[j--];
    for (int k = 0; k < merged.size(); k++) {
        idx[l + k] = merged[k];
    }
}

全局逆序数==相邻逆序数

bool isIdealPermutation(vector<int>& A) {
    // 全局逆序数==相邻逆序数,除了相邻、没有逆序,
    // 即max(A[0..i-2])<=A[i]
    int theMax = -1;
    for (int i = 2; i < A.size(); i++) {
        theMax = max(theMax, A[i-2]);
        if (theMax > A[i]) return false;
    }
    return true;
}