leetcode(300)—— Longest Increasing Subsequence(最长递增子序列)
2016-06-08 11:33
609 查看
参考 Python 解法: 动态规划 —— 最长递增子序列(LIS)
原题位置:Longest Increasing Subsequence | LeetCode OJ
题目的说明:
严格递增;
子序列不要求连续;
如果遍历到的新元素比ends数组中的首元素小的话,替换首元素为此新元素,
如果遍历到的新元素比ends数组中的末尾元素还大的话,将此新元素添加到ends数组末尾(注意不覆盖原末尾元素)。
如果遍历到的新元素比ends数组首元素大,比尾元素小时,此时用二分查找法找到第一个不小于此新元素的位置,覆盖掉位置的原来的数字,
以此类推直至遍历完整个 nums 数组,此时 ends 数组的长度就是我们要求的 LIS 的长度,特别注意的是 ends 数组的值可能不是一个真实的LIS,比如若输入数组nums为 {4, 2, 4, 5, 3, 7},那么算完后的ends数组为{2, 3, 5, 7},可以发现它不是一个原数组的LIS,只是长度相等而已,千万要注意这点。
原题位置:Longest Increasing Subsequence | LeetCode OJ
题目的说明:
严格递增;
子序列不要求连续;
解法 1,O(n2)
class Solution { public: int lengthOfLIS(vector<int>& nums) { if (nums.size() == 0) return 0; vector<int> dp(nums.size(), 1); int res = 1; for (int i = 1; i < nums.size(); ++i){ // 每次外部循环,确定以当前位置为末尾元素的最长子序列; for (int j = 0; j < i; ++j){ if (nums[j] < nums[i]){ dp[i] = max(dp[i], 1+dp[j]); // 通过遍历 j 实现对 dp[i] 的更新 } } res = max(res, dp[i]); } return res; } };
解法2:O(nlogn)
思路是,我们先建立一个数组 ends,把首元素放进去,然后比较之后的元素,如果遍历到的新元素比ends数组中的首元素小的话,替换首元素为此新元素,
如果遍历到的新元素比ends数组中的末尾元素还大的话,将此新元素添加到ends数组末尾(注意不覆盖原末尾元素)。
如果遍历到的新元素比ends数组首元素大,比尾元素小时,此时用二分查找法找到第一个不小于此新元素的位置,覆盖掉位置的原来的数字,
以此类推直至遍历完整个 nums 数组,此时 ends 数组的长度就是我们要求的 LIS 的长度,特别注意的是 ends 数组的值可能不是一个真实的LIS,比如若输入数组nums为 {4, 2, 4, 5, 3, 7},那么算完后的ends数组为{2, 3, 5, 7},可以发现它不是一个原数组的LIS,只是长度相等而已,千万要注意这点。
class Solution(object): def lengthOfLIS(self, nums): n = len(nums) if n == 0: return 0 ends = [nums[0]] for i in range(1, n): if nums[i] < ends[0]: ends[0] = nums[i] elif nums[i] > ends[-1]: ends.append(nums[i]) else: lo, hi = 0, len(ends) while lo < hi: mi = (lo + hi)//2 if nums[i] > ends[mi]: lo = mi + 1 else: hi = mi ends[hi] = nums[i] return len(ends)
解法 3:思路更为清晰的二分查找
跟上面那种方法很类似,思路是先建立一个空的dp数组,然后开始遍历原数组,对于每一个遍历到的数字,我们用二分查找法在dp数组找第一个不小于它的数字,如果这个数字不存在,那么直接在dp数组后面加上遍历到的数字,如果存在,则将这个数字更新为当前遍历到的数字,最后返回dp数字的长度即可,注意的是,跟上面的方法一样,特别注意的是dp数组的值可能不是一个真实的LIS。参见代码如下:class Solution { public: int lengthOfLIS(vector<int>& nums) { vector<int> dp; for (int i = 0; i < nums.size(); ++i){ int lo = 0, hi = dp.size(); while (lo < hi){ int mi = (lo + hi)/2; if (dp[mi] < nums[i]) lo = mi + 1; else hi = mi; } if (hi == dp.size()) dp.push_back(nums[i]); else dp[hi] = nums[i]; } return dp.size(); } };
4. 借助标准库 STL 中的算法实现二分查找部分
lower_bound 返回返回序列中第一个不小于某值的元素位置;class Solution{ public: int lengthOfLIS(vector<int>& nums){ vector<int> dp; for (int i = 0; i < nums.size(); ++i){ auto it = lower_bound(dp.begin(), dp.end(), nums[i]); if (it == dp.end()) dp.push_back(nums[i]); else *it = nums[i]; } return dp.size(); } };
相关文章推荐
- 关于github上的pull request的翻译问题
- easyui datagrid 行右键 动态获取并生成toolbar 按钮
- 对require使用的一点理解
- iOS: 玩转UICollectionViewLayout
- jadx-gui反编译apk
- 生产项目中queue同步问题导致项目部署后CPU爆表问题解决
- 从request获取各种路径总结
- Fuel快速安装开源openstack的实践
- mysql索引类型Normal,Unique,Full Text区别及索引方法Btree,Hash的区别
- ProcessBuilder执行本地命令
- iOS开发概述UIkit动力学
- UITextField 设置左右视图、文字距离及字符长度限制
- UIImage两个初始化的区别
- Gengxin讲STL系列——Queue和Stack
- vue.js 之道vuex
- iOS App开发中的UISegmentedControl分段组件用法总结
- Gradle Build速度加快终极方法
- 用array_count_values统计一篇英文文档中每个单词的出现次数,结果用表格展示出来
- 解析:使用easyui的form提交表单,在IE下出现类似附件下载时提示是否保存的现象
- select下拉列表(easyui)