我正在解决hackerrank的一个问题,我正在超越我的问题的时间限制。我似乎无法弄明白为什么。
输出差异最小的数字对。如果有多对,则按升序输出所有对,全部在同一行(连续),每对数字之间只有一个空格。如果有一个数字位于两对中,则打印两次(参见示例#3进行说明)。
输入数量 包含由空格分隔的所有元素的字符串
样品:
4
5 4 3 2
输出:
2 3 3 4 4 5
我失败的测试用例有100,000个输入。我计算了我的代码,我的代码中最慢的部分是函数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;
}
答案 0 :(得分:4)
// 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,可能有拼写错误,但应该这样做。我正在打电话,代码过于简洁。
答案 1 :(得分:0)
如果我理解你的问题,你也可以使用多图。 map的键/值是int / pair(int,int)。
一次查看排序列表中的2个数字。计算两个数字之间的差异。这个差异成为地图中的一个关键值,而这两个数字是你用来产生差异的两个数字。
完成后,您可以保证最小的差异位于地图的开头,因为地图使用&lt;对键进行排序。您现在拥有最小的差异以及导致这种差异的数字对的信息。
例如:
#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);
}
请注意,在构建地图时,永远不必进行最小的检查。有点让这个“安全”,但其他非地图答案的表现可能更快。