演算法分析與設計 - 作業6

Rainycolor發表於2024-03-25

目錄
  • 問題一
  • 問題二
  • 解法一
  • 解法二

寫這次作業的時候在打呃呃華為軟挑所以比較擺。

雖然軟挑打得也是一坨哈哈

問題一

給定一個字串 \(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)\) 級別。

相關文章