什么算法可能会在数组中找到O(n)时间内丢失的整数?
假设我们有一个数组A,其元素的值范围为{1,2,3 ... 2n}。缺少一半元素,因此A = n的长度。
例如:
A = [1,2,5,3,10],n = 5
输出= 4
答案 0 :(得分:5)
您可以在O(1)额外空间中执行此操作,假设数组上唯一有效的操作是读取元素和交换元素对。
首先请注意,问题的规范排除了数组包含重复项的可能性:它包含1到2N的一半数字。
我们执行快速选择类型算法。从m = 1开始,M = 2N + 1,并在(m + M)/ 2上旋转数组。如果数组左侧部分的大小(元素< =(m + M)/ 2)小于(m + M)/ 2 - m + 1,那么第一个缺失的数字必须在那里。否则,它必须位于数组的右侧。相应地重复左侧或右侧,直到找到缺失的数字。
每次考虑的阵列切片的大小减半,并且可以在O(n)时间和O(1)空间中旋转大小为n的数组。总的来说,时间复杂度为2N + N + N / 2 + ... + 1 <= 4N = O(N)。
答案 1 :(得分:1)
Paul Hankin在C ++中的想法implementation
#include <iostream>
using namespace std;
const int MAX = 1000;
int a[MAX];
int n;
void swap(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
}
// Rearranges elements of a[l..r] in such a way that first come elements
// lower or equal to M, next come elements greater than M. Elements in each group
// come in no particular order.
// Returns an index of the first element among a[l..r] which is greater than M.
int rearrange(int l, int r, int M) {
int i = l, j = r;
while (i <= j)
if (a[i] <= M) i++;
else swap(a[i], a[j--]);
return i;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
int L = 1, R = 2 * n;
int l = 0, r = n - 1;
while (L < R) {
int M = (L + R) / 2; // pivot element
int m = rearrange(l, r, M);
if (m - l == M - L + 1)
l = m, L = M + 1;
else
r = m - 1, R = M;
}
cout << L;
return 0;
}