循环/方法太慢了

时间:2014-02-10 03:18:56

标签: c++ c++11

我正在解决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;
}

2 个答案:

答案 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);
}

请注意,在构建地图时,永远不必进行最小的检查。有点让这个“安全”,但其他非地图答案的表现可能更快。