Il trucco della differenza tra numeri di riga
Sottrarre ROW_NUMBER da una sequenza per raggruppare i valori consecutivi in isole
Il trucco della differenza tra numeri di riga è una lezione Coding Interview Prep gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Coding Interview Prep, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Coding Interview Prep include 4 lezioni in totale.
La chiave dell'isola più elegante
Il trucco della differenza tra numeri di riga è la tecnica che gli intervistatori vogliono vedere più spesso per le isole di interi o date consecutivi. Produce la chiave di gruppo con una sola sottrazione, senza bisogno di LAG né di una somma progressiva.
L'idea è molto semplice: sottrarre un ROW_NUMBER al valore stesso. In una sequenza di valori consecutivi, sia il valore sia il numero di riga aumentano esattamente di 1 a ogni passaggio, quindi la loro differenza rimane costante per tutta la sequenza. Questa costante è la chiave dell'isola.
Perché la differenza rimane costante
Consideri due righe adiacenti di una sequenza consecutiva. Passando dall'una all'altra, il valore aumenta di 1 e il numero di riga aumenta di 1. Sottraendoli, gli incrementi di 1 si annullano, quindi value - row_number non cambia.
Ma non appena compare un vuoto, il valore aumenta di più di 1 mentre il numero di riga continua ad aumentare solo di 1. La differenza passa a una nuova costante. È proprio questo cambiamento a separare un'isola dalla successiva.
Osservarlo sui nostri dati
Ricordi i giorni di accesso 1, 2, 3, 7, 8, 10. Disponiamo il numero di riga e la differenza uno accanto all'altra:
- giorno 1, rn 1, diff 0
- giorno 2, rn 2, diff 0
- giorno 3, rn 3, diff 0
- giorno 7, rn 4, diff 3
- giorno 8, rn 5, diff 3
- giorno 10, rn 6, diff 4
Le differenze (0,0,0,3,3,4) suddividono perfettamente le righe nelle tre isole. Stessa differenza significa stessa isola.
SELECT
day_no,
ROW_NUMBER() OVER (ORDER BY day_no) AS rn,
day_no - ROW_NUMBER() OVER (ORDER BY day_no) AS grp
FROM logins
ORDER BY day_no;Raggruppare le righe nelle isole
Usando la differenza come chiave di gruppo, la query finale applica il raggruppamento standard. Racchiuda la differenza in una CTE e applichi GROUP BY a tale valore:
Il risultato restituisce le stesse tre isole di prima, ma l'SQL è più breve e chiaro rispetto alla versione con LAG e somma progressiva. Per sequenze intere o con incrementi regolari, questa è la prima soluzione da prendere in considerazione.
WITH keyed AS (
SELECT
day_no,
day_no - ROW_NUMBER() OVER (ORDER BY day_no) AS grp
FROM logins
)
SELECT
MIN(day_no) AS start_day,
MAX(day_no) AS end_day,
COUNT(*) AS length
FROM keyed
GROUP BY grp
ORDER BY start_day;Il punto critico: i valori devono aumentare di uno
Il semplice trucco della differenza presuppone che la sequenza aumenti di esattamente 1 a ogni passaggio. Questo vale per gli interi densi e per i giorni di calendario consecutivi, ma il metodo non funziona se i valori avanzano di un altro intervallo fisso o se sono presenti duplicati.
- Anche i valori pari 2,4,6,8 sembreranno lacune con una sottrazione tra il valore e il numero di riga.
- I valori duplicati alterano l'allineamento, perché il numero di riga continua ad aumentare mentre il valore resta invariato.
Comprendere questa limitazione e sapere come correggerla è ciò che distingue un trucco imparato a memoria dalla vera comprensione.
Correggere le sequenze a passo fisso
Se i valori avanzano di una costante nota k invece che di 1, li normalizzi prima: divida il valore per k (oppure usi value / k per gli interi), così ogni passaggio torna a essere di 1; quindi sottragga il numero di riga.
Per esempio, per i numeri pari con passo 2, usi day_no / 2 - ROW_NUMBER(). Il valore normalizzato ora cresce di 1 per ogni elemento consecutivo, ripristinando la proprietà della differenza costante.
SELECT
val,
(val / 2) - ROW_NUMBER() OVER (ORDER BY val) AS grp
FROM even_series
ORDER BY val;Applicarlo alle date
Le date sono il caso reale più comune. Le date di calendario non possono essere sottratte direttamente a un numero di riga, quindi converta prima la data in un conteggio di giorni. In Postgres, sottragga una data di riferimento fissa per ottenere un numero intero di giorni, quindi applichi lo stesso trucco.
Poiché due giorni di calendario consecutivi differiscono di 1, la differenza tra il conteggio dei giorni e il numero di riga torna a essere costante all'interno di un'isola.
WITH keyed AS (
SELECT
login_date,
(login_date - DATE '2000-01-01')
- ROW_NUMBER() OVER (ORDER BY login_date) AS grp
FROM daily_logins
)
SELECT MIN(login_date) AS start_date,
MAX(login_date) AS end_date,
COUNT(*) AS days_in_run
FROM keyed GROUP BY grp ORDER BY start_date;Differenze tra date nei diversi dialetti
Il passaggio da data a intero varia a seconda del motore, e gli intervistatori apprezzano la conoscenza dei diversi dialetti:
- Postgres: sottragga un valore letterale di tipo data:
login_date - DATE '2000-01-01'restituisce un intero. - MySQL: usi
DATEDIFF(login_date, '2000-01-01'). - SQL Server: usi
DATEDIFF(day, '2000-01-01', login_date).
Un'alternativa ancora più elegante, disponibile su alcuni motori, consiste nel sottrarre direttamente ROW_NUMBER giorni dalla data usando l'aritmetica degli intervalli, quindi nel raggruppare con GROUP BY per la data di riferimento risultante.
SELECT
login_date,
login_date - (ROW_NUMBER() OVER (ORDER BY login_date)
* INTERVAL '1 day') AS grp_date
FROM daily_logins;Aggiungere partizioni per gruppo
Per ottenere le isole per utente, partizioni il numero di riga per colonna del gruppo. È fondamentale che la chiave del gruppo includa anche la colonna di partizione, perché due utenti diversi possono produrre casualmente lo stesso valore di differenza.
Raggruppi quindi per user_id e per la differenza calcolata. Dimenticare user_id nel GROUP BY finale è un bug sottile che gli intervistatori amano individuare.
WITH keyed AS (
SELECT user_id, day_no,
day_no - ROW_NUMBER()
OVER (PARTITION BY user_id ORDER BY day_no) AS grp
FROM logins
)
SELECT user_id, MIN(day_no) AS start_day,
MAX(day_no) AS end_day, COUNT(*) AS len
FROM keyed
GROUP BY user_id, grp
ORDER BY user_id, start_day;Trucco o LAG: quale scegliere
Ora dispone di due tecniche solide. Scelga consapevolmente:
- Differenza con il numero di riga: è la soluzione più breve e pulita per sequenze di valori con passo uniforme (interi densi, date consecutive). È la prima scelta quando l'adiacenza significa «differisce di una costante».
- LAG più somma progressiva: è più flessibile quando l'adiacenza non corrisponde a un passo numerico fisso, per esempio «stesso stato della riga precedente» o regole personalizzate irregolari.
Durante il colloquio, esponga la scelta e la relativa motivazione: il ragionamento colpisce più della sintassi.
Gestire i duplicati in modo difensivo
Se un valore può ripetersi e si desidera comunque un'unica isola per ogni sequenza consecutiva, elimini prima i duplicati con DISTINCT oppure con un raggruppamento, così il numero di riga si allinea uno a uno con i valori. In alternativa, usi DENSE_RANK invece di ROW_NUMBER, in modo che i valori a pari merito condividano lo stesso rango.
Chieda sempre all'intervistatore se possono verificarsi duplicati; la difesa corretta dipende dal fatto che i duplicati debbano estendere la sequenza oppure essere ignorati al suo interno.
WITH d AS (SELECT DISTINCT day_no FROM logins)
SELECT day_no,
day_no - ROW_NUMBER() OVER (ORDER BY day_no) AS grp
FROM d;Verifica rapida
Si assicuri di aver compreso perché il trucco funziona.
Riepilogo: il trucco della differenza
Ora dispone della chiave più semplice per un'isola:
- Formula chiave:
value - ROW_NUMBER() OVER (ORDER BY value)è costante per ogni sequenza consecutiva. - Raggruppi con
GROUP BYsulla differenza per ottenere inizio, fine e lunghezza. - Per le sequenze a passo fisso, normalizzi prima i valori (dividendoli per il passo).
- Per le date, converta la data in un conteggio intero di giorni tramite la funzione di differenza del dialetto.
- Per gruppo: usi
PARTITION BYper il numero di riga e includa la colonna del gruppo nelGROUP BYfinale. - Gestisca i duplicati con
DISTINCToDENSE_RANK.
Ora spostiamo l'attenzione dalle isole agli spazi vuoti: trovare i gap.
Domande Frequenti
La lezione «Il trucco della differenza tra numeri di riga» è gratuita?
Sì — il testo completo di «Il trucco della differenza tra numeri di riga» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Coding Interview Prep, passa a CoddyKit PRO. Il corso Coding Interview Prep include 4 lezioni in totale.
Cosa imparerò in «Il trucco della differenza tra numeri di riga»?
Sottrarre ROW_NUMBER da una sequenza per raggruppare i valori consecutivi in isole Eserciti Coding Interview Prep con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Coding Interview Prep?
Non è richiesta alcuna esperienza precedente. Coding Interview Prep su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Il trucco della differenza tra numeri di riga»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Coding Interview Prep?
Sì. Ogni lezione Coding Interview Prep include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Riconoscere un problema di gaps-and-islands
- Il trucco della differenza tra numeri di riga
- Trovare le lacune in una sequenza
- Isole con cambi di data e stato