E-相依

定义dp[i]为第一个数到第i个数所需要合并的最少次数,可以得到动态转移方程:

dp[i] = min{dp[j - 1] + 1} (1 <= j < i且 val[i] = val [j]且 dp[j - 1]存在)

但是这样做要枚举前i - 1个数,时间复杂度原地爆炸。观察动态转移方程,不难发现我们要找的是dp[j - 1]的最小值,即每个与i位置有相同的值的j位置前面一个位置的dp值的最小值。所以可以使用哈希表记录每个val值前面位置dp值的最小值,用m[val]代表这个值,那么dp[i]就可以这样计算:

dp[i] = m[val[i]] + 1

现在,只需要在每次计算完当前i位置的dp值后更新val值,就可以用o(n)的时间复杂度完成本题了

#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
#define MAXN 1000000000
int arr[1000000];
int dp[1000000];
int n;
unordered_map<int, int> valm;

int main() {
	cin >> n;
	for(int i = 1; i <= n; i++) {
		scanf("%d", &arr[i]);
	}
	dp[0] = 0;
	for(int i = 1; i <= n; i++) {
		//计算当前dp值
		dp[i] = MAXN;
		if(valm.find(arr[i]) != valm.end()) {
			dp[i] = valm[arr[i]] + 1;
		}
		//更新最小val值
		if(dp[i - 1] == MAXN) continue;
		if(valm.find(arr[i]) == valm.end()) {
			valm[arr[i]] = dp[i - 1];
		} else {
			valm[arr[i]] = min(valm[arr[i]], dp[i - 1]);
		}
		
	}
	if(dp[n] == MAXN) {
		cout << "-1";
		return 0;
	}
	cout << dp[n];
	return 0;
}