我们将游戏记录组织如下:
允许玩家在不同级别玩游戏,并保持高分榜以显示前10名游戏记录列表。高分表上的每个游戏记录包含一组属性,例如,玩家的名字,获得的总分和获得分数的等级。游戏记录列表通常从最高得分到最低得分,表示从最高到最低等级的玩家等级。
我们必须实施
public GameRecord[] updateGameRecords(GameRecord[] oldRecords, GameRecord newRecord)
以下列方式:
如果与newRecord具有相同级别的记录数小于10 ,则我们在oldRecords中插入新记录并对其进行排序然后将其返回。否则,请转到到第3步。
如果有任何记录与newRecord处于同一级别的得分较差,那么我们将该级别的得分最低的记录替换,因为给定级别的记录数不能超过10,然后我们排序并返回oldRecords
到目前为止,这是我的代码:
public GameRecord[] updateGameRecords(GameRecord[] oldRecords, GameRecord newRecord) {
int index = -1, r = 0;
boolean break_loop = false, same_name_level = false;
for (int i = 0; i < oldRecords.length; ++i) {
while (i < oldRecords.length && newRecord.getLevel() < oldRecords[i].getLevel()) {
++i;
continue;
}
while (i < oldRecords.length && i < oldRecords.length && newRecord.getLevel() == oldRecords[i].getLevel()) {
if (r == 0)
index = i;
++r;//r is number of records with same level
if (!break_loop && newRecord.getName().equals(oldRecords[i].getName())) {
same_name_level = true;
break_loop = true;
if (newRecord.getScore() > oldRecords[i].getScore()) {
oldRecords[i].setScore(newRecord.getScore());
}
}
++i;
}
if (break_loop == true)
break;
}
if (break_loop == true) {
Util.sort(oldRecords);
return oldRecords;
}
if (r > 0 && r < 10 && same_name_level == false) {
GameRecord[] temp = oldRecords.clone();
oldRecords = new GameRecord[oldRecords.length + 1];
System.arraycopy(temp, 0, oldRecords, 0, temp.length);
oldRecords[temp.length] = newRecord;
Util.sort(oldRecords);
return oldRecords;
}
if (r == 10) {
if (oldRecords[index + 9].getScore() < newRecord.getScore())
oldRecords[index + 9].setScore(newRecord.getScore());
Util.sort(oldRecords);
return oldRecords;
}
if (r == 0) {
GameRecord[] temp = oldRecords.clone();
oldRecords = new GameRecord[oldRecords.length + 1];
System.arraycopy(temp, 0, oldRecords, 0, temp.length);
oldRecords[temp.length] = newRecord;
Util.sort(oldRecords);
return oldRecords;
} else
return oldRecords;
}
它工作正常,但这是线性时间复杂度代码,它需要O(oldRecords.length)+ 时间由Util.sort()功能,这使得总运行时间非线性。
你能建议我一个线性时间算法。
答案 0 :(得分:2)
要在插入或更新记录时维护排序列表,不必再次对整个列表进行排序;将此记录移动到适当的位置就足够了。此外,因为我们从不改变等级,只增加分数,我们知道这个记录只会向上移动。
也就是说,在完成插入或更新记录之后,我会调用以下方法:
void moveToProperPlace(GameRecord[] records, int index) {
int newIndex = findCorrectIndex(records, index);
if (newIndex != index) {
GameRecord record = records[index];
System.arrayCopy(records, newIndex, records, newIndex + 1, index - newIndex);
records[newIndex] = record;
}
}
int findCorrectIndex(records, index) {
int i = index;
do {
i--;
} while (i >= 0 && higher(records[index], records[i]);
return i + 1;
}
boolean higher(GameRecord x, GameRecord y) {
return x.getScore() > y.getScore() || (x.getScore() == y.getScore && x.getLevel() > y.getLevel());
}
由于预分类数据很常见,如果检测到数据几乎已排序,那么标准库中设计良好的排序实现可能实际上会回退到这样的插入排序,为只有常数的输入提供O(n)排序元素数量在错误的位置,否则为O(n log n)。特别是,java.util.Arrays.sort
和java.util.Collections.sort
以这种方式实现。如果您的Util.sort
也是这样实现的,那么您的算法已经是O(n)。
在任何情况下,除非你每秒要记录数千个级别和数百万个游戏,否则O(n)和O(n log n)之间的差异不太可能对执行时间产生显着影响。你的计划。
答案 1 :(得分:0)
O(n)解决方案是:
static final int MAX = 10;
static void bubbling(int[] recs) {
for (int i = recs.length - 1; i > 0; --i)
if (recs[i] > recs[i - 1]) {
int temp = recs[i];
recs[i] = recs[i - 1];
recs[i - 1] = temp;
}
}
static int[] updateRecord(int[] oldRecs, int newRec) {
int oldLen = oldRecs.length;
int newLen = oldLen < MAX ? oldLen + 1 : MAX;
int[] newRecs = new int[newLen];
System.arraycopy(oldRecs, 0, newRecs, 0, oldLen);
if (newLen > oldLen || newRec >= newRecs[newLen - 1]) {
newRecs[newLen - 1] = newRec;
bubbling(newRecs);
}
return newRecs;
}
GameRecord
更改为int
以简化问题。