完整教程:算法1112


1. 简写单词

简写单词

1.1 思路

简单的模拟题。

1.2 源码

#include <iostream>
  using namespace std;
  #include <string>
    int main() {
    string s;
    while (cin >> s) {
    if (s[0] <= 'z' && s[0] >= 'a') cout << (char)(s[0] - 32);
    else cout << s[0];
    }
    return 0;
    }

1.3 总结

  1. cin >> s 遇到空白字符时,会先完成当前单词的读取(把空白字符前的内容存入 s),然后跳过该空白字符,等待下一次读取。
  2. 只要输入中还有后续非空白字符(即还有其他单词),下一次 cin >> s 仍能成功读取,循环就会继续。
  3. 只有当输入中没有更多可读取的非空白字符(比如到达文件末尾,或手动输入了 EOF 信号),cin >> s 才会返回失败状态(false),循环才会结束。

2. dd爱框框

dd爱框框

2.1 思路

滑动窗口!特点是数组具有单调性,并且可以用同向双指针,优先想滑动窗口。

  1. 下标从一开始
    在这里插入图片描述
  2. 算法的时间复杂度一定是O(n)在这里插入图片描述
  3. 所有的输入都是大于1的(具有单调性),如此我们才能做优化。在这里插入图片描述
  4. 滑动窗口四步走:
    1. 进窗口
    1. 判断
    1. 出窗口
    1. 思考更新窗口的时机

2.2 源码

#include<iostream>
  using namespace std;
  int N = 1e7 + 10;
  int arr[N];
  int n, x; // 封装全局的意义:可以避免函数传参
  int main()
  {
  cin >> n >> x;
  for(int i = 1; i < n; i++)
  {
  cin >> arr[i];
  }
  int retlen = N, retleft = -1, retright = -1, sum;
  int left = 0, right = 0;
  while(right <= n)
  {
  sum += arr[right];
  while(sum >= x)
  {
  if(right - left + 1< retlen)
  {
  retleft = left;
  retright = right;
  retlen = right - left + 1;
  }
  sum -= arr[left++];
  }
  right ++;
  }
  cout << retleft << " " << retright << endl;
  return 0;
  }

2.3 总结

我想到用双指针,也想到右指针不用回溯,但是!不知道多会儿更新指针的值。
这个题还有一个坑的点,要解决不支持变长数组的问题。

3. 除2!

除2!

3.1思路

模拟+贪心+堆
每次都找数组中最大的数进行折半,通过(只存偶数)来维护数组有序的结构。

3.2 复习优先级队列

当在cpp中提到要用堆的数据结构的时候,我们不用真的去写一个堆的数据结构,不用去造轮子。而是直接使用优先级队列,来实现堆的结构。

好的,我们来复习一下优先级队列(Priority Queue)的核心知识点,包括定义、特性、实现方式、应用场景等内容。

3.2.1 什么是优先级队列?

优先级队列是一种特殊的队列,每个元素都有一个“优先级”,队列的出队操作不是按“先进先出(FIFO)”,而是优先级最高的元素先出队(若优先级相同,可能按插入顺序或其他规则处理)。

3.2.2 核心特性
  • 有序性:元素按优先级排序(通常是最大优先级或最小优先级在前)。
  • 操作
    • insert(入队):添加元素并调整队列以维持优先级顺序。
    • extractMax/extractMin(出队):移除并返回优先级最高(或最低)的元素。
    • peek:查看优先级最高(或最低)的元素,不删除。
    • (可选)updatePriority:修改某个元素的优先级后重新调整队列。
3.3.3 实现方式
3.3.3.1 堆(Heap)
  • 原理:堆是一种完全二叉树,分为最大堆(父节点 ≥ 子节点)和最小堆(父节点 ≤ 子节点),天然适合优先级队列。
  • 时间复杂度
    • 插入(heapify up):O(log n)(向上调整堆)。
    • 取最值(extractMax/Min + heapify down):O(log n)(移除根节点后向下调整堆)。
    • 建堆:O(n)(从最后一个非叶子节点向上调整)。
  • 优点:效率高,是优先级队列的主流实现方式。
3.3.3.2 堆的实现细节

最大堆为例(最小堆类似,只需调整比较逻辑):

  • 存储:用数组表示完全二叉树,对于索引 i 的节点:
    • 左孩子:2i + 1
    • 右孩子:2i + 2
    • 父节点:(i - 1) // 2
  • 插入操作
    1. 元素添加到数组末尾。
    2. 向上调整(heapify up):与父节点比较,若更大则交换,重复直到根节点或满足堆性质。
  • 取最大值操作
    1. 取出根节点(数组[0])。
    2. 将数组最后一个元素移到根节点位置。
    3. 向下调整(heapify down):与左右孩子中较大的交换,重复直到叶子节点或满足堆性质。

C++priority_queue(默认是最大堆,需包含 <queue> 头文件)。

3.3 源码

#include<iostream>
  #include<queue>
    using namespace std;
    typedef long long LL;
    LL n, k;
    priority_queue<LL> heap;
      int main()
      {
      cin >> n >> k;
      LL sum = 0, x;
      while(n--)
      {
      cin >> x;
      sum += x;
      if(x % 2 == 0)
      heap.push(x);
      }
      while(heap.size() && k--)
      {
      LL t = heap.top() / 2;
      heap.pop();
      sum -= t;
      if(t % 2 == 0) heap.push(t);
      }
      cout << sum << endl;
      return 0;
      }

3.4 总结

我在思考本题的时候,想到要将输入存在数组中,也想到要维护数组的顺序。但是我想的使用qsort来维护,这样每次改变数组都需要排序,时间复杂度很高。
重点是要想到使用优先级队列。当需要每次都拿出一堆数中的最小或者最大的时候就要想到堆结构!!!


posted @ 2025-12-14 10:37  clnchanpin  阅读(4)  评论(0)    收藏  举报