优化以下hackerrank计划

时间:2017-10-01 12:55:09

标签: c algorithm data-structures linked-list

我想优化以下代码,以便在hackerrank问题中传递所有测试用例。它目前有效但由于超时而导致某些情况失败。您能否指导我如何在不改变概念的情况下优化代码?

问题

  

爱丽丝正在玩街机游戏,想要爬到排行榜的顶端。   她能帮助她追踪每个级别的排名吗?游戏使用密集排名,因此其排行榜的工作方式如下:

     

•得分最高的玩家是排行榜上的排名。

     

•得分相同的玩家获得相同的排名,下一位玩家将获得紧随其后的排名。

     

例如,四名球员的得分分别为100分,90分,90分和80分。这些球员的得分分别为1,2,3和3。

     

当Alice开始播放时,排行榜上已有n人。 Alice为m级别玩,我们在通过每个级别后表示她的总得分。完成每个级别后,Alice想知道她目前的等级。

     

您将获得一系列单调递减的排行榜得分,以及每个级别的游戏的另一个Alice累积得分数组。你必须打印整数:整数应该表示通过每个级别后Alice的当前排名。

     

输入格式:

     
      
  • 第一行包含一个整数n,表示排行榜上已有的玩家数量。
  •   
  • 下一行包含n以空格分隔的整数,用于描述其分数的相应值。
  •   
  • 下一行包含一个整数m,表示Alice击败的等级数。
  •   
  • 最后一行包含m以空格分隔的整数,用于描述每个玩家的各自值。
  •   
     

输出格式:

     

打印整数。通过每个级别后,整数应指示Alice的等级。

INPUT

7
100 100 50 40 40 20 10
4
5 25 50 120

输出

6
4
2
1

这是我的代码:

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct player {
    int rank;
    int score;
};

struct node {
    struct player data;
    struct node *next;
};

int main() {
    int n, i, m, temp, count = 1, x;
    struct node *ptr, *head;
    head = (struct node *)malloc(sizeof(struct node));
    ptr = head;
    scanf("%d", &n);
    for (i = 0; i < n; i++) {
        scanf("%d", &x);
        ptr->data.score = x;
        if (x < temp)
            count++;
        ptr->data.rank = count;
        temp = ptr->data.score;
        ptr->next = (struct node *)malloc(sizeof(struct node));
        ptr = ptr->next;
    }
    ptr = NULL;
    ptr = head;
    scanf("%d", &m);
    for (i = 0; i < m; i++) {
        scanf(" %d", &x);
        while (x < ptr->data.score)
            ptr = ptr->next;
        if (ptr->next == NULL)
            ptr->data.rank = count + 1;
        printf("%d\n", ptr->data.rank);
        ptr = head;
    }
    return 0;
}

问题在于,每次我取出Alice的排名时,我都会从头开始遍历链表。对此可能有什么优化?

2 个答案:

答案 0 :(得分:2)

反转代表排行榜的列表,使排行榜单调增加。如果以这种方式订购排行榜,您只需要从最后一个位置开始遍历排行榜。即为您的示例 - 输入:

10/5    20/4    40/3    40/3     50/2     100/1     100/1           leaderboard
5               25               50                           120   score
6               4                2                            1     pos

作为伪代码:

node n = leaderboard.reverse().head

foreach score in scorelist:
    while n != null and n.score > score
        n = n.next

    if n == null:
        print 1
    else:
        print n.pos - 1

这是有效的,因为根据排行榜中score[i]的位置(l[j]),我们知道score[i + 1]必须位于l[j + x],其中x > 0在反向排行榜中。

答案 1 :(得分:0)

您的代码中存在未定义的行为,因为您未初始化temp变量:第一个比较if (x < temp)具有未定义的行为,因此count可能会错误地增加。

保罗的方法是一个非常好的解决方案,可以将复杂性从 O(N 2 降低到 O(N)

以下是修改后的代码:

#include <stdio.h>
#include <stdlib.h>

struct node {
    int rank;
    int score;
    struct node *next;
};

int main(void) {
    int n, i, m, last = 0, rank = 1, x;
    struct node *ptr, *head = NULL;
    if (scanf("%d", &n) != 1)
        return 1;
    for (i = 0; i < n; i++) {
        ptr = malloc(sizeof(*ptr));
        if (ptr == NULL)
            return 1;
        if (scanf("%d", &ptr->score) != 1)
            return 1;
        if (ptr->score < last)
            rank++;
        ptr->rank = rank;
        last = ptr->score;
        ptr->next = head;
        head = ptr;
    }
    if (scanf("%d", &m) != 1)
        return 1;
    for (ptr = head, i = 0; i < m; i++) {
        if (scanf(" %d", &x) != 1)
            return 1;
        while (ptr && x > ptr->score)
            ptr = ptr->next;
        if (ptr == NULL)
            rank = 1;
        else
        if (x == ptr->score)
            rank = ptr->rank;
        else
            rank = ptr->rank + 1;
        printf("%d\n", rank);
    }
    return 0;
}