假设我有一个数组 A = {a1,a2,...,an}
假设A被划分为大小 b
的块我要做的是:
让 MinUntilHere 和 MinStartingHere 为2个大小 n 的数组,其中:
我想在数组的单个横向中填充这2个数组...我正在尝试以下伪代码:
int fill(int pos = 0){
if(pos >= n) return INF
if(pos is the start index of a block){ //i % b == 0
MinUntilHere[pos] = A[pos]
MinStartingHere[pos] = min(A[pos], fill(i + 1))
}
else{
MinUntilHere[pos] = min(A[pos], A[pos - 1])
MinStartingHere[pos] = min(A[pos], fill(i + 1))
return MinStartingHere[pos]
}
}
但正如您所看到的,它并不完整,因为它无法检测每个块何时结束并且缺少某些返回。我怎样才能创建一个只通过数组一次的函数并计算我的答案?
Example:
让 A = {2,1,3,6,5,4} 和 b = 2 ,数组必须像这样填充:
MinUntilHere = {2,1,3,3,5,4}
MinStartingHere = {1,1,3,6,4,4}
MinUntilHere [0] = 2从0的块开始直到索引0,最小值为2.
MinUntilHere [1] = 1从1的块开始直到索引1,最小值为min(1,2)= 1
End of Example
答案 0 :(得分:1)
您可以使用以下作业完成2次传递:
template <typename InputIt, typename OutputIt>
void ComputeMinUntilHere(InputIt begin, InputIt end, OutputIt output)
{
if (begin == end) {
return;
}
auto min = *begin;
while (begin != end) {
min = std::min(min, *begin);
*output = min;
++begin;
++output;
}
}
struct MinByBlock
{
std::vector<int> minUntilHere;
std::vector<int> minStartingHere;
};
MinByBlock ComputeMinByBlock(const std::vector<int>&v, std::size_t blockSize)
{
MinByBlock res;
res.minUntilHere.resize(v.size());
res.minStartingHere.resize(v.size());
for (std::size_t i = 0; i < v.size(); i += blockSize) {
const auto blockBegin = v.begin() + i;
const auto blockEndIndex = std::min(i + blockSize, v.size());
const auto blockEnd = v.begin() + blockEndIndex;
ComputeMinUntilHere(blockBegin, blockEnd, res.minUntilHere.begin() + i);
ComputeMinUntilHere(std::make_reverse_iterator(blockEnd),
std::make_reverse_iterator(blockBegin),
std::make_reverse_iterator(res.minStartingHere.begin() + blockEndIndex));
}
return res;
}
您可能会注意到,minUntilHere
和minUntilHere
相似,只是依赖于您从左到右或从右到左进行迭代。
ComputeMinUntilHere
完成整个范围的工作。
ComputeMinByBlock
通过独立块分割矢量以按块填充结果。
答案 1 :(得分:0)
在一般情况下,您不能希望在一次通过中填充数组。
例如,如果块大小为N
(整个数组),那么要填写条目MinUntilHere[i]
,您需要查看i
之前的所有项目并填写条目MinStartingHere[i]
您需要查看i
之后的所有项目。
答案 2 :(得分:0)
很抱歉,但是我能够找到一个线性解决方案(仅运行一次数组),代码要小得多。这是解决方案:
int fill(int pos = 0){
if(pos >= |A|) return INF;
int mod = pos % b;
if(mod == 0){
MinUntilHere[pos] = A[pos];
MinStartingHere[pos] = min(A[pos], fill(pos + 1));
return fill(pos + bsize);
}
else if(mod == bsize - 1){
MinUntilHere[pos] = min(MinUntilHere[pos-1], A[pos]);
return MinStartingHere[pos] = A[pos];
}
else{
MinUntilHere[pos] = min(MinUntilHere[pos-1], A[pos]);
return MinStartingHere[pos] = min(A[pos], fill(pos + 1));
}
}
它的工作原理如下:
一个重要的细节是,当你启动块时,你会调用很多递归,然后使用MinStartingHere的值返回到该块的开头,并且在调用pos + b的方法之后,这意味着它将在完成当前块后开始计算新块。
感谢您的帮助:)