1.【题目描述】
小 Q 得到了一个长度为 n 的序列 A,A 中的数各不相同。对于 A 中的每一个
数 Ai,求:min(1≤j<i)|Ai−Aj|
以及令上式取到最小值的 j(记为 P_i)。若最小值点不唯一,则选择使 Aj 较小的那个。
输入描述:
第一行一个整数 n,第二行 n 个数。
输出描述: n-1 行,每行 2 个用空格隔开的整数。分别表示当 i 取 2~n 时,对应的 min(1≤j<i)|Ai−Aj|和 Pi的值
输入样例:
3
1 5 3
输出样例:
4 1
2 1
2.【问题分析】
1.暴力破解的代价太大。进一步考虑,如果输入序列有序,那么每次检索比较的范围可以缩小到三个数之间
2.问题要求输出相应Pi的值,则选用数组等数据结构不可取,需要借助用户自定义类型,这里我们选择双向链表,由于初始化(即插入)工作一次完成,后边不做修改,可以将其简化为静态双向链表
3.需要借助辅助数组来维护原始序列的元素位置和下标。
3.【图示】

4.【代码】
#include<bits/stdc++.h>
using namespace std;
/*
小Q的最小值序列
3
1 5 3
*/
const int N = 1e5 + 5; //开辟数组的空间大小
const int inf = 1e9;
struct P
{
int value;
int pos;
};
P a[N];
int cmp(P x, P y)
{
return x.value < y.value;
}
int b[N], b2[N], cnt, head, tail, ans1[N], ans2[N];
struct node
{
int value;
int next, pre;
}e[N];
void init() //初始化一个静态的双向链表
{
cnt = 2;
head = 1;
tail = 2;
e[head].next = tail;
e[tail].pre = head;
}
void ins(int pos, int x) //相当于双向链表的插入操作
{
e[++cnt].value = x;
e[cnt].next = e[pos].next;
e[cnt].pre = pos;
e[e[pos].next].pre = cnt;
e[pos].next = cnt;
}
void del(int pos) //相当于双向链表的删除操作
{
e[e[pos].next].pre = e[pos].pre;
e[e[pos].pre].next = e[pos].next;
}
int main()
{
int n; //元素的总数
scanf_s("%d", &n);
for (int i = 1; i <= n; ++i) //初始化输入序列
{
scanf_s("%d", &a[i].value);
a[i].pos = i;
}
sort(a+1, a+1+n, cmp); //经过排序操作,下标将会打乱次序
init();
for (int i = 1; i <= n; ++i)
{
ins(e[tail].pre, a[i].value); //尾插
b[a[i].pos] = cnt; //记录元素在e中的的位置,将a[i]中的元素插入e中,并还原其初始位置,与排序前位置保持一致
b2[cnt] = a[i].pos; //维护b[i]的下标
}
for (int i = n; i >= 2; --i)
{
ans1[i] = inf;
if (e[b[i]].next != tail) //从最后一个元素开始
{
ans1[i] = min(ans1[i], abs(e[b[i]].value - e[e[b[i]].next].value));
ans2[i] = b2[e[b[i]].next];
}
if (e[b[i]].pre != head) //从最后一个元素开始
{
if (ans1[i] >= abs(e[b[i]].value - e[e[b[i]].pre].value))
{
ans1[i] = abs(e[b[i]].value - e[e[b[i]].pre].value);
ans2[i] = b2[e[b[i]].pre];
}
}
del(b[i]); //极其重要
}
for (int i = 2; i <= n; ++i)
{
printf("%d %d\n", ans1[i], ans2[i]);
}
return 0;
}
4.【运行结果】

探讨了如何通过使用双向链表和辅助数组解决小Q的最小值序列问题,包括输入序列的处理、数据结构的选择及算法实现,旨在寻找序列中每个元素与前序元素的最小绝对差值及其对应位置。
434

被折叠的 条评论
为什么被折叠?



