300. Longest Increasing Subsequence
2016-07-09 22:55
477 查看
Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given
The longest increasing subsequence is
is
for you to return the length.
Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
O(N^2)
dp[i] = max{dp[j]+1}, 1<=j<i,a[j]<a[i].,最后答案为dp[i]中最大的
以下分析摘自 http://yzmduncan.iteye.com/blog/1546503
考虑两个数a[x]和a[y],x<y且a[x]<a[y],且dp[x]=dp[y],当a[t]要选择时,到底取哪一个构成最优的呢?显然选取a[x]更有潜力,因为可能存在a[x]<a[z]<a[y],这样a[t]可以获得更优的值。在这里给我们一个启示,当dp[t]一样时,尽量选择更小的a[x].
按dp[t]=k来分类,只需保留dp[t]=k的所有a[t]中的最小值,设d[k]记录这个值,d[k]=min{a[t],dp[t]=k}。
这时注意到d的两个特点(重要):
1. d[k]在计算过程中单调不升;
2. d数组是有序的,d[1]<d[2]<..d
。
利用这两个性质,可以很方便的求解:
1. 设当前已求出的最长上升子序列的长度为len(初始时为1),每次读入一个新元素x:
2. 若x>d[len],则直接加入到d的末尾,且len++;(利用性质2)
否则,在d中二分查找,找到第一个比x小的数d[k],并d[k+1]=x,在这里x<=d[k+1]一定成立(性质1,2)。
注意:只能求长度,不能求具体的 LIS
For example,
Given
[10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is
[2, 3, 7, 101], therefore the length
is
4. Note that there may be more than one LIS combination, it is only necessary
for you to return the length.
Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
O(N^2)
dp[i] = max{dp[j]+1}, 1<=j<i,a[j]<a[i].,最后答案为dp[i]中最大的
public static int lengthOfLIS(int[] nums) { int len=nums.length; if(len<1) return 0; int[] dp=new int[len]; Arrays.fill(dp, 1); for(int i=1;i<len;i++) { int max=Integer.MIN_VALUE; for(int j=0;j<i;j++) if(nums[i]>nums[j]) max=Math.max(max, dp[j]); if(max>Integer.MIN_VALUE) dp[i]=max+1; } int maxlen=Integer.MIN_VALUE; for(int i=0;i<len;i++) maxlen=Math.max(maxlen, dp[i]); return maxlen; }
以下分析摘自 http://yzmduncan.iteye.com/blog/1546503
考虑两个数a[x]和a[y],x<y且a[x]<a[y],且dp[x]=dp[y],当a[t]要选择时,到底取哪一个构成最优的呢?显然选取a[x]更有潜力,因为可能存在a[x]<a[z]<a[y],这样a[t]可以获得更优的值。在这里给我们一个启示,当dp[t]一样时,尽量选择更小的a[x].
按dp[t]=k来分类,只需保留dp[t]=k的所有a[t]中的最小值,设d[k]记录这个值,d[k]=min{a[t],dp[t]=k}。
这时注意到d的两个特点(重要):
1. d[k]在计算过程中单调不升;
2. d数组是有序的,d[1]<d[2]<..d
。
利用这两个性质,可以很方便的求解:
1. 设当前已求出的最长上升子序列的长度为len(初始时为1),每次读入一个新元素x:
2. 若x>d[len],则直接加入到d的末尾,且len++;(利用性质2)
否则,在d中二分查找,找到第一个比x小的数d[k],并d[k+1]=x,在这里x<=d[k+1]一定成立(性质1,2)。
注意:只能求长度,不能求具体的 LIS
public class Solution { public int lengthOfLIS(int[] nums) { int[] dp = new int[nums.length]; int len = 0; for(int x : nums) { int i = Arrays.binarySearch(dp, 0, len, x); if(i < 0) i = -(i + 1); dp[i] = x; if(i == len) len++; } return len; } }
/** 最长递增子序列O(nlogn)算法: 状态转移方程:f[i] = max{f[i],f[j]+1},1<=j<i,a[j]<a[i]. 分析:加入x<y,f[x]>=f[y],则x相对于y更有潜力。 首先根据f[]值分类,记录满足f[t]=k的最小的值a[t],记d[k]=min{a[t]},f[t]=k. 1.发现d[k]在计算过程中单调不上升 2.d[1]<d[2]<...<d[k] (反证) 1 2 3 8 4 7 解法: 1. 设当前最长递增子序列为len,考虑元素a[i]; 2. 若d[len]<a[i],则len++,并将d[len]=a[i]; 否则,在d[0-len]中二分查找,找到第一个比它小的元素d[k],并d[k+1]=a[i].() */ #include <iostream> #include <cstdio> #include <cstring> using namespace std; 4000 const int N = 41000; int a ; //a[i] 原始数据 int d ; //d[i] 长度为i的递增子序列的最小值 int BinSearch(int key, int* d, int low, int high) { while(low<=high) { int mid = (low+high)>>1; if(key>d[mid] && key<=d[mid+1]) return mid; else if(key>d[mid]) low = mid+1; else high = mid-1; } return 0; } int LIS(int* a, int n, int* d) { int i,j; d[1] = a[1]; int len = 1; //递增子序列长度 for(i = 2; i <= n; i++) { if(d[len]<a[i]) j = ++len; else j = BinSearch(a[i],d,1,len) + 1; d[j] = a[i]; } return len; } int main() { int t; int p; scanf("%d",&t); while(t--) { scanf("%d",&p); for(int i = 1; i <= p; i++) scanf("%d",&a[i]); printf("%d\n",LIS(a,p,d)); } return 0; }
相关文章推荐
- 生成器模式(Builder)
- 关于UITableView中Cell的保持/保存 选中状态的简单方法
- hibernate中Query的list和iterator区别(续)
- UINavigationController 的一些坑
- POJ1904 King's Quest(完备匹配可行边:强连通分量)
- [置顶] The requested resource (/) is not available
- UINavigationController改变背景颜色
- LeetCode - 112. Path Sum
- Label设置行间距
- 火眼金睛:continue&break
- UESTC 842 天下归晋(树状数组)
- UESTC 841 休生伤杜景死惊开(树状数组)
- UESTC 838 母仪天下(树状数组)
- Parquet与ORC:高性能列式存储格式
- Android UI布局优化
- easyui datagrid 小结
- POJ1417 True Liars (并查集+背包)
- LeetCode - 63. Unique Paths II
- 使用UE4实现HTC Vive设备的简单操作
- UITableview禁止cell点击选中