我有以下算法,效果很好
我尝试在这里为自己http://nemo.la/?p=943解释它,并在此处解释http://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/以及stackoverflow以及
我想修改它以产生最长的非单调增加的子序列
序列30 20 20 10 10 10 10
答案应为4:“10 10 10 10”
但是使用nlgn版本的算法却无法正常工作。初始化s以包含第一个元素“30”并从第二个元素开始= 20.这就是:
第一步:30不大于或等于20.我们发现最小元素大于20.新s变为“20”
第二步:20大于或等于20.我们扩展序列,s现在包含“20 20”
第三步:10不大于或等于20.我们发现大于10的最小元素是“20”。新s变为“10 20”
并且在此之后s将永远不会增长,算法将返回2而不是4
int height[100];
int s[100];
int binary_search(int first, int last, int x) {
int mid;
while (first < last) {
mid = (first + last) / 2;
if (height[s[mid]] == x)
return mid;
else if (height[s[mid]] >= x)
last = mid;
else
first = mid + 1;
}
return first; /* or last */
}
int longest_increasing_subsequence_nlgn(int n) {
int i, k, index;
memset(s, 0, sizeof(s));
index = 1;
s[1] = 0; /* s[i] = 0 is the index of the element that ends an increasing sequence of length i = 1 */
for (i = 1; i < n; i++) {
if (height[i] >= height[s[index]]) { /* larger element, extend the sequence */
index++; /* increase the length of my subsequence */
s[index] = i; /* the current doll ends my subsequence */
}
/* else find the smallest element in s >= a[i], basically insert a[i] in s such that s stays sorted */
else {
k = binary_search(1, index, height[i]);
if (height[s[k]] >= height[i]) { /* if truly >= greater */
s[k] = i;
}
}
}
return index;
}
答案 0 :(得分:3)
要找到最长的非严格增加的子序列,请更改以下条件:
- 如果
A[i]
在所有活动列表的最终候选者中最小,我们将启动新的有效列表1
。- 如果
A[i]
在所有活动列表的最终候选者中最大,我们将克隆最大的活动列表,并按A[i]
进行扩展。- 如果介于
醇>A[i]
之间,我们会找到一个最大结束元素小于A[i]
的列表。按A[i]
克隆并扩展此列表。我们将丢弃与此修改列表长度相同的所有其他列表。
为:
- 如果
A[i]
小于活动列表中所有最终候选者中的最小者,我们将启动长度为1
的新活动列表。- 如果
A[i]
在所有活动列表的最终候选者中最大,我们将克隆最大的活动列表,并按A[i]
进行扩展。- 如果介于
醇>A[i]
之间,我们会找到一个列表,其最大结尾元素小于或等于A[i]
。按A[i]
克隆并扩展此列表。我们将丢弃与此修改列表长度相同的所有其他列表。
示例序列的第四步应该是:
10
不小于10
(最小元素)。我们找到小于或等于10
的最大元素(即s[0]==10
)。按10
克隆并扩展此列表。放弃现有的长度为2的列表。新的s
变为{10 10}
。
答案 1 :(得分:3)
除了binary_search()
函数中的问题之外,您的代码几乎可以工作,此函数应该返回大于目标元素(x)的第一个元素的索引,因为您需要最长的非递减序列。修改它,它会没事的。
如果您使用c ++,std::lower_bound()
和std::upper_bound()
将帮助您摆脱这个令人困惑的问题。顺便说一句,if语句“if (height[s[k]] >= height[i])
”是多余的。
int binary_search(int first, int last, int x) {
while(last > first)
{
int mid = first + (last - first) / 2;
if(height[s[mid]] > x)
last = mid;
else
first = mid + 1;
}
return first; /* or last */
}
答案 2 :(得分:2)
通过使用词典比较,将最长的增加子序列算法应用于有序对(A [i],i)。
答案 3 :(得分:1)
这个问题的完全不同的解决方案如下。制作数组的副本并对其进行排序。然后,计算数组中任意两个元素之间的最小非零差异(这将是两个相邻数组元素之间的最小非零差异),并将其称为δ。此步骤需要时间O(n log n)。
关键观察是,如果向原始数组的元素0添加0,向原始数组的第二个元素添加δ/ n,向数组的第三个元素添加2δ/ n等,则任何非递减序列在原始数组中,在新数组中变为严格增加的序列,反之亦然。因此,您可以通过这种方式转换数组,然后运行标准的最长增长子序列求解器,它在时间O(n log n)内运行。此过程的最终结果是用于查找最长非递减子序列的O(n log n)算法。
例如,考虑30,20,20,10,10,10,10。在这种情况下δ= 10且n = 7,因此δ/n≈1.42。然后新阵列
40, 21.42, 22.84, 14.28, 15.71, 17.14, 18.57
这里,LIS是14.28,15.71,17.14,18.57,它们在原始数组中映射回10,10,10,10。
希望这有帮助!
答案 4 :(得分:0)
我的Java版本:
public static int longestNondecreasingSubsequenceLength(List<Integer> A) {
int n = A.size();
int dp[] = new int[n];
int max = 0;
for(int i = 0; i < n; i++) {
int el = A.get(i);
int idx = Arrays.binarySearch(dp, 0, max, el);
if(idx < 0) {
idx = -(idx + 1);
}
if(dp[idx] == el) { // duplicate found, let's find the last one
idx = Arrays.binarySearch(dp, 0, max, el + 1);
if(idx < 0) {
idx = -(idx + 1);
}
}
dp[idx] = el;
if(idx == max) {
max++;
}
}
return max;
}