diff --git a/banque.c b/banque.c index 8f5cedd..62a9290 100644 --- a/banque.c +++ b/banque.c @@ -168,13 +168,56 @@ const Transaction *rechercher_par_id(const Transaction *t, int n, int id) } /* F7 : nombre de paires de transactions de montants opposés (a + b = 0) */ +static int cmp_long(const void *a, const void *b) +{ + long x = *(const long *)a, y = *(const long *)b; + return (x > y) - (x < y); +} + long nb_paires_opposees(const Transaction *t, int n) { - long nb = 0; + if (n < 2) + return 0; + + long *m = malloc(n * sizeof(long)); + if (!m) + return 0; for (int i = 0; i < n; i++) - for (int j = i + 1; j < n; j++) - if (t[i].montant + t[j].montant == 0) - nb++; + m[i] = t[i].montant; + + qsort(m, n, sizeof(long), cmp_long); /* O(n log n) */ + + long nb = 0; + + /* zéros : tous les montants nuls forment un bloc contigu */ + int deb = 0; + while (deb < n && m[deb] < 0) + deb++; + int fin = deb; + while (fin < n && m[fin] == 0) + fin++; + long z = fin - deb; + nb += z * (z - 1) / 2; + + /* deux pointeurs : négatifs depuis la fin de la zone négative, + positifs depuis le début de la zone positive (fin) */ + int i = deb - 1; /* plus grand négatif : le plus proche de 0 */ + int j = fin; /* plus petit positif : le plus proche de 0 */ + while (i >= 0 && j < n) { + long neg = -m[i], pos = m[j]; + if (neg < pos) { + i--; + } else if (neg > pos) { + j++; + } else { + long v = pos, a = 0, b = 0; + while (i >= 0 && -m[i] == v) { a++; i--; } + while (j < n && m[j] == v) { b++; j++; } + nb += a * b; + } + } + + free(m); return nb; }