循环/方法太慢

Loop/Method is too slow

本文关键字:方法 循环      更新时间:2023-10-16

我目前正在处理hackerbank中的一个问题,我的问题已经超过了时间限制。我似乎不明白为什么。

输出差值最小的数字对。如果有多对,则按升序输出所有对,所有对都在同一行(连续),每对数字之间只有一个空格。如果有一个数字位于两对中,请将其打印两次(有关解释,请参见示例案例#3)。

输入数量包含由空白分隔的所有元素的字符串

样品:

4
5 4 3 2

输出:

2 3 3 4 4 5

我失败的测试用例有100000个输入。我对代码进行了计时,代码中最慢的部分是函数closest中的循环。我最初有一个向量,然后在得到列表后使用std:sort。然后,我尝试使用multiset而不是调用std::sort来尝试提高我的性能。它仍然没有通过测试。关于如何改进closest或方法addPair中的循环,有什么想法吗?

#include <iostream>
#include <set>
#include <utility>
#include <cmath>
#include <string>
#include <algorithm>
#include <ctime>
#define NUMBER 10000
double diffclock(clock_t clock1, clock_t clock2)
{
double diffticks = clock1 - clock2;
double diffms = (diffticks) / (CLOCKS_PER_SEC / NUMBER);
return diffms;
}
class ClosestPair
{
private:
long _distance;
const char UNSET = -1;
std::multiset<int> _list;
long getDistance(const int number1, const int number2) const;
public:
ClosestPair();
~ClosestPair();
void addPair(const int number1, const int number2);
const std::multiset<int>& getList() const;
const std::string toString() const;
void sort();
};
ClosestPair::ClosestPair()
{
_distance = UNSET;
}
ClosestPair::~ClosestPair()
{
}
void ClosestPair::addPair(const int number1, const int number2)
{
long distance = getDistance(number1, number2);
if(distance < _distance || _distance == UNSET)
{
_list.clear();
_distance = distance;
//std::pair<int, int> newPair(number1, number2);
//_list.push_back(newPair);
_list.insert(number1);
_list.insert(number2);
}
else if(distance == _distance)
{
_list.insert(number1);
_list.insert(number2);
//std::pair<int, int> newPair(number1, number2);
//_list.push_back(newPair);
}
}
inline long ClosestPair::getDistance(const int number1, const int number2) const
{
return std::abs(number1 - number2);
}
const std::multiset<int>& ClosestPair::getList() const
{
return _list;
}
const std::string ClosestPair::toString() const
{
std::string allPairs;
for(auto iterator = _list.begin(); iterator != _list.end(); iterator++)
{
allPairs += std::to_string(*iterator);
allPairs += " ";
//allPairs += std::to_string(iterator->second);
//allPairs += " ";
}
if(allPairs.size() > 0)
{
allPairs.substr(0, allPairs.size() - 1);
}
return allPairs;
}
void ClosestPair::sort()
{
//std::sort(_list.begin(), _list.end());
}
void closest(int* array, int size)
{
ClosestPair closestPairs;
clock_t begin = clock();
for(int i = 0; i < size; i++)
{
for(int j = i + 1; j < size; j++)
{
closestPairs.addPair(array[i], array[j]);
}
}
clock_t end = clock();
std::cout << "AddPair time: " << diffclock(end, begin) << " ms." << std::endl;
//closestPairs.sort();
begin = clock();
std::cout << closestPairs.toString();
std::cout << "toString time: " << diffclock(end, begin) << " ms." << std::endl;
end = clock();
}
int main()
{
int sizeOfList;
std::string allNumbers;
std::cin >> sizeOfList >> std::ws;
std::getline(std::cin, allNumbers);
size_t position = 0;
size_t nextPosition = 0;
int count = 0;
int array[sizeOfList];
clock_t begin = clock();
do
{
position = nextPosition;
nextPosition = allNumbers.find(' ', position + 1);
if(position > 0)
position++;
array[count] = atoi(allNumbers.substr(position, nextPosition - position).c_str());
count++;
}
while(nextPosition != std::string::npos);
clock_t end = clock();
std::cout << "Tokenize time: " << diffclock(end, begin) << " ms." << std::endl;
closest(array, sizeOfList);
return 0;
}
// requires [b,e) is sorted:
template<typename Iterator>
std::vector<Iterator> find_close_pairs( Iterator b, Iterator e ){
if (b==e || std::next(b) == e) return {};
std::vector<std::size_t> retval = {0};
auto old = *std::next(b) - *b;
for(auto it = std::next(b); std::next(it) != e; ++it) {
auto delta = *std::next(it) - *it;
if (delta < old) {
retval.clear();
old = delta;
}
if (delta <= old) {
retval.push_back(it);
}
}
return retval;
}
// requires: iterators are writable.  Sorts range.  Faster with random access:
template<typename Iterator>
std::vector<std::pair<int,int>> solve(Iterator b, Iterator e) {
std::sort(b, e);
auto close_pairs_indexes = find_close_pairs(b, e);
std::vector<std::pair<int,int>> retval;
retval.reserve(close_pairs_indexes.size());
for(auto it:close_pairs_indexes) {
retval.push_back( {*it, *std::next(it)} );
}
return retval;
}
// requires: numbers is a container, not a C array:
template<typename Container>
std::vector<std::pair<int,int>> solve(sContainer numbers) {
using std::begin; using std::end;
return solve( begin(numbers), end(numbers) );
}

是C++11,可能有拼写错误,但应该这样做。代码过于简洁,就像我在电话里一样。

如果我正确理解你的问题,你也可以使用多映射。映射的键/值是int/pare(int,int)。

一次浏览你的排序列表2个数字。计算这两个数字之间的差值。这个差值成为地图中的一个关键值,而这两个数字就是你用来计算差值的两个数字。

完成后,可以保证最小的差异在地图的开头,因为地图使用<以对密钥进行排序。现在,您有了最小的差异,再加上导致该差异的一对数字的信息。

例如:

#include <map>
#include <vector>
#include <algorithm>
typedef std::multimap<int, std::pair<int, int>> IntMap;
typedef std::vector<int> IntVect;
void getDifferences(const IntVect& intVect, IntMap& theMap)  // assume intVect is     sorted
{
theMap.clear();
if (intVect.size() < 2)
return;
size_t nItems = intVect.size();
for (size_t i = 0; i < nItems - 1; ++i)
{
int num1 = intVect[i+1];
int num2 = intVect[i];
int diff = num1 - num2
theMap.insert(std::make_pair(diff, std::make_pair(num2, num1)));
}
}
int main()
{
int Test[] = { 3, 4, 2, 7, 1, 11 };
IntVect testV(Test, Test + sizeof(Test) / sizeof(Test[0]));
std::sort(testV.begin(), testV.end());
IntMap myMap;
getDifferences(testV, myMap);
}

请注意,在构建地图时,永远不必检查最小值。这有点"安全",但其他非地图答案的执行速度可能更快。