降低程序的复杂性

时间:2017-04-23 18:24:50

标签: c++ vector time-complexity

以下是查找总计最多3对的程序。

例如:

  

输入:0,3,5,1,2,4
  输出:0,3,1,2。

这意味着它应该返回总和等于3的所有对。

但我想减少这个程序的时间复杂度。现在我使用两个嵌套的for循环。

任何人都可以建议一种更好的方法来减少时间复杂度。

#include<iostream>
#include <vector>
using namespace std;

void main()
{
   vector<int> v;
   vector<int> r;
   int x;

   cout << "Enter the elements";

   for(int i = 0; i < 6; i++)
   {
       cin >> x;
       v.push_back(x);
   }

   for(int i = 0 ; i < v.size() - 1; i++)
   {
       for(int j = i + 1; j < v.size(); j++)
       {
          if(v[i] + v[j]  == 3)
          {
              r.push_back(v[i]);
              r.push_back(v[j]);
          }
       }
   }

   cout << "\noutput\n";

   for(int i = 0 ; i < r.size(); i++)
   {
       cout<<r[i]<<"\n";
   }

}

4 个答案:

答案 0 :(得分:3)

我要做两个准备步骤;首先,消除所有数字&gt; 3,因为它们不会成为任何有效对的一部分。这降低了第二步的复杂性。其次,对剩余的数字进行排序,以便单次浏览可以找到所有结果。

遍历从排序数组的两端接近对;如果找到一对,则两个边界都可以缩小;如果当前结束总和达到>> 3,只有一个边界变窄。

运行时复杂性为O(N logN),其中N是元素的数量&lt; = 3; O(N logN)基本上来自排序;两个单独的漫游将不计入大N s。

int main(int argc, char* argv[]) {

    const int N = 3;

    std::vector<int> input{ 0,3,5,1,2,4};
    std::vector<int>v(input.size());
    int t=0;
    for (auto i : input) {
        if (i <= N) {
            v[t++]=i;
        }
    }
    std::sort (v.begin(), v.end());

    long minIdx = 0;
    long maxIdx = v.size()-1;
    while (minIdx < maxIdx) {
        int minv = v[minIdx];
        int maxv = v[maxIdx];
        if (minv+maxv == 3) {
            cout << minv << '+' << maxv << endl;
            minIdx++;maxIdx--;
        }
        else
            minIdx++;
    }
    return 0;
}

答案 1 :(得分:1)

您正在搜索 n 元素中两个数字之间的所有组合,更具体地说,是那些总结为特定值的数字。这是子集求和问题的变体

为了实现这一点,您可以生成所有组合而不重复保存值的向量的索引。以下是如何执行此操作的示例recursively,此处是如何执行此操作的示例iteratively,只是为了获得一个想法并可能将其用作您案例中的基准。

另一种方法是dynamic programmingbacktracking

答案 2 :(得分:0)

我认为你可以用O(n)用地图来解决这个问题。

public void printPairs(int[] a, int v)
{
   map<int, int> counts = new map<int, int>();

   for(int i = 0; i < a.length; i++)
   {
     if(map.count(a[i]) == 0)
     {
        map[a[i]] = 1;
     }
     else
     {
       map[a[i]] = map[a[i]] + 1;
     }
   }

   map<int, int>::iterator it = map.begin();
   while(it != map.end())
   {
      int v1 = it->second;
      if (map.count(v - v1) > 0)
      {
         // Found pair v, v1 
         //will be found twice (once for v and once for v1)
      }
   }
}

答案 3 :(得分:0)

延迟回答但适用于负整数 ...首先,找到std::vector<int>中的最小数字,然后像this回答说的那样,删除所有元素(或复制相反的),高于3 + minimum。在对std::vector<int>进行排序后,从两端迭代它,条件如下所示:

#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>

std::vector<int> findPairs(const std::vector<int>& input, const int sum) {
    int minElem = INT_MAX;
    for(auto lhs = input.begin(), rhs = input.end() - 1; lhs < rhs;
            ++lhs, --rhs) {
        const int elem = (*lhs < *rhs ? *lhs : *rhs);
        if(elem < minElem)
            minElem = elem;
    }

    std::vector<int> temp(input.size());
    const auto tempBegin = temp.begin();
    const auto tempEnd = std::remove_copy_if(input.begin(), input.end(),
            temp.begin(), [minElem, sum](int elem) {
        return (elem + minElem) > sum;
    });
    std::sort(tempBegin, tempEnd);

    std::vector<int> result;
    auto leftIter = tempBegin;
    auto rightIter = tempEnd - 1;

    while(leftIter < rightIter) {
        if(*leftIter + *rightIter == sum) {
            result.push_back(*leftIter++);
            result.push_back(*rightIter--);
        }
        else {
            if(sum - *leftIter < *rightIter) rightIter--;
            else leftIter++;
        }
    }

    return result;
}

int main() {
    auto pairs = findPairs({ 0, 3, 5, 1, 2, 4, 7, 0, 3, 2, -2, -4, -3 }, 3);
    std::cout << "Pairs: { ";
    for(auto it = pairs.begin(); it != pairs.end(); ++it)
        std::cout << (it == pairs.begin() ? "" : ", ") << *it;
    std::cout << " }" << std::endl;
}

上面的代码将产生以下结果:

Pairs: { -4, 7, -2, 5, 0, 3, 0, 3, 1, 2 }