算法:计算每个更新查询的不同排序子序列的最小数量

标签 algorithm

这个问题是在面试中问我的:
包含相邻值的不同排序子序列 定义为其长度为一 或它仅包含排序时的相邻数字。每个元素只能属于 1 个这样的子序列。我有 Q 个查询,每个更新 A 中的一个值,我必须为每个查询回答,如果部分数量最小化,A 的分区中有多少部分会分成不同的排序子序列。

例如,A = [1,2,3,4,3,5] 的部分数可以通过以下两种方式划分来最小化,这两种方式都只包含两个部分:

1) [1,2,3] && [4,3,5] ==> answer 2 (4,3,5 sorted is 3,4,5 all adjacent values)

2) [1,2,3,4,5] && [3] ==> answer 2 

我尝试过的方法:散列和形成集合,但由于超时,所有测试用例都没有被清除。

问题陈述 PDF: PDF

约束:
1<= N,Q <= 3*10^5
1< A(i)< 10^9

最佳答案

预处理

首先,您可以在所有查询之前预处理 A 并生成一个表(比如 times_of),这样当给定一个数字 n 时,可以通过times_of[n]等表达式,高效获取nA中出现的次数。在以下示例中,假设 A 的类型为 int[N],我们使用 std::map 来实现该表。它的构建花费了O(NlogN)时间。

auto preprocess(int *begin, int *end)
{
    std::map<int, std::size_t> times_of;
    while (begin != end)
    {
        ++times_of[*begin];
        ++begin;
    }
    return times_of;
}

minmax 分别是A 的最小和最大元素。然后应用以下引理:

The minimum number of distinct sorted subsequences is equal to max{0, times_of[min] - times_of[min-1]} + ... + max{0, times_of[max] - times_of[max-1]}.

严格的证明有点技术性,所以我从这个答案中省略了它。粗略地说,从小到大考虑数字。如果n出现的次数多于n-1,则必须带上额外的times_of[n]-times_of[n-1]个子序列。

有了这个引理,我们可以在 O(N) 时间内计算不同排序子序列 result 的最小数量(通过遍历 times_of,而不是从 迭代code>minmax)。以下是示例代码:

std::size_t result = 0;
auto prev = std::make_pair(min - 1, static_cast<std::size_t>(0));
for (auto &cur : times_of)
{
    // times_of[cur.first-1] == 0
    if (cur.first != prev.first + 1) result += cur.second;
    // times_of[cur.first-1] == times_of[prev.first]
    else if (cur.second > prev.second) result += cur.second - prev.second;

    prev = cur;
}

查询

为了处理查询A[u] = v,我们首先更新times_of[A[u]]times_of[v] 这花费了 O(logN) 时间。然后根据引理,我们只需要重新计算常量(即 4)相关项来更新 result。每次重新计算都花费 O(logN) 时间(以查找 times_of 中的上一个或下一个元素),因此查询总共花费 O(logN) 时间。

关于算法:计算每个更新查询的不同排序子序列的最小数量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48472972/

相关文章:

algorithm - 当 c > 0 Log(n) = O(n) 时?不确定为什么不是 O(log n)

用于查找树中相同值节点的最大连通区域大小的算法

c++ - 如何设计一个固定TIME长度的循环缓冲区?

c++ - 按字符拆分字符串

arrays - 查找元素数量差异最大的子数组

php - 找到从 A 点到 B 的路径,循环次数为 n

algorithm - 检查矩阵中元素邻居的最佳方法

c++ - 堆排序中的堆大小

algorithm - 在阶跃响应后找到平均稳定值

algorithm - 在程序中取对数会对计算机造成负担吗?