【打卡记录】【leecode】高效制胜学习计划

本文探讨了数组和树结构中常见的求和问题、斐波那契数列、动态规划法以及字符串处理的算法。通过二分查找、双指针、哈希表、递归和动态规划等技术解决了一系列编程挑战,如两数之和、三数之和、斐波那契数列、爬楼梯问题、最长子序列、监控二叉树等。
摘要由CSDN通过智能技术生成

文章目录

Day 1 求和问题

1. 两数之和 [数组 哈希表]

两数之和 🔗
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值target的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。

思路一:暴力解法

思路:

一层遍历:从左到右 依次为i
	二层遍历:从i到右 依次为j
		check:是否第i个和第j个数字加和为target 

时间复杂度: O ( N 2 ) O(N^2) O(N2)
空间复杂度: O ( 1 ) O(1) O(1)

思路二 哈希表

一次遍历:从左到右
	check哈希表中有无当前值的补数
		有,则直接输出答案
		无,则向哈希表中添加当前key及index

时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( N ) O(N) O(N),多为哈希表开销

vector<int> twoSum(vector<int>& nums, int target) {
    unordered_map<int,int> hashmap;
    int other;
    for(int i=0;i<nums.size();++i){
        auto it = hashmap.find(target - nums[i]);
        if (it != hashmap.end()) {  return {it->second, i}; }
        hashmap.insert(pair<int,int>(nums[i],i));
    }
    return {};
}

167. 两数之和 II - 输入有序数组【数组 双指针 二分查找】

两数之和 II - 输入有序数组 🔗
给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

注:本题是有序数组,是1的特例

思路一:二分查找

思路:

一层遍历:从左到右 依次为i——固定一值        O(N)
	在i右侧查找num[i]的补值(利用二分法)      O(logN)

时间复杂度: O ( N l o g N ) O(NlogN) O(NlogN)
空间复杂度: O ( 1 ) O(1) O(1)

思路二 双指针

left指左,right指右
	两个元素之和与target进行比较
		大:右-1
		小:左+1
		==:getAnswer

时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( 1 ) O(1) O(1)

 vector<int> twoSum(vector<int>& numbers, int target) {
   int low = 0, high = numbers.size() - 1;
    while (low < high) {
        int sum = numbers[low] + numbers[high];
        if (sum == target) { return {low + 1, high + 1};  } 
        else if (sum < target) { ++low; } 
        else { --high;}
    }
    return {-1, -1};
} 

Day 2 求和问题

15. 三数之和 [数组 双指针 排序]

三数之和 🔗
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

思路:排序+双指针

思路:

排序
一层遍历:从左到右 依次为 first [0,nsize-2) //确定第一个值  及  其余两值范围为右侧
	二层遍历:从first+1到右 依次为left
  			 从nsize-1到左 依次为right
  			 转换为两数之和的问题	
		check:是否第left个和第right个数字加和为 -first 

时间复杂度: O ( N 2 ) O(N^2) O(N2)
空间复杂度: O ( l o g N ) O(logN) O(logN)

vector<vector<int>> threeSum(vector<int>& nums) {
   vector<vector<int>> res;
    int nSize=nums.size();
    if(nSize<3) return res;
    sort(nums.begin(),nums.end());
    int second=1,third=2;
    for(int first=0;first<nSize-2;++first ){
        if(first>0&& nums[first]==nums[first-1]) { continue; }
        if(nums[first]>0) break;
        int right=nSize-1;
        int third=right;
        int target=-nums[first];
        for(int second=first+1;second<nSize-1;++second){
            if(second>first+1&& nums[second]==nums[second-1]) { continue; } 
            while(third>second&&nums[second] + nums[third] > target){ third--;}
            if (second == third) { break; }
            if (nums[second] + nums[third] == target) {
                res.push_back({nums[first], nums[second], nums[third]});
            }
        }
    }
    return res;
}

18. 四数之和 [数组 双指针 排序]

四数之和 🔗
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [ n u m s [ a ] , n u m s [ b ] , n u m s [ c ] , n u m s [ d ] ] [nums[a], nums[b], nums[c], nums[d]] [nums[a],nums[b],nums[c],nums[d]]

  • 0 < = a , b , c , d < n 0 <= a, b, c, d < n 0<=a,b,c,d<n
  • a、b、c 和 d 互不相同
  • n u m s [ a ] + n u m s [ b ] + n u m s [ c ] + n u m s [ d ] = = t a r g e t nums[a] + nums[b] + nums[c] + nums[d] == target nums[a]+nums[b]+nums[c]+nums[d]==target
    你可以按 任意顺序 返回答案 。

思路:排序+双指针

思路:确定两值,以 转换为二数之和的问题

排序
一层遍历:从左到右 依次为 first [0,nsize-2) //确定第一个值  及  其余三值范围为右侧
	二层遍历:从左到右 依次为 second [first+1,nsize-2) //确定第2个值  及  其余两值范围为右侧
		二层遍历:从second +1到右 依次为left
	  			 从nsize-1到左 依次为right
	  			 转换为两数之和的问题	
			check:是否第left个和第right个数字加和为 -first -second

时间复杂度: O ( N 3 ) O(N^3) O(N3)
空间复杂度: O ( l o g N ) O(logN) O(logN)

vector<vector<int>> fourSum(vector<int>& nums, int target) {
    vector<vector<int>> res;
    int s=nums.size();
    if(s<4) return res;
    sort(nums.begin(),nums.end());

    for(int first=0;first<s-3;++first ){
        if(first>0&& nums[first]==nums[first-1]) continue;
        for(int second=first+1;second<s-2;++second){
            if(second>first+1&& nums[second]==nums[second-1]) continue;
            int t2=target-nums[first]-nums[second];
            int right=s-1;

            for(int third=second+1;third<s-1;++third){
                int forth=right;
                if(third>second+1&& nums[third]==nums[third-1]) continue; 
                while(forth>third&&nums[forth] + nums[third] > t2)  forth--;
                if (forth == third) break;
                if (nums[forth] + nums[third] == t2) {
                    right=forth;
                    res.push_back({nums[first], nums[second], nums[third],nums[forth]});
                }
            }
        }
    }
    return res;
}

Day 3 斐波那契数列

509. 斐波那契数列 [递归 记忆化搜索 数学] E

509 斐波那契数 🔗
斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F ( 0 ) = 0 , F ( 1 ) = 1 F(0) = 0,F(1) = 1 F(0)=0F(1)=1 F ( n ) = F ( n − 1 ) + F ( n − 2 ) , 其 中 n > 1 F(n) = F(n - 1) + F(n - 2),其中 n > 1 F(n)=F(n1)+F(n2)n>1
给你 n ,请计算 F(n) 。

思路:记忆化递归

思路:

固定变量 f0, f1 恒存储F(n-2) F(n-1)
迭代获取F(n)即可

时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( 1 ) O(1) O(1)

int fib(int n) {
    if(n<2)return n;
    int f0=0,f1=1,res; 
    while(n>1){
        res=f1+f0;
        f0=f1;
        f1=res;
        --n;
    }
    return res;
}

70. 爬楼梯 [记忆化搜索 数学 动态规划]

70 爬楼梯 🔗
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 注意:给定 n 是一个正整数。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

思路:记忆化递归

思路:

固定变量 f0, f1 恒存储F(n-2) F(n-1)
迭代获取F(n) = F(n - 1) + F(n - 2)即可

时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( 1 ) O(1) O(1)

int climbStairs(int n) {
    if(n<3)return n;
    int f1=1,f2=2,res; 
    while((n--)>2){
        res=f1+f2;
        f1=f2;
        f2=res;
    }
    return res;
}

Day 4 动态规划法

53. 最大子序和 [数组 分治 动态规划] E

53 最大子序和 🔗
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

思路:记忆化递归

思路:
动态规划转移方程: f ( i ) = max ⁡ { f ( i − 1 ) + f(i)=\max \{f(i-1)+ f(i)=max{f(i1)+ nums [ i ] [i] [i], nums [ i ] } [i]\} [i]}
时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( 1 ) O(1) O(1)

int maxSubArray(vector<int>& nums) {
    int pre = 0, maxAns = nums[0];
    for (const auto &x: nums) {
        pre = max(pre + x, x);
        maxAns = max(maxAns, pre);
    }
    return maxAns;
}

416. 分割等和子集 [数组 动态规划] M

416 分割等和子集 🔗
给一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

思路:动态规划

思路:
动态规划转移方程: p [ j ] = d p [ j ] ∣ d p [ j − n u m s [ i ] ] p[j]=dp[j] ∣ dp[j−nums[i]] p[j]=dp[j]dp[jnums[i]]
时间复杂度: O ( n × t a r g e t ) O(n×target) O(n×target)
空间复杂度: O ( t a r g e t ) O(target) O(target)

bool canPartition(vector<int>& nums) {
    int sum=accumulate(nums.begin(),nums.end(),0);//求取总和
    if(sum%2) return false; //若有余 则无法均分
    int target=sum/2;
    int n=nums.size();
    vector<bool>dp(target+1,false);//看是否可达成target的总和
    dp[0]=true;
    for(int i=0;i<nums.size();++i){
        for(int j=target;j>=nums[i];--j){
            dp[j]=dp[j]||dp[j-nums[i]];
        }
    }
    return dp[target];
}

322. 零钱兑换 [广度优先搜索 数组 动态规划] M

322 零钱兑换 🔗
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
1 < = c o i n s . l e n g t h < = 12 1 < = c o i n s [ i ] < = 2 31 − 1 0 < = a m o u n t < = 1 0 4 1 <= coins.length <= 12\\1 <= coins[i] <= 2^{31} - 1 \\0 <= amount <= 10^4 1<=coins.length<=121<=coins[i]<=23110<=amount<=104

思路:动态规划

思路:
动态规划转移方程: d p [ a m o u n t ] = m i n ( d p [ a m o u n t ] , d p [ a m o u n t − c o i n s [ i ] ] + 1 ) dp[amount]=min(dp[amount], dp[amount−coins[i]]+1) dp[amount]=min(dp[amount],dp[amountcoins[i]]+1)
时间复杂度: O ( a m o u n t × c o i n s . s i z e ( ) ) O(amount×coins.size()) O(amount×coins.size())
空间复杂度: O ( a m o u n t ) O(amount) O(amount)

const int top=10001;
int coinChange(vector<int>& coins, int amount) {
    if(amount==0)return 0;
    sort(coins.begin(),coins.end());
    int n=coins.size();
    vector<int> dp(amount+1,top);
    dp[0]=0;
    for(int j=coins[0];j<=amount;++j){
        for(int i=0;i<n;++i){
            if(j<coins[i])break;
            dp[j]=min(dp[j],dp[j-coins[i]]+1);
        }
    }
    return dp[amount]==top?-1:dp[amount];
}

Day 5 堆栈

20.有效的括号 [栈 字符串] E

20 有效的括号 🔗
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。

思路:遍历+栈

思路:
将左括号放入栈 右括号消除左括号, 看可否成功消除及最终栈是否为空
时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( 1 ) O(1) O(1)

char isright(char &c){
    char left='#';//isleft;
    if(c==')')left='(';
    else if(c=='}')left='{';
    else if(c==']')left='[';
    return left;
}
bool isValid(string s) {
    if(s.length()%2)  return false;
    stack<char> stk;
    char left;
    for(char& c:s){
        left=isright(c);
        if(left=='#')stk.push(c);
        else{
            if(stk.empty()||stk.top()!=left)return false;
            stk.pop();
        }
    }
    return stk.empty();
}    

496. 下一个更大元素I [栈 数组 哈希表 单调栈] E

496 下一个更大元素I 🔗
给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。

思路:哈希表+单调栈

  1. 对 nums2 中的每一个元素,求出它的右边第一个更大的元素;//单调栈的方法
  2. 将上一步的对应关系放入哈希表(HashMap)中;
  3. 遍历数组 nums1,根据哈希表找出答案。
    时间复杂度: O ( N + M ) O(N+M) O(N+M),分别遍历数组 nums1 和数组 nums2 各一次即可
    空间复杂度: O ( N ) O(N) O(N)
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
    unordered_map<int,int>hashmap;
    int res=-1;
    stack<int>stk;
    stk.push(nums2[0]);
    for(int i=1;i<nums2.size();++i){
        while(!stk.empty()&&stk.top()<nums2[i]){
            hashmap[stk.top()]=nums2[i];
            stk.pop();
        }
        stk.push(nums2[i]);
    }
    while(!stk.empty()){
        hashmap[stk.top()]=-1;
        stk.pop();
    }
    vector<int>ans(nums1.size());
    for(int i=0;i<nums1.size();++i){
        ans[i]=hashmap[nums1[i]];
    }
    return ans;
}

456. 132模式 [栈 数组 二分查找 有序集合] M

456 132模式 🔗
给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。
如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false 。

思路:动态规划

思路:
时间复杂度: O ( n ) O(n) O(n)。枚举 i i i 的次数为 O ( n ) O(n) O(n),由于每一个元素最多被加入和弹出单调栈各一次,因此操作单调栈的时间复杂度一共为 O ( n ) O(n) O(n),总时间复杂度为 O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n),即为单调栈需要使用的空间。

bool find132pattern(vector<int>& nums) {
    int n = nums.size();
    stack<int> candidate_k;
    candidate_k.push(nums[n - 1]);
    int max_k = INT_MIN;

    for (int i = n - 2; i >= 0; --i) {
        if (nums[i] < max_k) {
            return true;
        }
        while (!candidate_k.empty() && nums[i] > candidate_k.top()) {
            max_k = candidate_k.top();
            candidate_k.pop();
        }
        if (nums[i] > max_k) {
            candidate_k.push(nums[i]);
        }
    }

    return false;
}

Day 6 数字

119.杨辉三角II [数组 动态规划] E

119 杨辉三角 II 🔗
给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。

思路:一维动态规划

思路:
从右往左层序更新
时间复杂度: O ( r o w I n d e x 2 ) O(rowIndex^2) O(rowIndex2)
空间复杂度: O ( 1 ) O(1) O(1) 不考虑返回值的空间占用。

vector<int> getRow(int rowIndex) {
    vector <int> res(rowIndex+1,1);
    for(int r=2;r<=rowIndex;++r){
        for(int i=r-1;i>0;--i){
            res[i]+=res[i-1];
        }
    }
    return res;
}  

279. 完全平方数 [DFS 数字 动态规划] M

279 完全平方数 🔗
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

思路:动态规划

状态转移。
时间复杂度: O ( n n ) O(n\sqrt n) O(nn )
空间复杂度: O ( n ) O(n) O(n)

int numSquares(int n) {
    vector<int> dp(n + 1, INT_MAX);
    dp[0] = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j * j <= i; ++j) {
            dp[i] = min(dp[i], dp[i-j*j] + 1);
        }
    }
    return dp[n];
}

483. 最小好进制 [数字 二分查找] H

483 最小好进制 🔗
对于给定的整数 n, 如果n的k(k>=2)进制数的所有数位全为1,则称 k(k>=2)是 n 的一个好进制。
以字符串的形式给出 n, 以字符串的形式返回 n 的最小好进制。

思路:数学

思路:

string smallestGoodBase(string n) {
    long nVal = stol(n);
    int mMax = floor(log(nVal) / log(2));
    for (int m = mMax; m > 1; m--) {
        int k = pow(nVal, 1.0 / m);
        long mul = 1, sum = 1;
        for (int i = 0; i < m; i++) {
            mul *= k;
            sum += mul;
        }
        if (sum == nVal) {
            return to_string(k);
        }
    }
    return to_string(nVal - 1);
}

Day 7 树

112.路径总和 [树 dfs 二叉树] E

112 路径总和 🔗
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。
叶子节点 是指没有子节点的节点。

思路:迭代+dfs

思路:
时间复杂度: O ( N ) O(N) O(N) N:树的节点数。对每个节点访问一次
空间复杂度: O ( H ) O(H) O(H) H H H 是树的高度。空间复杂度主要取决于递归时栈空间的开销,最坏情况下,树呈现链状,空间复杂度为 O ( N ) O(N) O(N)。平均情况下树的高度与节点数的对数正相关,空间复杂度为 O ( l o g N ) O(logN) O(logN)

bool hasPathSum(TreeNode* root, int targetSum) {
    if(!root) return false;
    if(!root->left&&!root->right) return root->val==targetSum;
    return ( root->left&&hasPathSum(root->left,targetSum-root->val))||(root->right&&hasPathSum(root->right,targetSum-root->val));
}

230. 二叉搜索树中第K小的元素 [树 DFS 二叉搜索树] M

230 二叉搜索树中第K小的元素 🔗
给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

思路:动态规划

int count=0;  
int ans;
void search(TreeNode* t,int k){
    if(t->left!=nullptr) search(t->left,k);
    count++;
    if(count==k){ ans=t->val; return; }
    else if(count>k) return ;
    if(t->right!=nullptr) search(t->right,k);
}
int kthSmallest(TreeNode* root, int k) {
    if(root==nullptr) return 0;
    search(root,k);
    return ans;
}

968. 监控二叉树 [树 DFS 动态规划] H

968 监控二叉树 🔗
给定一个二叉树,我们在树的节点上安装摄像头。节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。计算监控树的所有节点所需的最小摄像头数量。

思路:数学

思路:

struct Status {
    int a, b, c;
};
Status dfs(TreeNode* root) {
    if (!root) return {INT_MAX / 2, 0, 0};
    auto [la, lb, lc] = dfs(root->left);
    auto [ra, rb, rc] = dfs(root->right);
    int a = lc + rc + 1;
    int b = min(a, min(la + rb, ra + lb));
    int c = min(a, lb + rb);
    return {a, b, c};
}
int minCameraCover(TreeNode* root) {
    auto [a, b, c] = dfs(root);
    return b;
}

Day 8 字符串

720.词典中最长的单词 [字典树 数组 哈希表 字符串] E

720 词典中最长的单词 🔗
给出一个字符串数组words组成的一本英语词典。从中找出最长的一个单词,该单词是由words词典中其他单词逐步添加一个字母组成。若其中有多个可行的答案,则返回答案中字典序最小的单词。
若无答案,则返回空字符串。

思路:哈希表

string longestWord(vector<string>& words) {
    sort(words.begin(), words.end());//从小到大排序
    unordered_set<string> mySet;
    string ans = "";  //从空开始记录
    mySet.insert(ans);
    for(auto& word: words){
        if(mySet.find(string(word.begin(), word.end() - 1)) != mySet.end()){
            if(word.size() > ans.size()) ans = word; //如果长度更长,更新答案
            mySet.insert(word);  //记录这个单词
        }
    }
    return ans;
}

3. 无重复字符的最长字串 [哈希表 字符串 滑动窗口] M

3 无重复字符的最长字串 🔗
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

思路:哈希表+滑动窗口

状态转移。
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

int lengthOfLongestSubstring(string s) {
    unordered_map<char,int>hashmap;
    int res=0, start=0;
    for(int i=0;i<s.size();++i){
        if(hashmap.count(s[i])>0&&hashmap[s[i]]>=start){
            res=max(res,i-start);
            start=hashmap[s[i]]+1;
        }
        hashmap[s[i]]=i;            
    }
    res=max(res,(int)s.size()-start);
    return res;
}

97. 交错字符串 [字符串 动态规划] M 📓

97 交错字符串 🔗
给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。
两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串:
s = s1 + s2 + … + sn
t = t1 + t2 + … + tm
|n - m| <= 1
交错 是 s1 + t1 + s2 + t2 + s3 + t3 + … 或者 t1 + s1 + t2 + s2 + t3 + s3 + …
提示:a + b 意味着字符串 a 和 b 连接。

思路:数学

思路:

bool isInterleave(string s1, string s2, string s3) {
	int l1 = s1.length(), l2 = s2.length(), l3 = s3.length();
	s1.insert(s1.begin(),'0');
	s2.insert(s2.begin(),'0');
	s3.insert(s3.begin(),'0');
	if(l3 != l1 + l2) return false;
	bool dp[l3+1][l1+1];

	for(int i = 0; i <= l3; ++i) 
			memset(dp[i], false, sizeof(dp[i]));
	for(int i = 0; i <= l1; ++i) 
			dp[0][i] = true;

	for(int i = 1; i <= l3; ++i) 
		for(int j = 0; j <= min(i, l1); ++j) {
			int k = i - j;
			dp[i][j] = (j>=1 && dp[i-1][j-1] && s1[j] == s3[i]) || (dp[i-1][j] && s2[k]==s3[i]);
		}
	return dp[l3][l1];
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的微信小程序制作学习计划打卡记录页面的代码示例: ```html <!-- index.wxml --> <view class="container"> <view class="header">学习计划打卡记录</view> <view class="content"> <view class="plan"> <view class="plan-title">今日计划</view> <view class="plan-item" wx:for="{{planList}}" wx:key="index"> <checkbox value="{{item.checked}}" bindchange="onPlanChange">{{item.title}}</checkbox> </view> </view> <view class="record"> <view class="record-title">打卡记录</view> <view class="record-item" wx:for="{{recordList}}" wx:key="index"> <checkbox checked="{{item.checked}}" disabled="{{!item.enable}}">{{item.date}}</checkbox> </view> </view> </view> </view> ``` ```css /* index.wxss */ .container { display: flex; flex-direction: column; height: 100%; } .header { background-color: #007aff; color: #fff; font-size: 18px; text-align: center; line-height: 50px; } .content { flex: 1; display: flex; flex-direction: column; padding: 20px; } .plan { margin-bottom: 20px; } .plan-title { font-size: 16px; font-weight: bold; margin-bottom: 10px; } .plan-item { display: flex; align-items: center; margin-bottom: 10px; } .record-title { font-size: 16px; font-weight: bold; margin-bottom: 10px; } .record-item { display: flex; align-items: center; margin-bottom: 10px; } ``` ```javascript // index.js Page({ data: { planList: [ { title: '阅读一篇英文文章', checked: false }, { title: '学习一小时编程', checked: false }, { title: '完成一个小项目', checked: false }, ], recordList: [], }, onPlanChange(event) { const { index } = event.currentTarget.dataset; const { value } = event.detail; this.setData({ [`planList[${index}].checked`]: value, }); this.updateRecordList(); }, updateRecordList() { const recordList = []; const today = new Date().toLocaleDateString(); this.data.planList.forEach((plan, index) => { if (plan.checked) { recordList.push({ date: today, checked: true, enable: true, }); } else { const lastRecord = this.data.recordList[index - recordList.length]; if (lastRecord && lastRecord.date === today) { recordList.push(lastRecord); } else { recordList.push({ date: today, checked: false, enable: false, }); } } }); this.setData({ recordList }); }, }); ``` 这个页面包含两个部分:学习计划打卡记录学习计划部分使用 `checkbox` 组件表示每日计划,当用户勾选计划后,会更新打卡记录部分的内容。打卡记录部分使用 `checkbox` 组件表示每天的打卡情况,已经打卡过的日期会被禁用。 在 `onPlanChange` 方法中,我们处理计划勾选状态的变化,并且调用 `updateRecordList` 方法更新打卡记录。在 `updateRecordList` 方法中,我们根据计划的勾选状态和之前的打卡记录生成新的打卡记录。这个方法会在页面加载和计划勾选状态变化时被调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值