Skip to content

Instantly share code, notes, and snippets.

@matyax
Created May 29, 2021 19:56
Show Gist options
  • Save matyax/885258295f6ca8c609b3c382e45ecd82 to your computer and use it in GitHub Desktop.
Save matyax/885258295f6ca8c609b3c382e45ecd82 to your computer and use it in GitHub Desktop.
Solución: Climbing the Leaderboard

Solución: Climbing the Leaderboard

URL: https://www.hackerrank.com/challenges/climbing-the-leaderboard/problem

Lo había intentado antes y me había trabado siempre en el mismo lugar: timeout con inputs grandes. Probé casi las mismas "optimizaciones" que antes ("cache", pseudo búsqueda binaria) pero siempre daba timeout. Finalmente me inspiré: las posiciones en la tabla equivalen al índice del array de puntajes ordenado de manera decreciente, más uno.

TL;DR: el problema no era complejo, solamente había que eliminar los puntajes duplicados para tener rápidamente la tabla de puntajes "calculada", o calculable.

function climbingLeaderboard(ranked, player) {
    ranked.sort((a, b) => b - a);
    ranked = ranked.filter((value, index) => index > 0 ? (value !== ranked[index - 1]) : true);
    
    const rankedLength = ranked.length;
    
    const cache = {};

    return player.map(score => {
        if (cache[score]) {
            return cache[score];
        }
        
        if (score > ranked[0]) {
            cache[score] = 1;
            return cache[score];
        }
        
        if (score < ranked[rankedLength - 1]) {
            cache[score] = rankedLength + 1;
            
            return cache[score];
        }
        
        let start = 0;
        let middle = Math.round(rankedLength / 2);
        
        while (ranked[middle] > score) {
            start = middle;
            middle += Math.round(middle / 2);
        }
        
        for (let i = start; i < rankedLength; i++) {
            if (ranked[i] <= score) {
                cache[score] = i + 1;
                
                return cache[score];
            }
        }
    });
}

En limpio, el algoritmo sería así:

function climbingLeaderboard(ranked, player) {
    ranked.sort((a, b) => b - a);
    ranked = ranked.filter((value, index) => index > 0 ? (value !== ranked[index - 1]) : true);
    
    const rankedLength = ranked.length;

    return player.map(score => {
        if (score > ranked[0]) {
            return 1;
        }
        
        if (score < ranked[rankedLength - 1]) {
            return rankedLength + 1;
        }
        
        for (let i = 0; i < rankedLength; i++) {
            if (ranked[i] <= score) {
                return i + 1;
            }
        }
    });
}

Si bien es relativamente eficiente, requiere de las optimizaciones de la versión anterior para pasar todos los inputs sin timeout.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment