百度2019屆算法崗秋招編程-逆序對數

題目

  • 給一個數組,可以將其中一個數字轉化爲0,求轉化後的逆序對之和的最小值以及此時轉化的下標。
  • 思路:這題最主要的就是求每個數字的到當前狀態時的逆序對數(修改前和後),之前想的是用multiset存儲數字,用upper_bound求比當前值大的數,用distance去計算逆序對的個數,但是後來發現distance在這種不可隨機訪問的容器中的時間複雜度爲O(N),果斷超時,只過了60%左右的case。
  • leetcode上有相似的題目,是求逆序對數的個數的,沒有涉及到數字轉換的問題:https://leetcode.com/problems/count-of-smaller-numbers-after-self/
  • 上面的最佳解法是構建pair數組,進行歸併排序即可。
  • 可以將上面的思路引入到這裏面來。先找到從左到右以及從右到左的逆序對的個數(從端點到當前),然後再逐個變成0,看是否可以減小逆序對的數量,記錄最小數量以及最小值即可。
  • 關於上面leetcode題解有個比較好的講解:https://www.cnblogs.com/ilovezyg/p/6877214.html

代碼

	#include <cstdlib>
	#include <string>
	#include <iostream>
	#include <fstream>
	#include <sstream>
	#include <unordered_map>
	#include <unordered_set>
	#include <map>
	#include <set>
	#include <stdio.h>
	#include <numeric>
	#include <algorithm>
	#include <functional>
	#include <stack>
	#include <queue>
	#include <cmath>
	#include <vector>
	#include <memory>
	#include <memory.h>
	using namespace std;
	typedef long long ll;
	const int MOD = 1e9 + 7;
	typedef unsigned char uchar;
	
	// #define G_DEBUG
	// 定義unordered_set<pair<int,int>, pairhash> sets時會用到
	struct pairhash {
	public:
		template <typename T, typename U>
		std::size_t operator()(const std::pair<T, U> &x) const
		{
			return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
		}
	};
	
	void merge(vector<int>& count, vector<pair<int, int>>& nums, int start, int mid, int end)
	{
		int left = start, right = mid + 1;
	
		vector<pair<int, int>> helper(end - start + 1);
		int idx = 0;
		while (left <= mid && right <= end)
		{
			if (nums[left].first > nums[right].first)
			{
				count[nums[left].second] += (end - right + 1);
	
				helper[idx++] = nums[left++];
			}
			else
				helper[idx++] = nums[right++];
		}
		while (left <= mid)
			helper[idx++] = nums[left++];
		while (right <= end)
			helper[idx++] = nums[right++];
	
		copy(helper.begin(), helper.end(), nums.begin() + start);
	}
	
	void merge_sort(vector<int>& count, vector<pair<int,int>>& nums, int start, int end)
	{
		if (start >= end)
			return;
	
		int mid = (start + end) / 2;
		merge_sort(count, nums, start, mid);
		merge_sort(count, nums, mid + 1, end);
		merge( count, nums, start, mid, end );
	
	}
	
	
	int main()
	{
	
	#ifdef G_DEBUG
		// 調試使用
		ifstream file("data.txt");
		int N = 0;
		file >> N;
		vector<int> nums(N);
		for (int i = 0; i < N; i++)
		{
			file >> nums[i];
		}
	
		file.close();
	#else
		int N = 0;
		cin >> N;
		vector<int> nums(N, 0);
		for (int i = 0; i < N; i++)
		{
			cin >> nums[i];
		}
	
	#endif
		vector<pair<int, int>> pairs( N );
		for (int i = 0; i < N; i++)
		{
			pairs[i].first = nums[i];
			pairs[i].second = i;
		}
		vector<int> count_left(N, 0);
		merge_sort( count_left, pairs, 0, N-1 );
	
		vector<int> count_right(N, 0);
		
		for (int i = 0; i < N; i++)
		{
			pairs[i].first = -nums[N - 1 - i];
			pairs[i].second = N - 1 - i;
		}
		
		merge_sort(count_right, pairs, 0, N - 1);
	
		
	
		int before = 0;
		int min_idx = 0;
		int min_val = 0;
		for (int i = 0; i < N; i++)
			min_val += count_left[i];
		before = min_val;
		for (int i = 0; i < N; i++)
		{
			if (before + i - count_left[i] - count_right[i] < min_val)
			{
				min_val = before + i - count_left[i] - count_right[i];
				min_idx = i;
			}
				
		}
		
		cout << min_val << " " << (min_idx + 1) << endl;
	
	
	
		system("pause");
		return 0;
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章