算法分析与设计 - 作业6

写这次作业的时候在打呃呃华为软挑所以比较摆。

虽然软挑打得也是一坨哈哈

问题一

给定一个字符串 \(s\) 和一个整数 \(K\),设计策略返回一个最大子串长度使得子串每个字符重复出现的次数不大于 \(K\)

考虑对于所有位置 \(i(1\le i\le n)\),求得以该位置为左端点的最长子串 \([i, r_i]\),应当满足子串 \([i, r_i]\) 中每个字符重复出现次数不大于 \(K\),子串 \([i, r_i + 1]\) 中有字符重复出现次数大于 \(K\) 且该字符一定为 \(s_{r_i + 1}\)。则答案即为其中最长的子串。

发现序列 \(\{ r_i \}\)\(i\) 的增加是不递减的,于是考虑在枚举左端点 \(i\) 的同时维护变量 \(r\) 表示以 \(i\) 为左端点的最长的合法子串的右端点的位置,通过维护区间内各个字符出现次数在 \(i\) 右移的同时维护 \(r\) 即可。

设字符集大小为 \(O(m)\) 级别,则空间复杂度 \(O(n + m)\) 级别;左右端点 \(i\)\(r\) 均只会单调右移 \(n\) 次,总时间复杂度 \(O(n)\) 级别。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kM = 1e3 + 10;
//=============================================================
std::string s;
int n, k, cnt[kM];
//=============================================================
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  std::cin >> s;
  n = s.length();

  std::cin >> k;
  int ansl = 0, ansr = -1;
  for (int l = 0, r = -1; l < n; ++ l) {
    while (r < n - 1 && cnt[(int) s[r + 1]] < k) ++ r, ++ cnt[(int) s[r]];
    if (r - l > ansr - ansl) ansl = l, ansr = r;
    -- cnt[(int) s[l]];
  }
  std::cout << ansl << " " << ansr << "\n" << s.substr(ansl, ansr - ansl + 1);
  return 0;
}

问题二

假设一个由 \(n\) 人组成的小组中的每个人都从一组候选人中选出两个人来填补委员会的两个职位。排名前两位的选手只要各自获得超过 \(\frac{n}{2}\) 的选票,都会赢得位置。设计算法,确定获得最多选票的两位候选人是否各自获得了至少 \(\frac{n}{2}\) 张选票,如果是,则确定这两位候选人是谁。

解法一

考虑按照各个候选人的得票进行排序,即得得票最高的两人。

使用基于比较的排序算法,总时间复杂度 \(O(n\log n)\) 级别。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e6 + 10;
//=============================================================
int n;
std::pair <int, int> a[kN];
//=============================================================
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  std::cin >> n;
  for (int i = 1; i <= n; ++ i) {
    a[i].second = i;

    int x, y; std::cin >> x >> y;
    a[x].first ++, a[y].first ++;
  }
  std::sort(a + 1, a + n + 1, std::greater <std::pair <int, int> >());
  if (a[1].first > n / 2) std::cout << a[1].second << " " << a[1].second << "\n";
  if (a[2].first > n / 2) std::cout << a[2].second << " " << a[2].second << "\n";
  return 0;
}

解法二

发现得票数不大于 \(n\),于是考虑替换为计数排序,总时间复杂度变为 \(O(n)\) 级别。

posted @ 2024-03-25 23:14  Rainycolor  阅读(41)  评论(0)    收藏  举报