当前位置: 首页 > news >正文

Leetcode hot100 (day 8,9)

爬楼梯

做法一:小斐波那契数列,只要注意记忆化递归即可

    
    
class Solution {
public:
   int dp[50];
    int climbStairs(int n) {
        if(dp[n])return dp[n];
        if(n==2)
        {
            return dp[2]=2;
        }
        if(n==1)
        {
            return dp[1]=1;
        }
        //if(dp[n])return dp[n];
        return dp[n]=climbStairs(n-1)+climbStairs(n-2);
    }
};

做法二:动态规划,使用滚动数组即可

class Solution {
public:
    int climbStairs(int n) {
        int l,m,r;
        r=1,l=0,m=0;
        for(int i=1;i<=n;i++)
        {
            l=m;
            m=r;
            r=l+m;
        }
        return r;
    }
};

杨辉三角

相加 注意判断边界

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> ret(numRows);
        for(int i=0;i<numRows;i++)
        {
            ret[i].resize(i+1);
            ret[i][0]=ret[i][i]=1;
            for(int j=1;j<i;j++)ret[i][j]=ret[i-1][j]+ret[i-1][j-1];
        }
        return ret;
    }
};

打家劫舍

做法:动态规划,dp[n]=max(dp[n-1],dp[n-2]+nums[n])。并且要注意,要先判断nums的大小,不然赋值dp[1]的时候会出现错误。可以用滚动数组

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size()==1)return nums[0];
       vector<int> dp=vector<int>(nums.size(),0);
       dp[0]=nums[0];
       dp[1]=max(nums[0],nums[1]);
       for(int i=2;i<nums.size();i++)dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
       return dp[nums.size()-1];

    }
};

完全平方数

做法:动态规划

class Solution {
public:
    int numSquares(int n) {
        vector<int> f(n+1);
        for(int i=1;i<=n;i++)
        {
            int minn=INT_MAX;
            for(int j=1;j*j<=i;j++)
            {
                minn=min(minn,f[i-j*j]);
            }
            f[i]=minn+1;
        }
        return f[n];
    }
};

零钱兑换

做法一:记忆化搜索,每个递归都列举所有硬币,向下搜索,amount为0返回0,如果小于0,返回-1,也就是不成功。要注意记忆化,不然会超时

class Solution {
public:
    vector<int>count;
    int dp(vector<int>&coins,int amount)
    {
        if(amount<0)return -1;
        if(amount==0)return 0;
        if(count[amount])
        {
            return count[amount];
        }
        int Min=INT_MAX;
        for(int coin:coins)
        {
            int res=dp(coins,amount-coin);
            if(res>=0)Min=min(res+1,Min);
        }
        count[amount]=Min==INT_MAX?-1:Min;
        return count[amount];
    }
    int coinChange(vector<int>& coins, int amount) {
        if(amount==0)return 0;
        count.resize(amount+1);
        return dp(coins,amount);
    }
};

做法二:动态规划dp,其实和前面差不多

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int>dp(amount+1,INT_MAX-10);
        dp[0]=0;
        for(int i=1;i<=amount;i++)
        {
            for(int coin:coins)
            {
                if(coin<=i)dp[i]=min(dp[i],dp[i-coin]+1);
            }
        }
        return dp[amount]>=INT_MAX-10?-1:dp[amount];
    }
};

单词拆分

做法:动态规划,先用哈希存储word,后续查找为O(1),随后用dp思想即可

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> word;
        for(auto dic:wordDict) word.insert(dic);
        vector<int>dp(s.size()+1);
        dp[0]=1;
        for(int i=1;i<=s.size();i++)
        {
            for(int j=0;j<i;j++)
            {
                if(dp[j]&&word.find(s.substr(j,i-j))!=word.end())
                {
                    dp[i]=1;
                    break;
                }
            }
        }
        return dp[s.size()];
    }
};

最长递增子序列

做法一:动态规划。这里学习到了max_element min_element,返回数组或者vector中最大最小值,加*为值

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        vector<int> dp(nums.size(),0);
        for(int i=0;i<nums.size();i++)
        {
            dp[i]=1;
            for(int j=0;j<i;j++)
            {
                if(nums[j]<nums[i])dp[i]=max(dp[i],dp[j]+1);
            }
        }
        return *max_element(dp.begin(),dp.end());
    }
};

做法二:这个有点不好理解,再试试把。优化时间复杂度为O(nlogn)

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int len=1,n=nums.size();
        vector<int> d(n+1,0);
        d[len]=nums[0];
        for(int i=1;i<n;i++)
        {
            if(nums[i]>d[len])d[++len]=nums[i];
            else
            {
                int l=1,r=len,pos=0;
                while(l<=r)
                {
                    int mid=(l+r)>>1;
                    if(d[mid]<nums[i])
                    {
                        pos=mid;
                        l=mid+1;
                    }
                    else{
                        r=mid-1;
                    }
                }
                d[pos+1]=nums[i];
            }
        }
        return len;
    }
};

 


乘积最大子数组

做法:动态规划。不同的是,要保持一个最大值和最小值,因为如果当前数字为负数,那么说不定前面有负数的情况更大

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        long maxF=nums[0],minF=nums[0],ans=nums[0];
        for(int i=1;i<nums.size();i++)
        {
            long mx=maxF,mn=minF;
            maxF=max(maxF*nums[i],max((long)nums[i],mn*nums[i]));
            minF=min(mn*nums[i],min((long)nums[i],mx*nums[i]));
            ans=max(maxF,ans);
        }
        return ans;
    }
};

分割等和数组

做法:动态规划 dp[i][j],前i+1个数字,满足和为j为true。这样推上来即可

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int n=nums.size();
        if(n<2)return false;
        int sum=0,maxnum=0;
        for(auto &num:nums)
        {
            sum+=num;
            maxnum=max(maxnum,num);
        }
        if(sum&1)return false;
        int target=sum/2;
        if(maxnum>target)return false;
        vector<int> dp(target+1,0);
        dp[0]=true;
        for(int i=0;i<n;i++)
        {
            int num=nums[i];
            for(int j=target;j>=num;j--)dp[j]|=dp[j-num];
        }
        return dp[target];
    }
};

最长有效括号

做法一:动态规划,当前为i,如果s[i]==‘(’,那么必然dp[i]=0,如果为')',那么肯定要接着考虑前一位,如果为'(',dp[i]=dp[i-2]+2;如果为')',那么就需要考虑i-dp[i-1]-1是否大于0,以及s[i-dp[i-1]-1]是否为'(',如果是的话还要加上dp[i-dp[i-1]-2]

class Solution {
public:
    int longestValidParentheses(string s) {
        int maxans=0,n=s.size();
        vector<int> dp(n,0);
        for(int i=1;i<n;i++)
        {
            if(s[i]==')')
            {
                if(s[i-1]=='(')
                {
                    dp[i]=(i>=2?dp[i-2]:0)+2;
                }
                else if(i-dp[i-1]>0&&s[i-dp[i-1]-1]=='(')
                {
                    dp[i]=dp[i-1]+((i-dp[i-1])>=2?dp[i-dp[i-1]-2]:0)+2;
                }
                maxans=max(maxans,dp[i]);
            }
        }
        return maxans;
    }
};

做法二:栈

class Solution {
public:
    int longestValidParentheses(string s) {
        int maxans=0;
        stack<int> stk;
        stk.push(-1);
        for(int i=0;i<s.size();i++)
        {
            if(s[i]=='(')
            {
                stk.push(i);
            }
            else
            {
                stk.pop();
                if(stk.empty())
                {
                    stk.push(i);
                }
                else{
                    maxans=max(maxans,i-stk.top());
                }
            }
           
        }
        return maxans;
    }
};

最长有效路径

做法一:动态规划,f[i][j]=f[i-1][j]+f[i][j-1],同时要注意边界,由于第i行的状态只和第i-1行以及i行有关,所以可以用一维数组来滚动即可

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<int> f(n,1);
        for(int i=1;i<m;i++)
        {
            for(int j=1;j<n;j++)f[j]+=f[j-1];
        }
        return f[n-1];
    }
};

做法二:高中组合数

class Solution {
public:
    int uniquePaths(int m, int n) {
        long long ans=1;
        for(int x=n,y=1;y<m;x++,y++)
        {
            ans=ans*x/y;
        }
        return ans;
    }
};

最小路径和

做法一:和前面一样,dp即可

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int rows=grid.size(),columns=grid[0].size();
        auto dp=vector<vector<int>>(rows,vector<int>(columns));
        dp[0][0]=grid[0][0];
        for(int i=1;i<rows;i++)
        {
            dp[i][0]=dp[i-1][0]+grid[i][0];
        }
        for(int j=1;j<columns;j++)
        {
            dp[0][j]=dp[0][j-1]+grid[0][j];
        }
        for(int i=1;i<rows;i++)
        {
            for(int j=1;j<columns;j++)
            {
                dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];
            }
        }
        return dp[rows-1][columns-1];
    }
};

最长回文子串

做法一:动态规划,逐步遍历子串长度,从L=2开始

class Solution {
public:
    string longestPalindrome(string s) {
        int len=s.length();
        if(len<2)return s;
        int maxlen=1;
        int begin=0;
        vector<vector<bool>>dp(len,vector<bool>(len));
        for(int i=0;i<len;i++)
        {
            dp[i][i]=true;
        }
        for(int L=2;L<=len;L++)
        {
            for(int i=0;i<len;i++)
            {
                int j=L+i-1;
                if(j>=len)break;
                if(s[i]!=s[j])dp[i][j]=false;
                else
                {
                    if(j-i<3)
                    {
                        dp[i][j]=true;
                    }
                    else
                    {
                        if(j-i<3)
                        {
                            dp[i][j]=true;
                        }
                        else
                        {
                            dp[i][j]=dp[i+1][j-1];
                        }
                    }
                    if(dp[i][j]&&j-i+1>maxlen)
                    {
                        maxlen=j-i+1;
                        begin=i;
                    }
                }
            }
        }
        return s.substr(begin,maxlen);
    }
};

做法二:中心扩展,对于每个位置,都看能否扩展

class Solution {
public:
    pair<int,int> expand(const string& s,int left,int right)
    {
        while(left>=0&&right<s.size()&&s[left]==s[right])
        {
            left--;
            right++;
        }
        return {left+1,right-1};
    }
    string longestPalindrome(string s) {
        int start=0,end=0;
        for(int i=0;i<s.size();i++)
        {
            auto [left1,right1]=expand(s,i,i);
            auto [left2,right2]=expand(s,i,i+1);
            if(right1-left1>end-start)
            {
                start=left1;
                end=right1;
            }
            if(right2-left2>end-start)
            {
                start=left2;
                end=right2;
            }
        }
        return s.substr(start,end-start+1);
    }
};

最长公共子序列

做法:动态规划

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int m=text1.size(),n=text2.size();
        vector<vector<int>> dp(m+1,vector<int>(n+1));
        for(int i=1;i<=m;i++)
        {
            char c1=text1[i-1];
            for(int j=1;j<=n;j++)
            {
                char c2=text2[j-1];
                if(c1==c2)dp[i][j]=dp[i-1][j-1]+1;
                else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        }
        return dp[m][n];
    }
};

编辑距离

做法:dp

class Solution {
public:
    int minDistance(string word1, string word2) {
        int n=word1.size();
        int m=word2.size();
        if(n*m==0)return n+m;
        vector<vector<int>> dp(n+1,vector<int>(m+1));
        for(int i=0;i<n+1;i++)dp[i][0]=i;
        for(int j=0;j<m+1;j++)dp[0][j]=j;
        for(int i=1;i<n+1;i++)
        {
            for(int j=1;j<m+1;j++)
            {
                int left=dp[i-1][j]+1;
                int down=dp[i][j-1]+1;
                int left_down=dp[i-1][j-1];
                if(word1[i-1]!=word2[j-1])left_down+=1;
                dp[i][j]=min(left,min(down,left_down));
            }
        }
        return dp[n][m];
    }
};

燃尽了。希望越来越好

相关文章:

  • k8s node inode被耗尽如何处理?
  • 解决前后端时区不一致问题
  • Redis与Mysql双写一致性如何保证?
  • 图灵逆向——题十-魔改算法
  • Tigshop| 一个基于Java的开源商城系统
  • C++初级入门学习
  • Android里面如何优化xml布局
  • 应急物资仓库管理系统|基于GAV仓库管理的应用
  • 美*WMS项目总结
  • ​如何判断安捷伦气质联用仪GCMS 8890-5977B 四级杆是否需要更换​
  • Linux——进程概念
  • RTK 实时动态定位概述
  • Java 中 SQL 注入问题剖析​
  • TrueNAS scale(23.10) Restful API接口调用
  • LLM 为什么使用ID,每个单词不都是有编码的吗
  • vit中的位置编码,RoPE旋转位置编码,torch.nn.functional.embedding
  • 动态路由刷新后消失或重定向到404
  • CCF-GESP(编程能力等级认证)
  • openpyxl合并连续相同元素的单元格
  • RVOS-2.基于NS16550a ,为os添加终端交互功能。
  • 淮上网站建设/搜索引擎调价平台哪个好
  • 网站有什么/百度推广开户费用
  • 做产品推广有网站比较好的/网站策划是干什么的
  • 珠宝行网站建设方案/系统开发
  • 电子商务网站有哪几种/软文范例200字
  • 汕头招聘网官网登录/广州灰色优化网络公司