0Pricing
Coding Interview Prep · Aula

O truque da diferença de números de linha

Subtraia ROW_NUMBER de uma sequência para agrupar valores consecutivos em ilhas.

O truque da diferença de números de linha é uma aula grátis de Coding Interview Prep no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Coding Interview Prep, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Coding Interview Prep inclui 4 aulas no total.

A chave de ilha mais elegante

O truque da diferença entre números de linha é a técnica que os entrevistadores mais querem ver para ilhas de inteiros ou datas consecutivos. Ele produz a chave de grupo com uma única subtração, sem LAG nem soma acumulada.

A ideia completa é: subtraia um ROW_NUMBER do próprio valor. Em qualquer sequência de valores consecutivos, tanto o valor quanto o número da linha aumentam exatamente 1 a cada passo; portanto, a diferença é constante em toda a sequência. Essa constante é a chave da sua ilha.

Por que a diferença permanece constante

Pense em duas linhas adjacentes dentro de uma sequência consecutiva. Ao passar de uma para a seguinte, o valor aumenta 1 e o número da linha aumenta 1. Ao subtraí-los, os dois +1 se anulam, portanto value - row_number não muda.

Mas, no momento em que há uma lacuna, o valor aumenta mais de 1, enquanto o número da linha continua aumentando apenas 1. A diferença muda para uma nova constante. Essa mudança é exatamente o que separa uma ilha da seguinte.

Observando nossos dados

Relembre os dias de login 1, 2, 3, 7, 8, 10. Vamos colocar o número da linha e a diferença lado a lado:

  • dia 1, rn 1, diff 0
  • dia 2, rn 2, diff 0
  • dia 3, rn 3, diff 0
  • dia 7, rn 4, diff 3
  • dia 8, rn 5, diff 3
  • dia 10, rn 6, diff 4

As diferenças (0,0,0,3,3,4) particionam perfeitamente as linhas nas três ilhas. O mesmo valor de diff significa a mesma ilha.

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;

Agrupando em ilhas

Com a diferença como chave de grupo, a consulta final é o agrupamento padrão. Envolva a diferença em uma CTE e faça GROUP BY por ela:

Isso retorna as mesmas três ilhas de antes, mas o SQL é mais curto e claro do que a versão com LAG e soma acumulada. Para sequências de inteiros ou com passos uniformes, esta é a primeira resposta que você deve considerar.

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;

A armadilha: os valores devem avançar de um em um

A técnica da diferença simples pressupõe que a sequência aumente exatamente 1 a cada passo. Isso vale para inteiros densos e dias consecutivos do calendário, mas deixa de funcionar se os valores avançarem por outro intervalo fixo ou se houver duplicatas.

  • Até mesmo os valores pares 2,4,6,8 parecerão lacunas para uma subtração do valor pelo número da linha.
  • Valores duplicados desalinhariam os resultados, porque o número da linha continua aumentando enquanto o valor não muda.

Compreender essa limitação e saber corrigi-la é o que diferencia uma técnica decorada de um entendimento real.

Corrigindo sequências de passo fixo

Se os valores avançarem por uma constante conhecida k em vez de 1, normalize-os primeiro: divida o valor por k (ou use value / k para inteiros) para que cada passo volte a ser 1 e, em seguida, subtraia o número da linha.

Por exemplo, para números pares que avançam de 2 em 2, use day_no / 2 - ROW_NUMBER(). O valor normalizado agora aumenta 1 a cada item consecutivo, restaurando a propriedade da diferença constante.

SELECT
  val,
  (val / 2) - ROW_NUMBER() OVER (ORDER BY val) AS grp
FROM even_series
ORDER BY val;

Aplicando isso a datas

As datas são o caso real mais comum. Não é possível subtrair datas diretamente de um número de linha; portanto, converta a data em uma contagem de dias primeiro. No Postgres, subtraia uma data-âncora fixa para obter um número inteiro de dias e então aplique a mesma técnica.

Como dias consecutivos do calendário diferem em 1, a diferença entre a contagem de dias e o número da linha volta a ser constante dentro de uma ilha.

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;

Diferença de datas entre dialetos

A etapa de converter uma data em inteiro varia conforme o mecanismo, e os entrevistadores valorizam a familiaridade com diferentes dialetos:

  • Postgres: subtraia um literal de data: login_date - DATE '2000-01-01' produz um inteiro.
  • MySQL: use DATEDIFF(login_date, '2000-01-01').
  • SQL Server: use DATEDIFF(day, '2000-01-01', login_date).

Uma alternativa ainda mais elegante em alguns mecanismos é subtrair diretamente da data os dias indicados por ROW_NUMBER, usando aritmética de intervalos, e depois usar GROUP BY na data-âncora resultante.

SELECT
  login_date,
  login_date - (ROW_NUMBER() OVER (ORDER BY login_date)
               * INTERVAL '1 day') AS grp_date
FROM daily_logins;

Adicionando partições por grupo

Para obter ilhas por usuário, particione o número da linha pela coluna do grupo. É essencial que a chave do grupo também inclua a coluna de partição, porque dois usuários diferentes podem produzir coincidentemente o mesmo valor de diferença.

Portanto, use GROUP BY tanto em user_id quanto na diferença calculada. Esquecer user_id no GROUP BY final é um erro sutil que os entrevistadores adoram identificar.

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;

Técnica versus LAG: qual usar

Agora você tem duas técnicas sólidas à sua disposição. Escolha de forma consciente:

  • Diferença entre números de linha: é a opção mais curta e limpa para sequências de valores com passos uniformes (inteiros densos e datas consecutivas). É a primeira escolha quando adjacência significa “difere por uma constante”.
  • LAG mais soma acumulada: é mais flexível quando a adjacência não corresponde a um passo numérico fixo, por exemplo, “tem o mesmo estado da linha anterior” ou segue regras personalizadas e irregulares.

Explique sua escolha e o motivo durante a entrevista; o raciocínio impressiona mais do que a sintaxe.

Tratando duplicatas com segurança

Se um valor puder se repetir e você ainda quiser uma ilha por sequência consecutiva, remova as duplicatas primeiro com DISTINCT ou com uma etapa de agrupamento, para que o número da linha se alinhe individualmente aos valores. Outra opção é usar DENSE_RANK em vez de ROW_NUMBER, fazendo com que valores empatados compartilhem a mesma posição.

Sempre pergunte ao entrevistador se podem ocorrer duplicatas; a proteção adequada depende de elas deverem estender a sequência ou ser ignoradas dentro dela.

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ção rápida

Certifique-se de entender por que a técnica funciona.

Recapitulando: a técnica da diferença

Agora você domina a chave de ilha mais simples:

  • Fórmula da chave: value - ROW_NUMBER() OVER (ORDER BY value) é constante em cada sequência consecutiva.
  • Use GROUP BY na diferença para obter início, fim e duração.
  • Para sequências de passo fixo, normalize os valores (dividindo-os pelo passo) primeiro.
  • Para datas, converta-as em uma contagem inteira de dias usando a função de diferença do dialeto.
  • Por grupo: use PARTITION BY no número da linha e inclua a coluna do grupo no GROUP BY final.
  • Proteja-se contra duplicatas com DISTINCT ou DENSE_RANK.

Agora mudaremos o foco das ilhas para os espaços vazios: encontrar lacunas.

Perguntas Frequentes

A aula “O truque da diferença de números de linha” é grátis?

Sim — o texto completo de “O truque da diferença de números de linha” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Coding Interview Prep, atualize para CoddyKit PRO. O curso de Coding Interview Prep inclui 4 aulas no total.

O que vou aprender em “O truque da diferença de números de linha”?

Subtraia ROW_NUMBER de uma sequência para agrupar valores consecutivos em ilhas. Você pratica Coding Interview Prep com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Coding Interview Prep?

Nenhuma experiência prévia é necessária. Coding Interview Prep no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “O truque da diferença de números de linha”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Coding Interview Prep?

Sim. Cada aula de Coding Interview Prep inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Reconhecendo um problema de lacunas e ilhas
  2. O truque da diferença de números de linha
  3. Encontrando lacunas em uma sequência
  4. Ilhas com mudanças de data e status
← Voltar para Coding Interview Prep