Uniqueness(思維 or 二分 or 暴力)

題目鏈接:B. Uniqueness

題意:n (1 - 2000) 個數,只刪除一個子串使得數組中沒有重複元素,求刪除的子串長度。

思路(參考博客cf1208B B. Uniqueness):
逆向考慮問題,要刪除的最少區間長度對應最多能保留多少個數,又因爲區間要是連續的,所以只能刪除左端區間,或中區間,或右邊區間。利用兩個map,第一個存從左往右能保留的每個元素的下標,並用一個數記錄最終下標;第二個map從右往左掃描,用於記錄當前元素的右半部分能保留多少數,如果出現與其右部分的重複元素,則計算其中間要刪除的元素個數,並判斷是否要更新答案,否則進行標記,若當前右半部分的元素與一開始左半部分的元素,則模擬對左半部分元素刪除操作,同時更新刪除元素個數找出最佳答案,具體情況看代碼和註釋。

暴力的話直接枚舉所有可能的長度,二分的話就是二分可能的長度,就是再暴力的基礎上多了一點優化。

原博主代碼:

#include <bits/stdc++.h>
using namespace std;
map<int, int > book1, book2;
int main() {
	int n;
	int a[2005];
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	int ans = 99999;
	// p記錄左半部分能保留數字的下標(即個數), q記錄右半部分能保留到的下標,q-p則爲要刪除的序列的大小 
	int p = 1, q = n; 
	// 從左往右掃描,記錄從左往右能保留多少個數,即遇到重複數字停止掃描 
	while (p <= n) {
		if (book1[a[p]]) {
			break;
		} else {
			book1[a[p]] = p;
		}
		p++;
	}
	// 由於掃描的時候是判斷下一位,所以p要減一纔是實際最後那個不重複元素的下標(個數) 
	p--;
	ans = n - p; // 此時要刪除的元素爲元素總個數減去前左半部分要保留的數字 
	// 從右往左掃描 
	while (q >= 1) {
		if (book2[a[q]]) { // 如果q右半部分的數字在左半部分沒出現過,但q右半部分的數字出現重複,則進行判斷後結束掃描 
			if (ans > q - p) ans = q - p; // 如果此時要刪除的元素個數比之前少,則更新答案 
			break;
		} else { // 否則進行標記該元素出現過 
			book2[a[q]] = 1;
		}
		if (book1[a[q]] && p >= book1[a[q]]) { // 如果右半部分的最左端的元素與一開始左半部分要保留的數字重複,
		//則模擬左半部分元素刪除操作,同時判斷是否要更新答案和更新左半部分要保留的數字下標 
			if (ans > q - p) ans = q - p;
			p = book1[a[q]] - 1;
		}
		q--;
	} 
	printf("%d\n", ans);
	return 0;
}

我就貼暴力的代碼了

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 2010;

int n;
int a[N];

map<int, int> ma;

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    int ans = n - 1;
    for (int i = 1; i <= n; i++)
    {
        ma.clear();
        bool ok = true;
        for (int j = 1; j < i; j++)
        {
            ma[a[j]]++;
            if (ma[a[j]] == 2)
            {
                ok = false;
                break;
            }
        }
        if (!ok)
            continue;
        int mn = n + 1;
        for (int j = n; j >= i; j--)
        {
            ma[a[j]]++;
            if (ma[a[j]] == 1)
            {
                mn = j;
            }
            else
                break;
        }
        ans = min(ans, mn - i);
    }
    cout << ans << endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章