Algorithm 给定序列中所有递增子序列的数目?
你可能听说过一个众所周知的问题,那就是如何找到正确的答案。优化算法具有Algorithm 给定序列中所有递增子序列的数目?,algorithm,Algorithm,你可能听说过一个众所周知的问题,那就是如何找到正确的答案。优化算法具有O(n*log(n))复杂度 我在考虑寻找给定序列中所有递增子序列的问题。我找到了一个我们需要解决的问题的解决方案,它具有O(n*k*log(n))复杂性(其中n是序列的长度) 当然,这个算法可以用于我的问题,但我想解决方案有O(n*k*log(n)*n)=O(n^2*k*log(n))复杂性。我认为,一定有更好(我是说更快)的解决方案,但我还不知道 如果您知道如何解决在给定序列中以最佳时间/复杂度查找所有递增子序列的问题(在
O(n*log(n))
复杂度
我在考虑寻找给定序列中所有递增子序列的问题。我找到了一个我们需要解决的问题的解决方案,它具有O(n*k*log(n))
复杂性(其中n是序列的长度)
当然,这个算法可以用于我的问题,但我想解决方案有O(n*k*log(n)*n)=O(n^2*k*log(n))
复杂性。我认为,一定有更好(我是说更快)的解决方案,但我还不知道
如果您知道如何解决在给定序列中以最佳时间/复杂度查找所有递增子序列的问题(在本例中,最佳=优于O(n^2*k*log(n))
,请告诉我
最后:这个问题不是家庭作业。在我的讲座中提到了一个最长递增子序列的问题,我已经开始思考给定序列中所有递增子序列的一般概念。我不知道这是否是最优的-可能不是,但这里有一个
O(n^2)
中的DP解
设dp[i]=以i作为最后一个元素的递增子序列的数目
for i = 1 to n do
dp[i] = 1
for j = 1 to i - 1 do
if input[j] < input[i] then
dp[i] = dp[i] + dp[j] // we can just append input[i] to every subsequence ending with j
对于i=1到n do
dp[i]=1
对于j=1到i-1do
如果输入[j]<输入[i],则
dp[i]=dp[i]+dp[j]//我们可以将输入[i]附加到以j结尾的每个子序列中
然后,只需将
dp
中的所有条目相加,就可以计算出O(n logn)时间内递增子序列的数量,如下所示
回想一下最长递增子序列长度的算法:
对于每个元素,计算先前元素中的前置元素,并向该长度添加一个
如果您使用诸如平衡二叉搜索树(BST)之类的数据结构(或更高级的整数范恩德-博阿斯树)计算前驱体,则该算法在O(n^2)时间内运行,在O(n log n)时间内运行(或者更好,在整数的情况下)
要修改此算法以计算序列数,请将结束于该元素的序列数存储在每个节点的BST中。在处理列表中的下一个元素时,只需搜索前置元素,计算以小于当前正在处理的元素结尾的序列数(以O(logn)时间为单位),并将结果与当前元素一起存储在BST中。最后,对树中每个元素的结果求和以获得结果
需要注意的是,递增序列的数量可能非常大,因此算术运算不再需要每次运算O(1)个时间。这需要加以考虑
伪代码:
ret = 0
T = empty_augmented_bst() // with an integer field in addition to the key
for x int X:
// sum of auxiliary fields of keys less than x
// computed in O(log n) time using augmented BSTs
count = 1 + T.sum_less(x)
T.insert(x, 1 + count) // sets x's auxiliary field to 1 + count
ret += count // keep track of return value
return ret
我假设输入A[0..(n-1)]由{0,1,…,n-1}中的所有整数组成,而不丧失泛化性 设DP[i]=以A[i]结尾的递增子序列的数目 我们有一个循环: 为了计算DP[i],我们只需要计算所有j的DP[j],其中A[j]A[i] 问题归结为计算DP[0]到DP[i-1]的和。假设我们已经计算了DP[0]到DP[i-1],我们可以使用芬威克树计算O(logn)中的DP[i]
最后的答案是DP[0]+DP[1]+。。。DP[n-1]。该算法在O(n log n)中运行。例如,Java版本:
int[] A = {1, 2, 0, 0, 0, 4};
int[] dp = new int[A.length];
for (int i = 0; i < A.length; i++) {
dp[i] = 1;
for (int j = 0; j <= i - 1; j++) {
if (A[j] < A[i]) {
dp[i] = dp[i] + dp[j];
}
}
}
int[]A={1,2,0,0,0,4};
int[]dp=新的int[A.长度];
for(int i=0;i
向量值
,一个n长度数组,是要搜索递增子序列的数组
vector<int> temp(n); // Array for sorting
map<int, int> mapIndex; // This will translate from the value in index to the 1-based count of values less than it
partial_sort_copy(values.cbegin(), values.cend(), temp.begin(), temp.end());
for(auto i = 0; i < n; ++i){
mapIndex.insert(make_pair(temp[i], i + 1)); // insert will only allow each number to be added to the map the first time
}
将值的所有n个元素
放入二进制索引树
的所有k维后。收集到结果
中的值
s表示长度k的递增子序列的总数
用于获得此结果的二元索引树函数有:
void update(int rank, int increment, vector<int>& binaryIndexTree)
{
while (rank < binaryIndexTree.size()) { // Increment the current rank and all higher ranks
binaryIndexTree[rank - 1] += increment;
rank += (rank & -rank);
}
}
int getValue(int rank, const vector<int>& binaryIndexTree)
{
auto result = 0;
while (rank > 0) { // Search the current rank and all lower ranks
result += binaryIndexTree[rank - 1]; // Sum any value found into result
rank -= (rank & -rank);
}
return result;
}
void更新(整数秩、整数增量、向量和二进制索引树)
{
而(rank0){//搜索当前秩和所有较低的秩
result+=binaryIndexTree[rank-1];//对结果中找到的任何值求和
秩-=(秩和秩);
}
返回结果;
}
二叉索引树显然是O(nklogn),但正是顺序填充的能力创造了将其用于解决方案的可能性
mapIndex
为values
中的每个数字创建一个秩,这样values
中的最小数字的秩为1。(例如,如果values
是“2,3,4,3,4,1”,那么mapIndex
将包含:“{1,1},{2,2},{3,3},{4,5}”。“4”的秩5是因为有2个“3”值中的s
binaryIndexTree
有k个不同的树,级别x表示可以由长度x组成的递增子字符串的总数。value
中的任何数字都可以创建长度为1的子字符串,因此每个元素将其秩和其上的所有秩递增1。在更高的级别,子字符串的增加取决于已经存在一个长度更短、级别更低的可用子字符串 由于元素是根据其在
值中的顺序插入到二叉索引树中的,因此
void update(int rank, int increment, vector<int>& binaryIndexTree)
{
while (rank < binaryIndexTree.size()) { // Increment the current rank and all higher ranks
binaryIndexTree[rank - 1] += increment;
rank += (rank & -rank);
}
}
int getValue(int rank, const vector<int>& binaryIndexTree)
{
auto result = 0;
while (rank > 0) { // Search the current rank and all lower ranks
result += binaryIndexTree[rank - 1]; // Sum any value found into result
rank -= (rank & -rank);
}
return result;
}
int arr[] = {7, 4, 6, 8};
int T[] = new int[arr.length];
for(int i=0; i<arr.length; i++)
T[i] = 1;
int sum = 1;
for(int i=1; i<arr.length; i++){
for(int j=0; j<i; j++){
if(arr[i] > arr[j]){
T[i] = T[i] + T[j];
}
}
sum += T[i];
}
System.out.println(sum);