问题:给定大小为N的数组,使用连续元素打印大小为K的已排序子集。
N = 10, K = 4
8 4 7 5 1 10 3 9 2 6
Output:
4 5 7 8, 1 4 5 7, 1 5 7 10, 1 3 5 10, ...
方法1:对所有子集进行排序并打印。
复杂性分析:
复制K个元素:O((N - K + 1)*(K))//子集的数量*子集的大小
排序子集:使用STL,对子集进行排序的最坏情况时间是O(K log K)。
因此,O((N - K + 1)*(K)+(N - K + 1)*(K log K))
方法2:从输出序列开始,连续的子集相差2个元素。因此,对于第二个子集,删除第一个元素并将第K + 1个元素插入到正确的位置。
复杂性分析:
创建第一个子集:K
删除并插入 - 线性搜索(这应该优化!):K
因此,O(K +(N-K + 1)*(K))
我想知道第二种方法是否更快?有显着的收益吗?是否值得不使用STL实现?这可以进一步改善吗?还有其他方法吗?以及对STL容器实施的任何建议。
答案 0 :(得分:1)
是否允许重复?
如果不允许重复,请使用std::set
,否则请使用std::multiset
。 set
和multiset
会一直对您的元素进行排序,每次插入都会在正确的有序位置进行。您不必担心何时对它们进行排序。
在插入过程中对所有内容进行排序实际上更便宜,因为当您必须搜索时,您不必与所有元素进行比较,而只需要与其中的一部分进行比较。
答案 1 :(得分:1)
使用std::multiset
。这将简单而干净:
vector<int> v = input();
multiset<int> s;
for (int i = 0; i < k; ++i) {
s.insert(v[i]);
}
print_set(s);
for (int i = 0; i < n-k; ++i) {
s.erase(s.find(v[i]));
s.insert(v[i+k]);
cout << ",";
print_set(s);
}
您可以尝试:http://ideone.com/moD3bg
使用multiset的所有操作的复杂性是O(nlogk)。但是请记住,打印所有这些数据的复杂性是O(n * k)。
答案 2 :(得分:0)
解决此问题的另一种方法是:
int k=4;
std::vector<int> v = {8,4,7,5,1,10,3,9,2,6};
std::multiset<int> ss;
for(auto itr=v.begin();itr<v.end();itr++)
{
size_t remaining(std::distance(itr+k, v.end()));
std::cout<<remaining<<std::endl;
ss.insert(itr,itr+k);
print_set(ss);
if(remaining==0)
break;
ss.clear();
}