【问题标题】:Hackerrank: Climbing the LeaderboardHackerrank:攀登排行榜
【发布时间】:2019-05-24 22:06:28
【问题描述】:

我与hackerrank algorithm problem 有交易。

它适用于所有情况,但 6-7-8-9 除外。它给出超时错误。我在这个级别上花了很多时间。有人看到问题出在哪里了吗?

static long[] climbingLeaderboard(long[] scores, long[] alice)  
{
    //long[] ranks = new long[scores.Length];
    long[] aliceRanks = new long[alice.Length]; // same length with alice length
    long lastPoint = 0;
    long lastRank;
    for (long i = 0; i < alice.Length; i++)
    {
        lastPoint = scores[0];
        lastRank = 1;
        bool isIn = false; // if never drop in if statement 
        for (long j = 0; j < scores.Length; j++)
        {
            if (lastPoint != scores[j])  //if score is not same, raise the variable
            {
                lastPoint = scores[j];
                lastRank++;
            }

            if (alice[i] >= scores[j])
            {
                aliceRanks[i] = lastRank;
                isIn = true;
                break;
            }
            aliceRanks[i] = !isIn & j + 1 == scores.Length ? ++lastRank : aliceRanks[i]; //drop in here
        }
    }
    return aliceRanks;
}

【问题讨论】:

  • 虽然我鼓励您在业余时间继续进行 Hackerrank 以帮助磨练您的技能,但如果您能更具体地了解您的实际问题会有所帮助。您究竟遇到了什么问题?
  • 还要报告调试器如何帮助或没有帮助您。
  • “它在所有情况下都有效,除了 6-7-8-9”不足以准确解释帖子中的内联问题。 “我正在处理 {link}”不是提出问题/提供有关 SO 详细信息的可接受方式 - 帖子必须包含足够的信息,以便在没有任何链接的情况下独立存在。
  • 您只需要找到一种更有效的方法来确定下一个分数在排名中的位置。您当前拥有的内容将在 n^2 时间内运行,但如果您利用有序的分数,您可以做得更好。
  • 你可以在大约 6 行 linq 中做到这一点,但我不确定你会理解它

标签: c#


【解决方案1】:

这个问题可以在O(n)时间内解决,完全不需要二分查找。首先,我们需要提取问题陈述中给出的最有用的一条数据,即,

现有排行榜得分按降序排列。

Alice 的分数,alice,按升序排列。

一种有用的方法是创建两个指针,一个在 alice 数组的开头,我们称之为“i”,第二个在scores数组的末尾,我们称之为“j em>”。然后我们循环直到 i 到达 alice 数组的末尾,并且在每次迭代中,我们检查三个主要条件.如果 alice[i] 小于 scores[j,我们将 i 加一] 因为alice的下一个元素也可能小于scores的当前元素,或者如果 alice[i] 大于 ,我们就减少 j score[j] 因为我们确信 alice 的下一个元素也大于 中丢弃的那些元素分数。最后一个条件是,如果 alice[i] == scores[j],我们只增加 i

我用 C++ 解决了这个问题,我的目标是让你理解这个算法,我想如果你理解了它,你可以很容易地将它转换为 C#。如果有任何困惑,请告诉我。代码如下:

// Complete the climbingLeaderboard function below.
vector<int> climbingLeaderboard(vector<int> scores, vector<int> alice) {
    int j = 1, i = 1;
    // this is to remove duplicates from the scores vector
    for(i =1; i < scores.size(); i++){
        if(scores[i] != scores[i-1]){
            scores[j++] = scores[i];
        }
    }
    int size = scores.size();
    for(i = 0; i < size-j; i++){
        scores.pop_back();
    }
    vector<int> ranks;

    i = 0;
    j = scores.size()-1;
    while(i < alice.size()){
        if(j < 0){
            ranks.push_back(1);
            i++;
            continue;
        }
        if(alice[i] < scores[j]){
            ranks.push_back(j+2);
            i++;
        } else if(alice[i] > scores[j]){
            j--;
        } else {
            ranks.push_back(j+1);
            i++;
        }
    }

    return ranks;
}

我认为这对你也有帮助:

vector 就像一个可以调整自身大小的数组列表。

push_back() 正在插入向量的末尾。

pop_back() 正在从向量的末尾移除。

【讨论】:

  • 太棒了!我现在通过了 HR 测试,尽管在 Perl 上重新实现了它。我浪费了我的时间,最初用二分搜索找到了错误的树。谢谢!
【解决方案2】:

这是一个使用BinarySearch 的解决方案。此方法返回数组中搜索到的数字的索引,或者如果未找到该数字,则返回一个负数,该负数是数组中下一个元素的索引的按位补码。二分查找仅适用于已排序的数组。

public static int[] GetRanks(long[] scores, long[] person)
{
    var defaultComparer = Comparer<long>.Default;
    var reverseComparer = Comparer<long>.Create((x, y) => -defaultComparer.Compare(x, y));
    var distinctOrderedScores = scores.Distinct().OrderBy(i => i, reverseComparer).ToArray();
    return person
        .Select(i => Array.BinarySearch(distinctOrderedScores, i, reverseComparer))
        .Select(pos => (pos >= 0 ? pos : ~pos) + 1)
        .ToArray();
}

使用示例:

var scores = new long[] { 100, 100, 50, 40, 40, 20, 10 };
var alice = new long[] { 5, 25, 50, 120 };
var ranks = GetRanks(scores, alice);
Console.WriteLine($"Ranks: {String.Join(", ", ranks)}");

输出:

排名:6、4、2、1

【讨论】:

    【解决方案3】:

    这是我的 c# 解决方案

    public static List<int> climbingLeaderboard(List<int> ranked, List<int> player)
        {
                List<int> result = new List<int>();
                ranked = ranked.Distinct().ToList();
                var pLength = player.Count;
                var rLength = ranked.Count-1;
              
                int j = rLength;
                for (int i = 0; i < pLength; i++)
                {               
                    for (; j >= 0; j--)
                    {
                        if (player[i] == ranked[j])
                        {
                            result.Add(j + 1);
                            break;
                        }
                        else if(player[i] < ranked[j])
                        {
                            result.Add(j + 2);
                            break;
                        }
                        else if(player[i] > ranked[j]&&j==0)
                        {
                            result.Add(1);
                            break;
                        }enter code here
                    }
                }
    
                return result;
        }
    

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    【解决方案4】:

    我很无聊,所以我用 Linq 试了一下,并为你重重地评论了它,

    给定

    public static IEnumerable<int> GetRanks(long[] scores, long[] person)
    
       // Convert scores to a tuple
       => scores.Select(s => (scores: s, isPerson: false))
    
                 // convert persons score to a tuple and concat
                .Concat(person.Select(s => (scores: s, isPerson: true)))
    
                 // Group by scores
                .GroupBy(x => x.scores)
    
                 // order by score
                .OrderBy(x => x.Key)
    
                 // select into an indexable tuple so we know everyones rank
                .Select((groups, i) => (rank: i, groups))
    
                 // Filter the person
                .Where(x => x.groups.Any(y => y.isPerson))
    
                 // select the rank
                .Select(x => x.rank);
    

    用法

    static void Main(string[] args)
    {
       var scores = new long[]{1, 34, 565, 43, 44, 56, 67};   
       var alice = new long[]{578, 40, 50, 67, 6};
    
       var ranks = GetRanks(scores, alice);
    
       foreach (var rank in ranks)
          Console.WriteLine(rank);
    
    }
    

    输出

    1
    3
    6
    8
    10
    

    【讨论】:

    • 数组scores按降序排列,数组alice按升序排列。没有正确的排序,预期的输出就不清楚了。
    【解决方案5】:

    基于给定的约束,蛮力解决方案不会有效解决问题。 您必须优化您的代码,这里的关键部分是查找可以通过使用二进制搜索有效完成的确切位置。

    这是使用二分搜索的解决方案:-

    static int[] climbingLeaderboard(int[] scores, int[] alice) {
            int n = scores.length;
            int m = alice.length;
    
            int res[] = new int[m];
            int[] rank = new int[n];
    
            rank[0] = 1;
    
            for (int i = 1; i < n; i++) {
                if (scores[i] == scores[i - 1]) {
                    rank[i] = rank[i - 1];
                } else {
                    rank[i] = rank[i - 1] + 1;
                }
            }
    
            for (int i = 0; i < m; i++) {
                int aliceScore = alice[i];
                if (aliceScore > scores[0]) {
                    res[i] = 1;
                } else if (aliceScore < scores[n - 1]) {
                    res[i] = rank[n - 1] + 1;
                } else {
                    int index = binarySearch(scores, aliceScore);
                    res[i] = rank[index];
    
                }
            }
            return res;
    
        }
    
        private static int binarySearch(int[] a, int key) {
    
            int lo = 0;
            int hi = a.length - 1;
    
            while (lo <= hi) {
                int mid = lo + (hi - lo) / 2;
                if (a[mid] == key) {
                    return mid;
                } else if (a[mid] < key && key < a[mid - 1]) {
                    return mid;
                } else if (a[mid] > key && key >= a[mid + 1]) {
                    return mid + 1;
                } else if (a[mid] < key) {
                    hi = mid - 1;
                } else if (a[mid] > key) {
                    lo = mid + 1;
                }
            }
            return -1;
        }
    

    您可以参考这个link以获得更详细的视频解释。

    【讨论】:

      【解决方案6】:
      static int[] climbingLeaderboard(int[] scores, int[] alice) {
      
            int[] uniqueScores = IntStream.of(scores).distinct().toArray();
      
              int [] rank = new int [alice.length];
      
              int startIndex=0;
      
              for(int j=alice.length-1; j>=0;j--) {
      
      
              for(int i=startIndex; i<=uniqueScores.length-1;i++) {
      
                  if (alice[j]<uniqueScores[uniqueScores.length-1]){
                          rank[j]=uniqueScores.length+1;
                          break;
                      }
      
                  else if(alice[j]>=uniqueScores[i]) {
                          rank[j]=i+1;
                          startIndex=i;
                          break;
                      }
      
                      else{continue;}
      
                  }
          } 
          return rank;
          }
      

      【讨论】:

      • 嗯嗯,下次我会,因为第一次回答,不知道怎么放这里
      • 只需按下代码下方的编辑并添加您想要添加的内容。
      【解决方案7】:

      我在 javascript 中用于攀登排行榜 Hackerrank 问题的解决方案。问题的时间复杂度可以是O(i+j),i是scores的长度,j是alice的长度。空间复杂度为 O(1)。

      // Complete the climbingLeaderboard function below.
      function climbingLeaderboard(scores, alice) {
          const ans = [];
          let count = 0;
          // the alice array is arranged in ascending order
          let j = alice.length - 1;
          for (let i = 0 ; i < scores.length ; i++) {
              const score = scores[i];
              for (; j >= 0 ; j--) {
                  if (alice[j] >= score) {
                      // if higher than score
                      ans.unshift(count+1);
                  } else if (i === scores.length - 1) {
                      // if smallest
                      ans.unshift(count+2);
                  } else {
                      break;
                  }
              }
              
              // actual rank of the score in leaderboard
              if (score !== scores[i-1]) {
                  count++;
              }
          }
          return ans;
      }
      

      【讨论】:

        【解决方案8】:

        我在 Java 中解决排行榜黑客等级问题的解决方案。

            // Complete the climbingLeaderboard function below.
        static int[] climbingLeaderboard(int[] scores, int[] alice) {
          Arrays.sort(scores);
          HashSet<Integer> set = new HashSet<Integer>();
        int[] ar = new int[alice.length];
        int sc = 0;
        
        
          for(int i=0; i<alice.length; i++){
            sc = 1;
            set.clear();
            for(int j=0; j<scores.length; j++){
               if(alice[i] < scores[j] && !set.contains(scores[j])){
                  sc++;
                  set.add(scores[j]);
                }
            }
            ar[i] = sc;
          }return ar;
        
        }
        

        【讨论】:

          猜你喜欢
          • 2020-05-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-05-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多