(для облегчения тестирования)
Контрпример (для версии C): {8, 33, 27, 30, 9, 2, 35, 7, 26, 32, 2, 23, 0, 13, 1, 6, 31, 3, 28 , 4, 5, 18, 12, 2, 9, 14, 17, 21, 19, 22, 15, 20, 24, 11, 10, 16, 25}. Здесь n = 0, m = 35. Эта последовательность пропускает 34
и имеет два 2
.
Это O (m) во времени и O (1) в пространственном решении.
Значения вне диапазона легко обнаруживаются по O (n) во времени и O (1) в пространстве, поэтому тесты концентрируются на последовательностях в диапазоне (то есть все значения находятся в допустимом диапазоне [n, n+m)
). В противном случае {1, 34}
является контрпримером (для версии C, sizeof (int) == 4, стандартное двоичное представление чисел).
Основное различие между версией C и Ruby:
<<
оператор будет вращать значения в C из-за конечного размера (int),
но в Ruby числа будут расти, чтобы соответствовать результату, например,
Рубин: 1 << 100 # -> 1267650600228229401496703205376
C: int n = 100; 1 << n // -> 16
В Ruby: check_index ^= 1 << i;
эквивалентно check_index.setbit(i)
. Тот же эффект может быть реализован в C ++: vector<bool> v(m); v[i] = true;
bool isperm_fredric(int m; int a[m], int m, int n)
{
/**
O(m) in time (single pass), O(1) in space,
no restriction on n,
?overflow?
a[] may be readonly
*/
int check_index = 0;
int check_value = 0;
int min = a[0];
for (int i = 0; i < m; ++i) {
check_index ^= 1 << i;
check_value ^= 1 << (a[i] - n); //
if (a[i] < min)
min = a[i];
}
check_index <<= min - n; // min and n may differ e.g.,
// {1, 1}: min=1, but n may be 0.
return check_index == check_value;
}
Значения вышеуказанной функции были проверены по следующему коду:
bool *seen_isperm_trusted = NULL;
bool isperm_trusted(int m; int a[m], int m, int n)
{
/** O(m) in time, O(m) in space */
for (int i = 0; i < m; ++i) // could be memset(s_i_t, 0, m*sizeof(*s_i_t));
seen_isperm_trusted[i] = false;
for (int i = 0; i < m; ++i) {
if (a[i] < n or a[i] >= n + m)
return false; // out of range
if (seen_isperm_trusted[a[i]-n])
return false; // duplicates
else
seen_isperm_trusted[a[i]-n] = true;
}
return true; // a[] is a permutation of the range: [n, n+m)
}
Входные массивы генерируются с:
void backtrack(int m; int a[m], int m, int nitems)
{
/** generate all permutations with repetition for the range [0, m) */
if (nitems == m) {
(void)test_array(a, nitems, 0); // {0, 0}, {0, 1}, {1, 0}, {1, 1}
}
else for (int i = 0; i < m; ++i) {
a[nitems] = i;
backtrack(a, m, nitems + 1);
}
}