算法1112
文章目录
- 1. 简写单词
- 1.1 思路
- 1.2 源码
- 1.3 总结
- 2. dd爱框框
- 2.1 思路
- 2.2 源码
- 2.3 总结
- 3. 除2!
- 3.1思路
- 3.2 复习优先级队列
- 3.2.1 什么是优先级队列?
- 3.2.2 核心特性
- 3.3.3 实现方式
- 3.3.3.1 堆(Heap)
- 3.3.3.2 堆的实现细节
- 3.3 源码
- 3.4 总结
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 总结
- cin >> s 遇到空白字符时,会先完成当前单词的读取(把空白字符前的内容存入 s),然后跳过该空白字符,等待下一次读取。
- 只要输入中还有后续非空白字符(即还有其他单词),下一次 cin >> s 仍能成功读取,循环就会继续。
- 只有当输入中没有更多可读取的非空白字符(比如到达文件末尾,或手动输入了 EOF 信号),cin >> s 才会返回失败状态(false),循环才会结束。
2. dd爱框框
dd爱框框
2.1 思路
滑动窗口!特点是数组具有单调性,并且可以用同向双指针,优先想滑动窗口。
- 下标从一开始

- 算法的时间复杂度一定是O(n)

- 所有的输入都是大于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
- 左孩子:
- 插入操作:
- 元素添加到数组末尾。
- 向上调整(
heapify up):与父节点比较,若更大则交换,重复直到根节点或满足堆性质。
- 取最大值操作:
- 取出根节点(数组[0])。
- 将数组最后一个元素移到根节点位置。
- 向下调整(
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来维护,这样每次改变数组都需要排序,时间复杂度很高。
重点是要想到使用优先级队列。当需要每次都拿出一堆数中的最小或者最大的时候就要想到堆结构!!!
完
