如何从给定数组中打印最长递增子序列(LIS)
How to print Longest Increasing Subsequence(LIS) from a given array?
我可以通过普通函数和递归函数打印LIS的长度。但我想在C++中打印给定数组中LIS子序列的索引。
这是我查找LIS:长度的函数
int lis( int *arr, int n )
{
int *lis, i, j, max = 0;
lis = (int*) malloc ( sizeof( int ) * n );
for ( i = 0; i < n; i++ )
lis[i] = 1;
for ( i = 1; i < n; i++ )
for ( j = 0; j < i; j++ )
if ( arr[i] > arr[j] && lis[i] < lis[j] + 1)
lis[i] = lis[j] + 1;
for ( i = 0; i < n; i++ )
if ( max < lis[i] )
max = lis[i];
/* Free memory to avoid memory leak */
free( lis );
return max;
}
此处为array[10]={7 6 2 3 4 1 8 5 9 10}
此处为LIS Length=6
我想打印array[10]
中的数字索引{2 3 4 6 8 9}
(不是序列,而是arrray索引,我想打印的)序列索引
计算每个索引的lis后,取一个等于max的tmp值,在lis数组上倒退,每次找到等于max的元素时,将该索引添加到答案中,并递减tmp。在这里,您将以相反的顺序获得索引数组。
示例代码:
int tmp = max;
std::vector<int> indexes;
for( i = n - 1; i >= 0; --i )
if( lis[ i ] == tmp )
{
indexes.push_back( i );
--tmp;
}
std::reverse( indexes.begin(), indexes.end());
要按顺序打印,可以使用递归方法:调用:printLIS(lis,lis.length-1,arr,max)
public static void printLIS(int[] lis, int lisIndex, int[] arr, int max) {
if(max == 0) {
return;
}
if(lis[lisIndex] == max) {
printLis(lis,lisIndex-1, arr, max-1);
System.out.print(arr[lisIndex] + " ");
} else {
printLis(lis,lisIndex-1, arr, max);
}
}
void solution() {
int n;
cin >> n;
vector<int> v(n);
for (int &x : v) cin >> x;
vector<int> dp(n, 1);
int i = 0, j = 1;
vector<int> par(n);
for (int i = 0; i < n; i++) {
par[i] = i;
}
for (int j = 1; j < n; j++) {
for (int i = 0; i < j; i++) {
if (v[j] > v[i] && dp[j] < dp[i] + 1) {
dp[j] = dp[i] + 1;
par[j] = i;
}
}
}
int mx = 1, idx = 0;
for (int i = 0; i < n; i++) {
if (dp[i] > mx) {
mx = dp[i];
idx = i;
}
}
cout << mx << "n";
vector<int> seq;
while (true) {
seq.pb(v[idx]);
if (par[idx] == idx) break;
idx = par[idx];
}
reverse(seq.begin(), seq.end());
for (int i = 0; i < mx; i++) {
cout << seq[i] << " ";
}
}
维护一个父数组,从LIS逐父结束的索引向后走,直到到达parent[index]=index的索引。
int lis( int *arr, int n )
{
int *lis, i, j, max = 0, max_index = 0;
int *print = (int*)malloc(sizeof(int)*n);
lis = (int*) malloc ( sizeof( int ) * n );
for ( i = 0; i < n; i++ ){
lis[i] = 1;
print[i] = -1
}
for ( i = 1; i < n; i++ )
for ( j = 0; j < i; j++ )
if ( arr[i] > arr[j] && lis[i] < lis[j] + 1){
lis[i] = lis[j] + 1;
print[i] = j;
}
for ( i = 0; i < n; i++ ){
if ( max < lis[i] ){
max = lis[i];
max_index = i;
}
}
while(max_index >=0){
printf("%d ",lis[max_inc_index]);
max_index = print[max_index];
}
/* Free memory to avoid memory leak */
free( lis );
return max;
}
使用一个额外的数组来跟踪索引,索引是最长子序列的一部分,然后遍历数组以打印所有相应的元素。
可以声明一个动态数组,其长度等于递增序列的最大长度。阵列ANS将保持最长的递增序列。
int *ans=(int*)malloc(sizeof(int)*max);
临时变量用于保持数组中最大长度的索引。
int index;
int length; //used to fill array ANS in reverse order.
for ( i = 0; i < n; i++ )
{
if ( max < lis[i] )
{
max = lis[i];
index=i;
}
}
length=max;
ans[length-1]=arr[index]; //filling array from the last
//last element will be the greatest element
length--;
while(index>0)
{
for(i=index-1;i>=0;i--)
{
if(lis[i]+1==lis[index] && arr[i]<arr[index])
{
ans[length-1]=arr[i];
index=i;
length--;
break;
}
}
}
for(i=0;i<max;i++)
{
printf("%d",ans[i]);
}
这里的复杂度是O(n)而不是O(n2),即使它可能使用两个循环,因为每当输入块时,我们都将索引的值更改为i。
不是最好的方法,但你可以尝试…
int lis(int ar[], int n) {
int max = INT_MIN;
int* lis = new int[n];
int* sub_arr = new int[n];
for (int i = 0; i < n; ++i)
lis[i] = 1;
for (int i = 1; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if(ar[i] > ar[j] && lis[j] + 1 >= lis[i]) {
lis[i] = lis[j] + 1;
sub_arr[i] = j;
}
}
}
for (int i = 0; i < n; ++i) {
if(max < lis[i])
max = ar[i];
}
int k = 0;
stack <int> st;
for (int i = 0; i < n; ++i) {
if(max == lis[i])
k = i;
}
cout << "Longest Incresing Subsequence : ";
st.push(k);
while(k > 0) {
st.push(sub_arr[k]);
k = sub_arr[k];
}
while (!st.empty()) {
cout << ar[st.top()] << ' ';
st.pop();
}
cout << endl;
return max;
}
如果有人对Java版本感兴趣。对解释进行了评论。
public int lengthOfLIS(int[] nums) {
if(nums.length == 0) return 0;
// array to store sub-problem solution. L[i] stores the length
// of the longest increasing sub-sequence ends with nums[i]
int[] L = new int[nums.length];
// used to print the actual LIS
int[] P = new int[nums.length];
// longest increasing sub-sequence having just one element has length 1
Arrays.fill(L, 1);
Arrays.fill(P, -1);
// start from second element in the array
for(int i=1; i<nums.length; i++) {
// do for each element in sub-array nums[0..i-1]
for(int j=0; j<i; j++) {
// find longest increasing sub-sequence that ends with nums[j]
// where nums[j] is less than the current element nums[i]
// and it extends the original sub-sequence increasingly
if(nums[j] < nums[i] && L[i] < L[j]+1) {
L[i] = L[j] + 1;
// store what index helped to extend L[i]
P[i] = j;
}
}
}
/* find the maximum LIS from L calculated also its index */
int max=L[0], maxIndex=0;
for(int i=1; i<nums.length; i++) {
if(max<L[i]) {
max=L[i];
maxIndex=i;
}
}
//starting from index of max-length LIS traverse back
//using P array populated earlier
while (maxIndex >= 0) {
System.out.print(nums[maxIndex]+", ");
maxIndex = P[maxIndex];
}
return max;
}
相关文章:
- Mongodb c++驱动程序:如何查询元素的数组
- 将数组的地址分配给变量并删除
- 从C++本机插件更新Vector3数组
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 数组索引的值没有增加
- 将对象数组的引用传递给函数
- 为char数组调整zlib-zpipe
- 2D数组来自文本输入,中间有空格
- std::向量与传递值的动态数组
- 在c++中用vector填充一个简单的动态数组
- 使用strcpy将char数组的元素复制到另一个数组
- 使用指针从C++中的数组中获取最大值
- C++使用整数的压缩数组初始化对象
- 告诉一个 const char 数组,除了编译时 C 样式的字符串外,它不以 '