【问题标题】:Lowering Time Complexity of Producing Rank Array降低生成秩数组的时间复杂度
【发布时间】:2014-03-30 10:06:43
【问题描述】:

public Ranking(String[] names, float[] scores) { nameTest = 新城市[names.length]; rankTest = 新城市[names.length]; 城市 = 新城市 [names.length]; scoreRanks = new Float[scores.length]; for (int i = 0; i

        for (int p = 0; p < scoreRanks.length; p++) {
            scoreRanks[p] = scores[p];
        }
        int[] ranking = new int[names.length];
        for (int k = 0; k < ranking.length; k++) {
            ranking[this.smallestIndex()] = k + 1;
        }
        for (int i = 0; i < ranking.length; i++) {
            city[i] = new Cities(names[i], ranking[i]);
            nameTest[i] = new Cities(names[i], ranking[i]);
            rankTest[i] = new Cities(names[i], ranking[i]);
        }
        Arrays.sort(nameTest, Cities.BY_NAME);
        Arrays.sort(rankTest, Cities.BY_RANK);
        for (int i = 0; i < names.length - 1; i++) {
            if (nameTest[i].getName().equals(nameTest[i + 1].getName())
                    || nameTest[i].getName() == null
                    || rankTest[i].getRank() == rankTest[i + 1].getRank())
                throw new IllegalArgumentException();
        }
    }

    public int smallestIndex() {
        float smallest = 0.0f;
        int i;
        for (i = 0; i < scoreRanks.length; i++) {
            if (scoreRanks[i] > 0.0f) {
                smallest = scoreRanks[i];
                break;
            } else
                continue;
        }
        int j = 1;
        while (j < scoreRanks.length) {
            if (scoreRanks[j] < smallest && scoreRanks[j] != 0.0f) {
                smallest = scoreRanks[j];
                i = j;
            }
            j++;
        }
        scoreRanks[i] = 0.0f;
        return i;
    }

这是我的排名构造函数。目前,在 for 循环中对 minimumIndex() 的调用将其提高到 O(n^2) 时间,但我需要它在不超过 O(n log n) 时间内运行。

它的作用是获取一组分数和名称。然后得分最低的位置将是排名 1,次低的位置是排名 2,依此类推。然后我可以创建 Cities 对象,其中 names[i] 对应于ranking[i]。

希望这是有道理的。买是的,但在 O(n log n) 时间内,我无法获得相同的结果。我的代码完美运行,我猜它太慢了:(。

另外,O(2n log n + 5n) 会归结为 O(n log n) 吗?

【问题讨论】:

  • 1.什么是原始问题? 2. 是的,O(2n log + 5n) = O(n logn)

标签: java algorithm sorting rank


【解决方案1】:

根据您的描述,基本上您希望根据分数的增加对列表进行排序。检查smallestIndex 中的代码,您似乎确实在以一种非常低效的方式执行此操作。如果我们要保留该方法,我建议将scoreRanks[i] = 0.0f 更改为scoreRanks[i] = Float.MAX_VALUE 并通过循环一次来简化方法。

但为了有效地完成任务,我建议完全删除 smallestIndex。我看到您已经在使用 Arrays.sort 和自定义比较器。只需使用相同的方法,您就可以有效地解决您的任务。您可以按照此问题中的说明创建自定义比较器:Get the indices of an array after sorting?

class ArrayIndexComparator implements Comparator<Integer>
{
    private Float[] scores;

    public ArrayIndexComparator(float[] scores)
    {
        this.scores = new Float[scores.length];
        for(int i=0; i<scores.length; i++){
            this.scores[i] = scores[i];
        }
    }

    public Integer[] createIndexArray()
    {
        Integer[] indexes = new Integer[scores.length];
        for (int i = 0; i < scores.length; i++)
        {
            indexes[i] = i;
        }
        return indexes;
    }

    @Override
    public int compare(Integer index1, Integer index2)
    {
        // Autounbox from Integer to int to use as array indexes
        return scores[index1].compareTo(scores[index2]);
    }

    public static void main(String[] args){
        float[] scoreRanks = new float[]{2.0f,3.0f,1.0f};
        ArrayIndexComparator comparator = new ArrayIndexComparator(scoreRanks);
        Integer[] indexes = comparator.createIndexArray();
        Arrays.sort(indexes, comparator);
        int[] ranking = new int[indexes.length];
        for (int i = 0; i < ranking.length; i++) {
            ranking[indexes[i]] = i + 1;
        }
        for (int i = 0; i < ranking.length; i++){
            System.out.println(ranking[i]+" "+scoreRanks[i]);
        }
        // Will print:
        // 2.0 2
        // 3.0 3
        // 1.0 1
    }
}

public Ranking(String[] names, float[] scores) {
    nameTest = new Cities[names.length];
    rankTest = new Cities[names.length];
    city = new Cities[names.length];
    scoreRanks = new Float[scores.length];
    for (int i = 0; i < scores.length - 1; i++) {
        if (scores[i] == scores[i + 1])
            throw new IllegalArgumentException();
    }
    if (names == null || scores == null)
        throw new NullPointerException();
    if (names.length != scores.length)
        throw new IllegalArgumentException();
    for (int p = 0; p < scoreRanks.length; p++) {
        scoreRanks[p] = scores[p];
    }
    // This is the updated part
    ArrayIndexComparator comparator = new ArrayIndexComparator(scoreRanks);
    Integer[] indexes = comparator.createIndexArray();
    Arrays.sort(indexes, comparator);
    int[] ranking = new int[indexes.length];
    for (int i = 0; i < ranking.length; i++) {
        ranking[indexes[i]] = i + 1;
    }
    // Up until this part
    for (int i = 0; i < ranking.length; i++) {
        city[i] = new Cities(names[i], ranking[i]);
        nameTest[i] = new Cities(names[i], ranking[i]);
        rankTest[i] = new Cities(names[i], ranking[i]);
    }
    Arrays.sort(nameTest, Cities.BY_NAME);
    Arrays.sort(rankTest, Cities.BY_RANK);
    for (int i = 0; i < names.length - 1; i++) {
        if (nameTest[i].getName().equals(nameTest[i + 1].getName())
                || nameTest[i].getName() == null
                || rankTest[i].getRank() == rankTest[i + 1].getRank())
            throw new IllegalArgumentException();
    }
}

这样你将使用Arrays类中的排序方法,即O(n log n)。

【讨论】:

  • 嗯...但这不是将ranking[]数组排序为[1,2,3,4,...]吗?因为问题是我做不到。 score[] 数组不能排序,ranking[] 也不能。城市对象可以晚一些,但数组必须与各自的字符串匹配,因此无法排序。
  • 不,这将提供与您的方法相同的 ranking 数组。 Arrays.sort 将根据分数对分数的 index 进行排序。所以在我上面的测试用例中(我添加了一个测试用例),indexes数组将是{2, 0, 1},指的是scores[2]是最小的,scores[0]是第二小的,scores[1]是最大的。那么它与你的smallestIndex 方法基本相同,只是结果已经在一个数组中,而不是调用方法n 次。你可以检查ranking的结果,看看是否正确。
  • Ermahgerd 就像黑魔法!非常感谢!它像梦一样工作,只是将我的复杂性从 O(n^2) 降低到 O(n log n)!
  • 很高兴有帮助 =)。只是要指出,这不是梦想,而是现实。实际上,如果您能接受这个答案,它将对我和其他人有所帮助,因此寻找排名排序的人可以找到这个已回答的问题 =D(如果您喜欢,也可以投票)
猜你喜欢
  • 2011-06-15
  • 2017-02-20
  • 2012-07-28
  • 2016-10-07
  • 2020-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多