DAY56
套磁很顺利,发现又有书读了!
300最长递增子序列
- 朴素法,这个好想,但是不对,比如
0 1 0 3 2 3
我的算法会找出0 1 3作为答案,而不是0 1 2 3
可以看出,后面的状态依赖于前面的状态:选了前面的3,就不会选出后面的2 3;
没选前面的3,就能够选出后面的2 3.
错误代码:
- class Solution {
- public:
- int lengthOfLIS(vector<int>& nums) {
- int len=1;
- for(int i=0;i<nums.size();i++){
- int ilen=1;
- int left=nums[i];
- for(int j=i+1;j<nums.size();j++){
- if(left<nums[j]){
- ilen++;
- left=nums[j];
- }
- }
- len=max(len,ilen);
- }
- return len;
- }
- };
- 动态规划,第一次接触,积攒经验。
Dp[i]的定义:dp[i]表示i之前包括i的以nums[i]为结尾的最长递增子序列的长度。
“尾部元素”很重要。
状态转移方程:好理解,遍历的思想
认真手写推导了,掌握了。
Code:
记得最后返回的是res就行,而不是dp的末位。
- class Solution {
- public:
- int lengthOfLIS(vector<int>& nums) {
- 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[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);
- }
- if(dp[i]>res) res=dp[i];
- }
- return res;
- }
- };
674最长连续递增序列
复习。滑动窗口法。
精心总结滑动窗口代码模板, 直接搞定80道Leetcode算法题_哔哩哔哩_bilibili
朴素法:
- class Solution {
- public:
- int findLengthOfLCIS(vector<int>& nums) {
- //朴素
- int res=1;
- for(int i=0;i<nums.size()-1;i++){
- for(int j=i;j<nums.size()-1;j++){
- if(nums[j]>=nums[j+1]) break;
- res=max(res,j+2-i);
- }
- }
- return res;
- }
- };
双指针:
- class Solution {
- public:
- int findLengthOfLCIS(vector<int>& nums) {
- //双指针
- int res=1;
- for(int l=0;l<nums.size();l++){
- int r=l+1;
- while(r<nums.size()&&nums[r]>nums[r-1]) r++;
- res=max(res,r-l);
- }
- return res;
- }
- };
滑动窗口复习:
精心总结滑动窗口代码模板, 直接搞定80道Leetcode算法题_哔哩哔哩_bilibili
练习:
209长度最小的子数组,中等
注意模版中,对与最长问题,要在外部while去更新bestres;
而在最短问题,需要在内部while去更新bestres;
- class Solution {
- public:
- int minSubArrayLen(int target, vector<int>& nums) {
- int l=0,r=0,bestres=0;
- int cursum=0;
- while(r<nums.size()){
- cursum+=nums[r];
- while(r<nums.size()&&cursum>=target){
- //这一句if也很重要
- if(r-l+1<bestres||bestres==0) bestres=r-l+1;
- cursum-=nums[l];
- l++;
- }
- r++;
- }
- return bestres;
- }
- };
ACWING799最长连续不重复子序列
799最长连续不重复子序列_哔哩哔哩_bilibili
讲得很好,主要是要手写模拟一遍。
CODE:
- #include<iostream>
- using namespace std;
- const int N=100010;
- int n;
- int a[N],b[N];
- int main(){
- cin>>n;
- int res=0;
- for(int i=0;i<n;i++) cin>>a[i];
- // i denotes begin, j denotes end
- for(int i=0,j=0;j<n;j++){
- b[a[j]]++;
- while(j>i&&b[a[j]]>1) b[a[i++]]--;
- res=max(res,j-i+1);
- }
- cout<<res<<endl;
- return 0;
- }
674最长连续递增序列
- 朴素 简单啦
- class Solution {
- public:
- int findLengthOfLCIS(vector<int>& nums) {
- int res=1;
- for(int i=0;i<nums.size();i++){
- int ilen=1;
- for(int j=i+1;j<nums.size();j++){
- if(nums[j-1]<nums[j]) ilen++;
- else break;
- }
- res=max(res,ilen);
- }
- return res;
- }
- };
- 双指针
- class Solution {
- public:
- int findLengthOfLCIS(vector<int>& nums) {
- int res=1;
- for(int l=0;l<nums.size()-1;l++){
- int llen=1;
- int r=l+1;
- while(r<nums.size()&&nums[r-1]<nums[r]) llen++,r++;
- res=max(res,llen);
- }
- return res;
- }
- };
- 动态规划
自己想出来了,很好。
- class Solution {
- public:
- int findLengthOfLCIS(vector<int>& nums) {
- int res=1;
- vector<int> dp(nums.size(),1);
- for(int i=1;i<nums.size();i++){
- if(nums[i-1]<nums[i]) dp[i]=dp[i-1]+1;
- res=max(res,dp[i]);
- }
- return res;
- }
- };
718最长重复子数组
- 很容易想到双指针,但是难点在于,怎么处理定位函数中,有多个定位函数结果,比如:
[0,1,3,2,5,8,9,7]
[0,5,4,2,6,2,3,4]
还是用动态规划吧。
- 动态规划,没接触过。
子数组就是连续子序列,没问题。
要想到:用二维数组记录两个字符串的所有比较情况。
学完了,在纸上手动推导一下DP数组:已完成。
一定要记得size()+1 初始化vector时候。
For()循环里也是<=size了,不然比较不完。
- class Solution {
- public:
- int findLength(vector<int>& nums1, vector<int>& nums2) {
- int res = 0;
- // 一定要记得size()+1
- vector<vector<int>> dp(nums1.size() + 1,
- vector<int>(nums2.size() + 1, 0));
- for (int i = 1; i <= nums1.size(); i++) {
- for (int j = 1; j <= nums2.size(); j++) {
- if (nums1[i - 1] == nums2[j - 1])
- dp[i][j] = dp[i - 1][j - 1] + 1;
- res = max(res, dp[i][j]);
- }
- }
- return res;
- }
- };