【发布时间】:2018-07-09 17:28:09
【问题描述】:
问题陈述
每次给我一个非常大的数字列表,我需要打印“中位数”。
更清楚地说,可以有“125,000,000”个数字,并且保证每个数字都小于“1.e+18”。
这是一个竞赛,所以有内存限制(最多 20 MB)和时间限制(最多 5 秒)。 p>
“中位数”是在已排序数字中间的那个。
例如,如果这是数字列表:
23
8
16
42
15
4
108
排序后的数字:
1) 4
2) 8
3) 15
4) 16
5) 23
6) 42
7) 108
“中位数”将是 16;
所以我在互联网上搜索了它,但我找不到任何超过这些限制的答案。
方法
我的方法是获取所有数字,将它们保存在文本文件中,对它们进行排序,然后得到“中位数”。
想法
- 我知道我可以从文件中读取所有数字并将它们放入向量中
然后轻松地对它们进行排序。
但这会超出内存限制。
- 所以我想出了这个想法,在将数字放入文本时对其进行排序
文件。
这就像有一个循环后得到下一个 来自控制台的数字读取文件(逐行)以及何时读取 到达正确的位置,在那里插入数字并且不接触其他 数字。
但问题是我不能在中间插入一行 文本文件,因为它会覆盖其他数字。
- 所以我创建了两个文件,其中一个文件的编号已经
输入,另一个读取第一个文件并将其复制到
本身直到到达正确的位置然后插入最后一个给定的数字然后
继续复制剩余的数字。
但是它花费了太多时间,所以它 超过时间限制。
请求
所以我想优化这些想法之一以通过限制或任何通过这些限制的新想法。
偏好
我更喜欢使用第二个想法,因为与其他两个不同,它通过了限制,但我不能这样做,因为我不知道如何在文本文件中间插入一行。所以如果我学会了这一点,剩下的过程就会变得如此简单。
尝试的解决方案
这是一个函数,它接收一个数字,并通过读取一个文件,为它找到最佳位置并将其放在那里。
事实上,它代表了我的第三个想法。
所以它可以工作(我用大量输入对其进行了测试)但我之前提到的问题是 时间限制。
void insertNewCombinedNumber ( int combinedNumber )
{
char combinedNumberCharacterArray[ 20 ];
bool isInserted = false;
ofstream combinedNumbersOutputFile;
ifstream combinedNumbersInputFile;
// Operate on First File
if ( isFirstCombinedFileActive )
{
combinedNumbersOutputFile.open ( "Combined Numbers - File 01.txt" );
combinedNumbersInputFile.open ( "Combined Numbers - File 02.txt" );
}
// Operate on Second File
else
{
combinedNumbersOutputFile.open ( "Combined Numbers - File 02.txt" );
combinedNumbersInputFile.open ( "Combined Numbers - File 01.txt" );
}
if ( !combinedNumbersInputFile )
{
combinedNumbersInputFile.close ();
ofstream combinedNumbersInputCreateFile ( "Combined Numbers - File 02.txt" );
combinedNumbersInputCreateFile.close ();
combinedNumbersInputFile.open ( "Combined Numbers - File 02.txt" );
}
combinedNumbersInputFile.getline ( combinedNumberCharacterArray , 20 );
for ( int i = 0; !combinedNumbersInputFile.eof (); i++ )
{
if ( !isInserted && combinedNumber <= characterArrayToDecimal ( combinedNumberCharacterArray ) )
{
combinedNumbersOutputFile << combinedNumber << endl;
isInserted = true;
}
combinedNumbersOutputFile << combinedNumberCharacterArray << endl;
combinedNumbersInputFile.getline ( combinedNumberCharacterArray , 20 );
}
if ( !isInserted )
{
combinedNumbersOutputFile << combinedNumber << endl;
isInserted = true;
}
isFirstCombinedFileActive = !isFirstCombinedFileActive;
combinedNumbersOutputFile.close ();
combinedNumbersInputFile.close ();
}
【问题讨论】:
-
一次读取 20 MB 的数字,对每个子集进行排序,将每个子集写入不同的文件,合并文件。
-
如果我遇到这个问题,我会研究不同的排序算法(有很多),看看是否可以使用任何方法来帮助处理这些约束。正如@NathanOliver 指出的那样,这个middle number 可能在没有完全排序的情况下可用......
-
@Bijan 等等……你是直接给了一个文件,还是一次只给一个数字?
-
@Justin 正如我所说,这是竞赛的一部分。用户传递给程序的数字有“500”,然后程序必须使用以下函数生成所有可能的数字,最后它必须打印排序数字中间的数字。 f ( x , y , z ) = z * ( y * ( x + 1 ) + 1 )。
-
@Bijan 那么您甚至必须编写文件,还是只计算中间数?