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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值