如果您知道数组元素的限制(请参阅下面的更新)我可以建议您使用时间复杂度 O(n*log(MaxN)) 和空间复杂度 O(MaxN) 的算法,其中 MaxN = Max(V[i ])。
对于这个算法,我们需要能够在时间复杂度为 O(log(N)) 的数组中获得最小值的结构,并以时间复杂度 O(log(N)) 更新数组元素。 Fenwick tree 可以做到这些。我们称这个结构为 minimizator。然后我们需要:
- 按给定顺序 v[i] 迭代所有元素,并将其放在 v[i] 位置的最小值 i 处。
- 对于每个元素 v[i],使用 1 和 v[i-1] 之间的最小化器找到最小值(这是小于 v[i] 的元素的最小索引)
- 记住 i 与找到的小于 v[i] 的元素的最小索引之间的最大差异。
好的。我试过写一些伪代码:
prepare array (map values)
init minimizator
ansI = -1
ansJ = -1
for i from 0 to v.length-1
minIndexOfElementLessThanCurrent = get min value from 1 to v[i]-1 (inclusive) using minimizator
set to minimizator v[i] position value i
if minIndexOfElementLessThanCurrent is exists
if ansJ - ansI < i - minIndexOfElementLessThanCurrent
ansJ = i
ansI = minIndexOfElementLessThanCurrent
C++ 实现:
class FenwickTree
{
vector<int> t;
int n;
public:
static const int INF = 1000*1000*1000;
void Init (int n)
{
this->n = n;
t.assign (n, INF);
}
int GetMin (int i)
{
int res = INF;
for (; i >= 0; i = (i & (i+1)) - 1)
res = min (res, t[i]);
return res;
}
void Update (int i, int value)
{
for (; i < n; i = (i | (i+1)))
t[i] = min (t[i], value);
}
};
pair<int, int> Solve(const vector<int>& v)
{
int maxElement = 0;
for(int i = 0; i < v.size(); i++)
maxElement = max(maxElement, v[i]);
FenwickTree minimizator;
minimizator.Init(maxElement+1);
int ansI = -1, ansJ = -1;
for(int i = 0; i < v.size(); i++)
{
int minLeftIndex = minimizator.GetMin(v[i]-1);
minimizator.Update(v[i], i);
if(minLeftIndex == FenwickTree::INF) continue; // no left elements less than v[i]
if(ansJ - ansI < i - minLeftIndex)
{
ansJ = i;
ansI = minLeftIndex;
}
}
return make_pair(ansI, ansJ);
}
更新:
如果元素的种类不是 int(f.e. double) 或者数组元素的最大值太大 (f.e. 10^9) 我们可以
将数组值(不会影响结果)映射到整数集1..N,然后时间复杂度应该是O(n * log(n))
更新:
如果元素是整数 - 有O(max(maxN, n)) 解决方案。所以如果maxN <= n 复杂度是O(N)。我们只需要在 const time O(1) 内回答“get minimum from 1 to N”这个查询:
- 创建大小为
maxN的数组
- 数组的元素 m[i] 是源数组 V 中
i 值的最小索引。
- 使用动态编程创建与数组元素
r[i] 最小为m[j], 1 <= j <= i 大小相同的数组。递归关系为r[i] = min(r[i-1], m[i])
这个算法的主要思想和上面一样,只是用数组r求从1到v[i]的最小值。
C++ implementation:
pair<int, int> Solve(const vector<int>& v)
{
int maxElement = 0;
for(int i = 0; i < v.size(); i++)
maxElement = max(maxElement, v[i]);
vector<int> minimum(maxElement + 1, v.size() + 1);
for(int i = 0; i < v.size(); i++)
minimum[v[i]] = min(minimum[v[i]], i); // minimum[i] contains minimum index of element i
for(int i = 1; i < minimum.size(); i++)
minimum[i] = min(minimum[i-1], minimum[i]); // now minimum[i] contains minimum index between elements 1 and i
int ansI = -1, ansJ = -1;
for(int i = 0; i < v.size(); i++)
{
int minLeftIndex = minimum[v[i]-1];
if(minLeftIndex >= i) continue; // no left elements less than v[i]
if(ansJ - ansI < i - minLeftIndex)
{
ansJ = i;
ansI = minLeftIndex;
}
}
return make_pair(ansI, ansJ);
}
如果元素是双精度的,或者其他的东西(非常大的整数),我们不能在线性时间内将元素映射到设置 1..N(或者可以吗?)。我只知道O(n*log(n)) 解决方案(排序元素等)