板子:有序表去重与合并(双指针)
有序是双指针的前提:两个指针都只往前走,不回头,所以一趟
就能扫完。
代码
void dedup(int A[], int &n) { // 有序表去重
if (n == 0) return; // 空表要特判,否则下面 k = 1 就错了
int k = 1; // A[0] 一定保留;A[0..k-1] 是去重后的结果
for (int i = 1; i < n; i++)
if (A[i] != A[k - 1]) A[k++] = A[i]; // 和已保留的最后一个比较,不同才收下
n = k;
}
int mergeSorted(int A[], int n, int B[], int m, int C[]) { // 两个升序表合并到 C,返回长度
int i = 0, j = 0, k = 0;
while (i < n && j < m) // 两边都还有元素才需要比较
C[k++] = A[i] <= B[j] ? A[i++] : B[j++]; // <=:相等时先取 A,合并是稳定的
while (i < n) C[k++] = A[i++]; // 剩下的直接接到后面(两句只会执行一句)
while (j < m) C[k++] = B[j++];
return k;
}
int intersect(int A[], int n, int B[], int m, int C[]) { // 两个升序表求交集,返回长度
int i = 0, j = 0, k = 0;
while (i < n && j < m) {
if (A[i] < B[j]) i++; // 小的一方往前走
else if (A[i] > B[j]) j++;
else { C[k++] = A[i]; i++; j++; } // 相等才收下
}
return k;
}复杂度:去重 C。
同一个骨架还能做
- 差集
:交集代码里, A[i] < B[j]时把A[i]收下。 - 归并排序的
Merge、两个有序链表合并:和mergeSorted是同一段代码。 - 2011 两序列中位数的保底解:按合并的顺序数到第
个,不需要存下来。见 两个等长升序序列的中位数。
易错点
- 无序表不能这样去重:要么先排序,要么值域小的时候用辅助数组标记(见 辅助数组计数与标记)。
- 合并时写
<=,相等时先取A的元素,这样合并是稳定的。 - 主循环结束后,两个
while收尾都要写,不知道哪边先用完。 - 如果
A后面还有个空位,可以从后往前填,直接合并到 A里,不用C。
链接
- 📕 返回:数据结构代码板子
- ⬅️ 上一篇:删除所有值为 x 的元素
- ➡️ 下一篇:二分查找
- 🔗 同属按条件过滤:删除所有值为 x 的元素
- 🔗 两个等长升序序列的中位数