题目描述:
给你一个数列,一次操作是指将某个数移到数列中别的位置上去,然后问最少要几次操作才能让数列变得有序。例如,数列7,1,3,2,6,5就只需要三次移动,把3移到2后面,把5移到6前面,再把7移到最后面即可。
问题等价转化:
其实就是一个最长上升子序列问题。因为整个操作过程实质上可以等价地看作是,把要移动的数先全部取出来,再挨个放回适当的位置。这就要求取出要移动的数后,剩下的那些数本身是有序的。若希望要移动的数越少越好,那也就等于说是剩下的不动的数要越多越好。
最长上升子序列问题:
给出一个由n个数组成的序列x[1..n],找出它的最长单调上升子序列。即求最大的m和a1,
a2……,am,使得a1
动态规划求解思路分析:(O(n^2))
经典的O(n^2)的动态规划
贪心+二分查找:(O(nlogn))
开辟一个栈,每次取栈顶元素s和读到的元素a做比较,如果a>s, 则加入栈;如果a
这也是很好理解的,对x和y,如果x
举例:原序列为1,5,8,3,6,7
栈为1,5,8,此时读到3,则用3替换5,得到栈中元素为1,3,8, 再读6,用6替换8,得到1,3,6,再读7,得到最终栈为1,3,6,7 ,最长递增子序列为长度4。
代码:
#include
using namespace std;
//DP:dp[i] = max{1,dp[j]+1} (j=1,2, ...,i-1,且A[j]
template
int Lis_Dp(T seq[],int n)
{
int *dp=new int[n];
memset(dp,0,n*sizeof(int));
dp[0]=1;
for(int i=1;i
{
int max=1;
for(int j=0;j
{
if(seq[j]
{
if(max
max=dp[j]+1;
}
}
dp[i]=max;
}
int ret=dp[n-1];
delete[] dp;
return ret;
}
template
int Lis_Greedy(T seq[],int n)
{
int top=0;
int *stack=new int[n];
memset(stack,0,n*sizeof(int));
stack[top]=seq[0];
for(int i=1;i
{
int low=0,high=top;
while(low<=high)
{
int mid=(low+high)/2;
if(stack[mid]
low=mid+1;
else
high=mid-1;
}
if(low==top+1)
top++;
stack[low]=seq[i];
}
delete[] stack;
return top+1;
}
int _tmain(int argc, _TCHAR* argv[])
{
int testdata[10]={4,6,3,2,5,1,5,7,9,8};
cout<
cout<
system("pause");
return 0;
}