给定一个int数组men,代表参加一场游戏依次来的每个人的身高,同时给定总人数n,要求一个人站在另一个人肩膀上,且下面的人比上面的人要更高一点。请返回最多能够叠的人数。注意参加游戏的人的先后顺序与原序列中的顺序应该一致保证,且n小于等于500。
测试样例:
[1,6,2,5,3,4],6
返回:4
# 最长公共子序列问题, 动态规划O(n^2) def getHeight1(self, men, n): if n < 1: return 0 x = men y = sorted(men) dp = [[0] * (n + 1) for i in range(n + 1)] for i in range(1, n + 1): for j in range(1, n + 1): if x[i-1] == y[j-1]: dp[i][j] = dp[i - 1][j - 1] + 1 else: dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) return dp[n][n]
# 动态规划 O(n ^ 2), 而且有结果集 def getHeight(self, men, n): if n < 1: return 0 dps = [[men[0]]] for i in range(1, n): maxOrder = [men[i]] for dp in dps: if dp[-1] < men[i] and len(dp) >= len(maxOrder): maxOrder = dp + [men[i]] dps.append(maxOrder) return len(max(dps, key=lambda a: len(a)))
# 动态规划 O(n^2) def getHeight(self, men, n): # dp[i]表示已第i个元素结尾的最长递增子序列的长度 dp = [0] * n dp[0] = 1 lgst = 0 for i in range(1, n): slgst = 0 sidx = 0 # 找到 men[0..i-1]中比men[i]小的对应的dp中的最大值 while sidx < i: if men[sidx] <= men[i]: slgst = slgst if slgst > dp[sidx] else dp[sidx] sidx += 1 dp[i] = slgst + 1 lgst = dp[i] if dp[i] > lgst else lgst return lgst
# 动态规划 O(nlogn) def getHeight(self, men, n): dp = [0] * n dp[0] = 1 bs = [0] * n bs[0] = men[0] # 在bs中找到第一个比x大的数并替换 def binary_search(x, end): i = 0 j = end while i <= j: mid = (i + j) / 2 if x > bs[mid]: i = mid + 1 else: j = mid - 1 end = max(end, i) bs[i] = x return i, end end = 0 # bs length for i in range(1, n): val, end = binary_search(men[i], end) dp[i] = val+1 return max(dp)
//最长递增子序列问题,牛客7.29动态规划串讲第一题,看了视频模仿写出了O(nlogn)的解法 class Stack { public: int getHeight(vector<int> men, int n) { // write code here int *dp = getDP(men, n);//记录以i为结尾的最长递增子序列 int res = 0; for(int i = 0; i < n; ++i) res = max(res, dp[i]); return res; } int* getDP(vector<int> men, int n){//求dp数组的函数 int *dp = new int[n]; int *help = new int[n];//最长子序列为j+1时候,长度为j序列最小值 help[0] = men[0]; dp[0] = 1; int end = 0;//记录help数组有有效值的末尾 int l = 0; int r = 0; for(int i = 1; i < n; ++i){//二分查找 l = 0; r = end; while(l <= r){ int mid = l + (r - l)/2; if(men[i] > help[mid]) l = mid + 1; else r = mid - 1; } end = max(end, l);//l为第一个比men[i]大的数的位置 help[l] = men[i]; dp[i] = l + 1; } return dp; } };
public class Stack { public int getHeight(int[] men, int n) { // write code here int[] res = new int[n]; res[0] = 1; int max = 1; for (int i=1; i<n; i++){ res[i] = 1; for (int j=i-1; j>=0; j--){ if (men[i] > men[j] && res[j]+1 > res[i]){ res[i] = res[j] + 1; } } max = Math.max(res[i], max); } return max; } }
题目搞错了应该……先来的人在下面,所以是最长递减子序列问题,把下面的判断身高的改成>即可。 class Stack { public: int getHeight(vector<int> men, int n) { int maxCount = 1; vector<int> dp(n, 1); for (int i = 1; i < n; ++i) { for (int j = 0; j < i; ++j) if (men[j] < men[i]) dp[i] = max(dp[i], dp[j] + 1); maxCount = max(maxCount, dp[i]); } return maxCount; } };
class Stack { public: int getHeight(vector<int> men, int n) { // write code here if(n == 0) return 0; vector<int>dp; dp.resize(men.size()); dp[0] = 1; int max_res = -1; //前面数字是否有小于当前数字的标志,初始为false bool flag = false; for (int i = 1; i < n; ++i) { int max_now = -1; int now = men[i]; for (int j = i; j > 0; j--) { if(now > men[j-1]) { flag = true; max_now = max(max_now, dp[j-1]); } } //有比当前值小的数,找到最大的数对应的dp+1 if(flag) dp[i] = max_now + 1; //最小的,dp =1 else dp[i] = 1; flag = false; max_res = max(max_res,dp[i]); } return max_res; } };
public int getHeight(int[] men, int n) { // write code here if(men == null){ return 0; } int[] dp = new int[n]; dp[0] = 1; for(int i = 1; i < n; i++){ dp[i] = 1; for(int j = i-1; j >= 0; j--){ if(men[i] >= men[j] && dp[j]+1 > dp[i]){ dp[i] = dp[j] + 1; } } } int max = 0; for(int i = 0; i < n; i++){ if(max < dp[i]){ max = dp[i]; } } return max; }
# -*- coding:utf-8 -*- # python2.7, time:32ms, memory:5752K class Stack: def getHeight(self, men, n): # write code here if n<=1: return n arr=[men[0]] maxlen=0 for v in men[1:]: l,r=0,maxlen res_idx=-1 while l<=r: mid=int((l+r)/2) if arr[mid] >= v: r = mid - 1 else: res_idx = max(res_idx, mid) l = mid + 1 if res_idx !=-1: if len(arr)<=res_idx+1: arr.append(v) else: arr[res_idx+1]=min(arr[res_idx+1], v) else: arr[0]=min(arr[0],v) maxlen = len(arr)-1 return maxlen+1求最长上升子序列即可. n*logn时间复杂度. arr[i]维护长度为i+1的最长上升子序列最大元素(即末尾元素)的最小值. arr为单调数组可进行二分查找.
class Stack { public: int getHeight(vector<int> men, int n) { // write code here memset(dp, 0, sizeof(dp)); dp[0] = 1; for (int i = 1; i < n; ++i) { dp[i] = 1; for (int j = 0; j < i; ++j) { if (men[j] < men[i] && dp[j] + 1 > dp[i]) { dp[i] = dp[j] + 1; } } } int ret = 0; for (int i = 0; i < n; ++i) { ret = max(ret, dp[i]); } return ret; } private: int dp[503] = {0}; };
class Stack { public: int getHeight(vector<int> men, int n) { // write code here vector<int>a{men[0]}; int k=0; for(int i=1;i<n;i++) { int l=0,r=k; while(l<=r) { int m=(l+r)/2; if(a[m]>=men[i]) r=m-1; else l=m+1; } if(l>k)a.push_back(men[i]),k++; else a[l]=men[i]; } return k+1; } }; 直接二分找到第一个比它大的替换,找不到加末尾,结果就是维护的二分查找数组的大小