给定一个大小为 n≤10e6 的数组。
有一个大小为 k的滑动窗口,它从数组的最左边移动到最右边。
你只能在窗口中看到 k个数字。
每次滑动窗口向右移动一个位置。
以下是一个例子:
该数组为 [1 3 -1 -3 5 3 6 7]
,k 为 3。
窗口位置 | 最小值 | 最大值 |
---|---|---|
[1 3 -1] -3 5 3 6 7 | -1 | 3 |
1 [3 -1 -3] 5 3 6 7 | -3 | 3 |
1 3 [-1 -3 5] 3 6 7 | -3 | 5 |
1 3 -1 [-3 5 3] 6 7 | -3 | 5 |
1 3 -1 -3 [5 3 6] 7 | 3 | 6 |
1 3 -1 -3 5 [3 6 7] | 3 | 7 |
你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。
输入包含两行。
第一行包含两个整数 n和 k,分别代表数组长度和滑动窗口的长度。
第二行有 n个整数,代表数组的具体数值。
同行数据之间用空格隔开。
输出包含两个。
第一行输出,从左至右,每个位置滑动窗口中的最小值。
第二行输出,从左至右,每个位置滑动窗口中的最大值。
8 3
1 3 -1 -3 5 3 6 7
-1 -3 -3 -3 3 3
3 3 5 5 6 7
这段代码的目标是在一个数组中找到每个长度为 k
的子数组的最小值和最大值。这是通过使用一个双端队列 que
来实现的,队列中存储的是数组元素的值,而不是索引。
下面是这段代码的详细解释:
n
和 k
分别表示数组的长度和子数组的长度。arr
是输入的数组,que
是用来存储子数组元素的队列。l
和 r
分别表示队列的头部和尾部。scanf
函数读取 n
和 k
的值,然后读取 n
个整数填充数组 arr
。arr
,对于每个元素 arr[i]
,如果队列不为空且 arr[i]
小于队列尾部的元素,那么就将队列尾部的元素出队,直到队列为空或者 arr[i]
不小于队列尾部的元素。然后将 arr[i]
入队。i
大于等于 k
,并且队列头部的元素等于窗口的第一个元素(即 arr[i-k]
),那么就将队列头部的元素出队。i
大于等于 k-1
,那么就输出队列头部的元素,因为它就是当前窗口的最小值。arr[i]
大于队列尾部的元素,那么就将队列尾部的元素出队,然后将 arr[i]
入队。#include
int que[1000005];
int arr[1000005] = { 0 };
int l = 0, r = 0;
int main() {
int n, k;
scanf("%d %d", &n, &k);
for (int i = 0; i < n; i++) scanf("%d", &arr[i]);
//MIN
for (int i = 0; i < n; i++) {
while (l < r && arr[i] < que[r - 1]) {
r--;
}
que[r++] = arr[i];
if (i >= k && que[l] == arr[i - k]) {
l++;
}
if (i >= k - 1) {
printf("%d ", que[l]);
}
}
printf("\n");
l = 0, r = 0;
//MAX
for (int i = 0; i < n; i++) {
while (l < r && arr[i] > que[r - 1]) {
r--;
}
que[r++] = arr[i];
if (i >= k && que[l] == arr[i - k]) {
l++;
}
if (i >= k - 1) {
printf("%d ", que[l]);
}
}
return 0;
}
(i >= k && que[l] == arr[i - k])
很关键,i>=k说明可以开始删元素,而que[l] == arr[i - k]
说明已经滑动到了应该删除的位置。给出项数为 n 的整数数列 。
找出这项数列每一项后面的数中第一个比他大的数的下标,没有就输出0。
第一行一个正整数n。
第二行 n 个正整数ai。
一行 n 个整数表示下标的值。
5
1 4 2 3 5
2 5 4 5 0
【数据规模与约定】
对于 30%的数据,n≤100;
对于 60%的数据,1≤n<=5×10e3
对于 100%的数据,1≤n≤3×10e6,1≤ai≤10e9。
#include // 引入标准输入输出库
int main() // 主函数
{
int n; // 定义整数 n,用于存储数组的大小
int l = 0,r = 0; // 定义两个整数 l 和 r,初始化为 0,用于作为栈的左右指针
scanf("%d", &n); // 从标准输入读取 n 的值
int arr[3000001]; // 定义一个大小为 3000001 的整数数组 arr
int i; // 定义整数 i,用于循环
for ( i = 0; i < n; i++) // 对于每一个 i,从 0 到 n-1
{
scanf("%d", &arr[i]); // 从标准输入读取 arr[i] 的值
}
int ans[3000001] = { 0 }; // 定义一个大小为 3000001 的整数数组 ans,并初始化所有元素为 0
int stack[3000001] = { 0 }; // 定义一个大小为 3000001 的整数数组 stack,并初始化所有元素为 0
for ( i = 0; i < n; i++) { // 对于每一个 i,从 0 到 n-1
while (r > l && arr[i] > arr[stack[r-1]]) { // 当 r 大于 l 且 arr[i] 大于栈顶元素时
ans[stack[r-1]] = i + 1; // 将 ans 数组的对应位置更新为 i + 1
r--; // r 减 1,即出栈
}
stack[r++] = i; // 将 i 压入栈中,然后 r 加 1
}
for ( i = 0; i < n; i++) // 对于每一个 i,从 0 到 n-1
printf("%d ", ans[i]); // 打印 ans[i] 的值和一个空格
printf("\n"); // 打印一个换行符
return 0; // 主函数返回 0,表示程序正常结束
}
共一行,包含一个整数 n。
按字典序输出所有排列方案,每个方案占一行。
1≤n≤7
3
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
#include
int path[10000]={0};
int n;
int state[10000]={0};
void print(int x){
if(x==n){
for(int i=0;i<n;i++){
printf("%d ",path[i]);
}
printf("\n");
}
else{
for(int j=1;j<=n;j++){
if(state[j]==0){
path[x]=j;
state[j]=1;
print(x+1);
state[j]=0;
}
}
}
}
int main(){
scanf("%d",&n);
print(0);
return 0;
}
(图片来自一位大佬…)
维护一个字符串集合,支持两种操作:
I x
向集合中插入一个字符串 x;Q x
询问一个字符串在集合中出现了多少次。共有 N 个操作,所有输入的字符串总长度不超过 105,字符串仅包含小写英文字母。
第一行包含整数 N,表示操作数。
接下来 N 行,每行包含一个操作指令,指令为 I x
或 Q x
中的一种。
对于每个询问指令 Q x
,都要输出一个整数作为结果,表示 x在集合中出现的次数。
每个结果占一行。
1≤N≤2∗10^4
5
I abc
Q abc
Q ab
I ab
Q ab
1
0
1
#include
#include
#define N 100010
int son[N][26], cnt[N], idx;
char str[N];
void insert(char* str)
{
int p = 0;
for (int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
if (!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
cnt[p]++;
}
int query(char* str)
{
int p = 0;
for (int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
if (!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
int main()
{
int m;
scanf("%d",&m);
while (m--)
{
char op[2];
scanf("%s%s", op, str);
if (*op == 'I') insert(str);
else printf("%d\n", query(str));
}
return 0;
}
这段代码是一个简单的字典树(Trie)实现,用于处理字符串的插入和查询操作。下面是对每个部分的详细解释:
int son[N][26]
:这是字典树的主要数据结构,son[i][j]
表示节点i
的第j
个子节点的编号。int cnt[N]
:cnt[i]
表示以节点i
为结束的字符串的数量。int idx
:用于给字典树中的每个节点分配一个唯一的编号。char str[N]
:用于存储输入的字符串。void insert(char* str)
:
p
设置为根节点(编号为0)。son[p][u]
和idx
。p
移动到新的子节点,并在字符串结束时增加cnt[p]
。int query(char* str)
:
cnt[p]
,即以查询字符串结束的字符串的数量。int main()
:
m
,表示操作的数量。op
和一个字符串str
。如果op
是’I’,它就调用insert(str)
;否则,它就调用query(str)
并打印结果。这个代码的主要用途是处理大量的字符串插入和查询操作,特别是当字符串的长度和数量都可能非常大时。字典树是一种高效的数据结构,可以在这种情况下提供快速的插入和查询操作。这个代码可能用于处理一些需要大量字符串匹配的问题,例如文本搜索、词频统计等。