我遇到了以下问题: 考虑有一个递增的数字列表(例如1,2,3,7,8,10), 收集(连续数字)范围并以紧凑的形式打印(如上面给出的数字):
1→3 7-> 8 10
特别是,该解决方案也应该适用于“退化情况”,例如只有一个元素的列表,或者像-2,1这样的列表。
我提出了一个解决方案,我尝试将数字分成不同的向量,但这看起来非常麻烦。所以,我想知道是否有更好的替代方法解决这个问题。
这是我的方法:
vector< vector<int> > result(numbers.size()*numbers.size(), vector<int>());
int last_range;
vector<int> range;
vector<string> result_string;
//1,2,3,7,8,10
if(numbers.size() == 1)
{
stringstream ss;
ss << numbers[0];
result_string.push_back(ss.to_string());
return result_string;
}
for (int i = 1; i < numbers.size(); i++ )
{
if( numbers[i] - numbers[i-1] == 1 )
{
range.push_back(numbers[i]);
}
if ( i == numbers.size()-1 )
{
last_range = numbers[i];
range.push_back(last_range);
}
result[i-1].push_back(range);
}
if( result.size() < 1 )
{
range.push_back(numbers[0]);
result[0].push_back(range);
stringstream ss;
ss << result[0][0];
result_string.push_back(ss.to_string());
return result_string;
}
//result[0] - > array of numbers 1,2,3
// result [1] - > array of numbers
for (int i = 0; i < result.size(); i++ )
{
int start_index = result[i][0];
int last_index = result[i][result.size()-1];
stringstream ss_startindex;
stringstream ss_endindex;
ss_startindex << result[i][0];
ss_endindex << result[i][result.size()-1];
string result = ss_startindex.to_string() + "->" + ss_endindex.to_string();
result_string.push_back(result);
}
return result_string;
}
答案 0 :(得分:0)
你需要的是一个对象,它跨越一个序列来携带上下文('下一个整数是一个范围的一部分?')。因此,使用std::for_each
算法作为一元函数的函数对象可以最好地解决这类问题。
一个工作的例子是:
#include <algorithm>
#include <limits>
#include <utility>
#include <vector>
#include <iostream>
using IntCollection = std::vector<int>;
IntCollection is = {1,2,3,7,8,10}, is2 = {-2,1}, is3 = {20};
using Range = std::pair<int,int>;
class IntRangePrinter
{
public:
void operator() (int i)
{
if (r.first == inval)
r.first = i;
else if (r.second == inval && r.first + 1 == i)
r.second = i;
else if (r.second + 1 == i)
r.second = i;
else {
print_range_or_value();
// reset after printing
reset();
// and re-init range with current value
r.first = i;
}
}
// There might be "pending" data to be printed
void flush()
{
print_range_or_value();
std::cout << std::endl;
reset();
}
private:
static int inval; // some value not to be expected in IntCollection
void print_range_or_value()
{
if (r.first != inval && r.second != inval)
std::cout << ' ' << r.first << "->" << r.second;
else // if (r.second == inval)
std::cout << ' ' << r.first;
}
void reset ()
{
r.first = inval;
r.second = inval;
}
Range r = {inval,inval};
};
int IntRangePrinter::inval = std::numeric_limits<int>::max();
int main () {
IntRangePrinter p;
p = std::for_each(is.begin(), is.end(), std::move(p));
p.flush();
p = std::for_each(is2.begin(), is2.end(), std::move(p));
p.flush();
p = std::for_each(is3.begin(), is3.end(), std::move(p));
p.flush();
return 0;
}