【问题标题】:Merge n lists and sort data maintaining original order/constraint合并 n 个列表并对数据进行排序,保持原始顺序/约束
【发布时间】:2019-07-18 04:43:55
【问题描述】:

我在编码比赛中遇到了以下问题。我尝试了很多,但一个私人测试用例总是以错误的答案对我来说失败,我无法弄清楚为什么我的下面的方法会失败。我没有天真的解决方案来生成压力测试用例并进行比较。此外,不会发表社论。 所以,如果可能的话,我正在寻找有人指出我方法中的缺陷。

以下是对问题的详细描述以及我到目前为止所做的尝试。

问题: 有多个地区,根据学生在各自地区的排名,您将获得每个地区的学生分数。 例如:

Region1:
StudentName, Score
A,           50.0
B,           60.0  
C,           40.0 

Region2:
StudentName, Score
D,           30.0
E,           10.0
F,           20.0 

在上面的数据中,学生A在Region1中排名第1,B在Region1中排名第2,C在Region1中排名第3。 同理,D在Region2中有Rank1,E有Rank2,F有Rank3。

  • 学生在同一区域内的分数可能较低,但仍具有较高的排名。例如,A 在 Region1 中的排名优于 B,即我们应该假设每个区域的数据已经按照排名进行了排序。

我们的任务是合并所有区域的数据并创建一个根据分数排名的全局数据。约束条件是,任何在该地区排名较低的学生仍然不能高于该地区其他学生的排名,这些学生在原始地区数据中的排名高于它。

例如:

Region1:
A, 50.0
B, 60.0
C, 40.0 

Region2:
D, 30.0
E, 10.0
F, 20.0

将被合并到:

A, 50.0
B, 60.0
C, 40.0 
D, 30.0
E, 10.0
F, 20.0

顺序没有根据分数改变,因为 B 将始终低于 A,F 将始终低于 E,根据其区域的限制。

其他测试用例:

Region1:
A, 50.0
B, 60.0
C, 70.0 

Region2:
D, 30.0
E, 20.0
F, 10.0

再次按照 A,B,C,D,E,F 的顺序产生结果

Region1:
A, 60.0
B, 80.0
C, 100.0 

Region2:
D, 70.0
E, 90.0
F, 110.0

将导致: D、E、F、A、B、C

但是,

Region1:
A, 11.5
B, 8.5
C, 10.0 

Region2:
D, 12.0
E, 9.0
F, 9.5

将导致:

D, 12.0
A, 11.5
E, 9.0 
B, 8.5
C, 10.0
F, 9.5

Constraints:
1<=number of regions<=6
score can be upto 7 decimal places

我的方法是将所有输入数据添加到一个列表中并保持稳定的排序,即如果两个学生的区域相同,则比较他们在区域中的排名,否则比较分数。

static class Student implements Comparable<Student>
{
String name;
double score;
int zone;
int rank;

//constructor

public int compareTo(Student o)
{
if(this.zone == o.zone)
{
//lower i.e. better rank
return Integer.compare(this.rank, o.rank);
}
//higher i.e. better score
return Double.compare(o.score, this.score);
}

}

main()
{
//read data from console input into an ArrayList<Student> students
Collections.sort(students);
//print each student from students

}

问题没有提到两个学生在不同区域的分数是否相等。在这种情况下,我尝试使用他们各自在区域中的排名来打破平局,但私人测试用例一直失败。我最初认为该问题可能缺少一些信息,但我在竞赛仪表板中看到许多成功提交此问题的信息。这就是我相信我遗漏了一些东西的原因,这个问题并不像我想的那么简单。但是,我无法提出一个测试用例来验证这个假设。

谢谢!

【问题讨论】:

  • 抱歉,没有公开链接
  • @ruakh 这个问题是有道理的,但令人困惑;在我理解它之前,我必须阅读它几次。但是,我不清楚的是,在区域内强加部分排序是否会导致合并列表的唯一结果。换句话说,这里描述的约束可能不会强加一个总排序。
  • 我提供了如此详细的问题描述、测试用例、我的方法和所有其他内容,但仍然被否决:( 没有什么能帮助你摆脱悲观情绪有时
  • @StuartMarks 评论中的“独特结果”是什么意思?
  • @Stacky 这就是我的意思。在我给出的例子中,A > B, B > C, C > A。你的排序关系不是传递的,这意味着你不能用它来排序。

标签: java algorithm sorting merge comparator


【解决方案1】:

据我了解,要求是根据分数对学生进行排序,但附加限制是保留区域内学生的相对顺序。

鉴于问题中列出的示例之一的输入数据,

Region1:
A, 11.5
B, 8.5
C, 10.0 

Region2:
D, 12.0
E, 9.0
F, 9.5

仅按分数排序会得出以下结果:DACFEB。

但是,关于在区域内保持相对排序的约束需要以下部分排序 A

OP 将这个特定示例的解决方案称为 DAEBCF。在关于这个问题的 cmets 中,我为此示例提出了另外两种可能的解决方案:DABCEF 和 DAEFBC。我没有看到任何标准可以让我们决定哪些可能的解决方案是正确的。因此,该问题受到了不足的约束。人们可以争论这些解决方案中的哪一个比其他解决方案更可取,但这样做会引入新的限制,而这些限制在原始问题中并不明显。

鉴于存在满足问题中所有标准的多个解决方案,这意味着该域中的值没有全排序。此外,鉴于正确的 Comparator 必须对其域的值进行总排序,因此不可能为该域编写适当的 Comparator。

当然,可以编写一个具有某些行为的正确比较器,并且它会优先选择这些可能的解决方案中的一个。这样做将隐含地实施不属于问题陈述的其他约束。事实上,Vincent van der Weele 似乎已经这样做了。语句“下一个空白点必须由其中一个区域的排名最高的剩余元素填充。哪个?得分最高的那个”引入了附加约束。它导致了 OP 建议的排序 DAEBCF。虽然这是明智的,但它必然是“正确”的顺序。

另一种算法可能如下。 1)从一个空的结果列表开始,并按排名顺序维护来自每个区域的学生列表。 2) 找出剩下的得分最高的学生。 3) 取该学生和同一区域内排名较高的学生,并将它们附加到结果中,保持相对顺序。 4) 重复直到没有学生留下。

将此算法应用于 DABCEF 中的示例输入结果。这是明智的,但方式不同。同样,我们不知道这是否是“正确”的答案。

要么是编程竞赛中的问题一开始就没有明确说明,要么是竞赛的问题陈述与 Stack Overflow 上 OP 的问题之间丢失了一些信息。

【讨论】:

  • 感谢您的详细回答。 “当然,可以编写一个具有某些行为的正确比较器,并且它会更喜欢这些可能的解决方案之一而不是其他解决方案。” - 你能推荐一个这样的比较器吗?显然,我写的那个甚至在倒数第二个测试用例中也失败了。它给了我 A,B,C,D,E,F 而不是 D,E,F,A,B,C。所以,它不满足任何“排序”。
  • @Stacky Vincent van der Weele 和我都描述了在给定各种不同规则的情况下生成排序的算法。但是,编写与这些算法具有等效排序的 比较器 有点微妙。我可能需要一些时间才能完成。
  • Stuart Marks,我一直在阅读有关传递性的文章,正如您、@njzk2 和其他人所描述的,倒数第二个测试用例表明我的比较器不是传递性的。我想知道为什么 Collections.sort 没有抛出异常说“比较方法违反其一般合同”,如以下问题所述。我认为 jvm 不保证例外。我什至尝试在多个随机输入上运行比较器,但没有产生异常。 stackoverflow.com/questions/21843689/…
【解决方案2】:

您的比较器不正确。您基本上说,如果学生来自同一地区,则按排名排序,否则按分数排序。但事实并非如此,如本例所示:

Region1:
A, 11.5
B, 8.5
C, 10.0 

Region2:
D, 12.0
E, 9.0
F, 9.5

结果

D, 12.0
A, 11.5
E, 9.0 
B, 8.5
C, 10.0
F, 9.5

即,得分为 9.0 的 E 排在得分为 10.0 的 C 之前,即使他们来自不同的地区。


一个更简单的有效算法:

逐个元素填充结果。下一个空位必须由其中一个区域中排名最高的剩余元素填充。哪一个?得分最高的那个。因此,从其区域中删除该元素,将其添加到结果中,然后重复直到完成。

【讨论】:

  • 谢谢,看起来我想出的这个测试用例可能是失败的。我会试试你的方法。我认为这个问题的答案应该是 - D、12.0 A、11.5 C、10.0 E、9.0 B、8.5 F、9.5 我们可以使用比较器来实现这一点吗?我不明白为什么当每个元素在排序中相互比较时比较器会在排序过程中失败?输入区域的数量可以改变 1
  • 我注意到@ruakh 并认为这是 OP 中的复制粘贴错误,因为它不符合问题描述,但我同意不应该做出这样的假设。如果那个例子是正确的,我的算法确实是行不通的。
  • @Stacky,不,这将是使用比较器时的答案,这正是它不正确的原因。您将 C 放在 B 之前,这是不允许的。比较器的问题在于它不具有传递性:B &gt; C(因为排名)、C &gt; E(因为价值)和E &gt; B(因为价值)。当您使用这样的比较器进行排序时,结果要么是任意的,要么算法永远不会结束,具体取决于您使用的排序实现。
  • @Vincent van der Weele ,实际上没有比较器给出以下结果,该结果出现在问题描述中并在您的答案中引用:D,12.0 A,11.5 E,9.0 B,8.5 C , 10.0 F, 9.5 我现在认为这个答案是正确的,因为 C 不能放在 B 之前(你在上面的评论中也提到了同样的问题)你为什么认为它不正确,正确的答案应该是什么?
  • 当您的比较器不尊重传递性时,排序的结果可能不正确。这并不意味着每个输入都是错误的。值得注意的是,如果您的输入由两个区域组成,每个区域的学生人数完全相同,那么您的算法与归并排序的结合实际上与我的完全相同。尝试使用更多学生、更多地区或每个地区不同数量的学生运行一些示例。在某些情况下,您应该看到结果是错误的。
猜你喜欢
  • 2020-12-20
  • 1970-01-01
  • 2013-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-15
相关资源
最近更新 更多