【LeetCode高频100题-3】冲冲冲(持续更新23.2.1)

这篇具有很好参考价值的文章主要介绍了【LeetCode高频100题-3】冲冲冲(持续更新23.2.1)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

62. 不同路径

题意

  • 一道数学题,排列组合/小学奥赛题。
  • 动态规划不是一般来解决最值问题的吗,这道题为什么会想到dp?

解法1 排列组合

从左上角到右下角,一共要走m+n-2步,其中向右n-1步,向下m-1步,因此路径的总数,相当于从m+n-2中选择m-1个向下的步数,即排列组合。
【LeetCode高频100题-3】冲冲冲(持续更新23.2.1)

  • 但是,需要注意的是,题目只保证最后结果在int型范围内,而实际上如果按下面的代码运行,即便中间运算已经用long long存储,还是会溢出,所以需要一边乘一边除(即便是一边乘一边除,中间过程也必须用long long,否则中间计算会超出int型可表示范围)。
class Solution {
public:
    int uniquePaths(int m, int n) {
        long long ans=1;
        for(int i=n;i<=m+n-2;i++)
            ans=ans*i; 	//会溢出
        for(int i=1;i<m;i++)
            ans/=i;
        return ans;
    }
};
// ac代码
class Solution {
public:
    int uniquePaths(int m, int n) {
        long long ans=1;
        for(int i=n,j=1;i<=m+n-2;i++,j++)
            ans=ans*i/j;
        return ans;
    }
};

解法2 动态规划

  • dp[i][j]表示走到 (i,j) 这个位置有几种走法。
  • dp[i][j]=dp[i-1][j]+dp[i][j-1]
  • 注意dp[0][0]和边界情况(i-1j-1)处理(也可以将dp[0,:]dp[:,0]全置1)。
class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int> > dp(m,vector<int>(n,0));
        dp[0][0]=1;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(dp[i][j]==0) 	//为了维护dp[0][0]
                {
                    int left=j==0?0:dp[i][j-1];
                    int top=i==0?0:dp[i-1][j];
                    dp[i][j]=left+top;
                }
            }
        }
        return dp[m-1][n-1];
    }
};

Attention

  • 二维数组的定义
vector<vector<int>> asd1(row, vector<int>(column, 0)); //初始化row*column二维动态数组,初始化值为0
  • 动态规划解法中,其实只需要保存dp[i-1][j]dp[i][j-1]两个数,还有空间优化的余地。
  • 排列组合基础
    【LeetCode高频100题-3】冲冲冲(持续更新23.2.1)
    【LeetCode高频100题-3】冲冲冲(持续更新23.2.1)

64. 最小路径和

题意

  • 只能向右或向下走,约束很强,所以很好遍历!
  • 求最小值。
  • 和第62题有相似之处。

解法1 DFS(剪枝也超时)

建立一个队列q和一个数组value[](记录每个点的最小值),将(0,0)压入队列,然后每从队列中取出一个点 (x,y) ,就将其右 (x+1,y) 和下 (x,y+1) 两个点压入队列中,同时更新其右 (x+1,y) 和下 (x,y+1) 两个点的最小值。

但是由于超时,需要剪枝。所以只有当前点使得其右 (x+1,y) 或下 (x,y+1) 的点的最小值被更新时,才将这个点压入队列中。

但是依旧超时,,,

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        // m行n列
        int m=grid.size(),n=grid[0].size();
        vector<vector<int>> value(m,vector<int>(n,-1));
        queue<pair<int,int> > q;
        pair<int,int> st(0,0);
        q.push(st);
        value[0][0]=grid[0][0];
        while(!q.empty())
        {
            pair<int,int> tmp=q.front();
            q.pop();
            int x=tmp.first,y=tmp.second;
            if(x+1<m&&y<n)
            {
                int tmp_value=value[x][y]+grid[x+1][y];
                if(value[x+1][y]!=-1)
                {
                    if(tmp_value<=value[x+1][y])
                    {
                        value[x+1][y]=tmp_value;
                        pair<int,int> nxt(x+1,y);
                        q.push(nxt);
                    }
                }
                else
                {
                    value[x+1][y]=tmp_value;
                    pair<int,int> nxt(x+1,y);
                    q.push(nxt);
                }
                    
            }
            if(y+1<n&&x<m)
            {
                int tmp_value=value[x][y]+grid[x][y+1];
                if(value[x][y+1]!=-1)
                {
                    if(tmp_value<=value[x][y+1])
                    {
                        value[x][y+1]=tmp_value;
                        pair<int,int> nxt(x,y+1);
                        q.push(nxt);
                    }
                }
                else
                {
                    value[x][y+1]=tmp_value;
                    pair<int,int> nxt(x,y+1);
                    q.push(nxt);
                }
            }
        }
        return value[m-1][n-1];
    }
};

解法2 动态规划

dp[i][j]是到达点 (i,j) 时路径的最小值,则dp[i][j]=min(dp[i-1[j]+grid[i][j],dp[i][j-1]+grid[i][j])

和第62题不同的处理是,这里左边界和上边界的点要单独处理。因为最左列的点只能从它上面的点过来,而最上行的点只能从它左边过来。

其他没什么难点。

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        // m行n列
        int m=grid.size(),n=grid[0].size();
        vector<vector<int>> dp(m,vector<int>(n,-1));
        dp[0][0]=grid[0][0];
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(i==0&&j!=0)
                    dp[i][j]=dp[i][j-1]+grid[i][j];
                else if(j==0&&i!=0)
                    dp[i][j]=dp[i-1][j]+grid[i][j];
                else
                {
                    int left=j-1>=0?dp[i][j-1]:0;
                    int top=i-1>=0?dp[i-1][j]:0;
                    dp[i][j]=min(left+grid[i][j],top+grid[i][j]);
                }
            }
        }
        return dp[m-1][n-1];
    }
};

ATTENTION

  • pair的用法

70. 爬楼梯

题意

  • 动态规划典型例题

解法1 动态规划

dp[i]是到达第 i 级台阶的方法数量。由于第i级台阶可以通过第 i-1 和 i-2 级台阶到达,所以dp[i]=dp[i-1]+dp[i-2]

边界条件:由于第 0 级台阶和第 1 级台阶都只有 1 种到达方法,所以初始化dp[0]=dp[1]=1

class Solution {
public:
    int climbStairs(int n) {
        vector<int> dp(n+1,0);
        dp[0]=dp[1]=1;
        for(int i=2;i<=n;i++)
            dp[i]=dp[i-1]+dp[i-2];
        return dp[n];
    }
};

解法2 矩阵快速幂(待补充)


72.编辑距离(waiting)


75. 颜色分类(待整理)

题意

  • 啊?这不是直接冒泡就能结束了吗,,,
  • 荷兰国旗问题?

解法1


76.最小覆盖子串

题意

  • 在字符串S中寻找包含字符串T所有字符的最小子串。
  • 字符串T可能有重复字符。
  • 覆盖子串唯一

解法1 滑动窗口(有待复习)

需要维护字符频数数组

暴力枚举
首先遍历字符串T,得到字符频数数组。然后枚举所有长度大于等于T.size()的子串,再遍历每个子串,与字符串T进行比较。时间复杂度O(|S|3+|T|)。
冗余:因为求的是最小字串,所以当一个子串s[i,j]已经包含字符串T的所有字符时,以s[i]为起始的更长子串就不用再考虑了。

滑动窗口

  • 首先将右边界右移,直到子串覆盖字符串T的所有字符。
  • 然后将左边界右移,得到当前最小覆盖子串。
  • 然后将左右边界都右移,回到第一步,寻找下一个符合的覆盖子串。
class Solution {
public:
    unordered_map<char,int> cur_cnt,t_cnt;
    int cur_tot=0,t_tot=0;
    bool is_cover() 	//是否覆盖的判断还是挺坑的
    {
        if(cur_tot<t_tot) return false; 
        for(auto it:t_cnt)
        {
            if(cur_cnt[it.first]<it.second) 	//覆盖子串的字符数可能比字符串T多
                return false;
        }
        return true;
    }
    string minWindow(string s, string t) {
        int s_n=s.size(),t_n=t.size();
        // string ans=s;
        string ans="";

        // t的词频数组
        for(auto &c:t)
            t_cnt[c]+=1;
        t_tot=t_n;

        int l=0,r=0;
        cur_cnt[s[l]]+=1;
        cur_tot+=1;
        while(true)
        {
            while(!is_cover()&&r<s_n)
            {
                r++;
                cur_cnt[s[r]]+=1;
                cur_tot+=1;
            }
            // 溢出
            if(r==s_n)
                break;
            else  //cover
            {
                while(is_cover())
                {
                    cur_cnt[s[l]]-=1;
                    cur_tot-=1;
                    l++;
                }
                // 一个覆盖子串,不一定是最小的
                // ans=ans.size()>(r-l+1)?s.substr(l-1,r-l+2):ans;   //更新
                if(ans==""||ans.size()>(r-l+1))
                    ans=s.substr(l-1,r-l+2);
                r++;
                cur_cnt[s[r]]+=1;
                cur_tot+=1;
            }
        }
        return ans;
    }
};

ATTENTION

  • auto(待整理)

78.子集


94. 二叉树的中序遍历

题意

解法

中序遍历:左-根-右。

当在最底层时,每个结点都可视为一棵树的,所以,应当在遍历到的时候进行 push 操作。

对于根,首先要判断是否为 NULL。然后再遍历其左子树,push root,遍历右子树。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void inOrder(TreeNode* root,vector<int>& ans)
    {
        if(root==NULL) return; 	//这个很重要,也就是说现将root传进来,再判断它存不存在。 
        inOrder(root->left,ans);
        ans.push_back(root->val);
        inOrder(root->right,ans);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ans;
        inOrder(root,ans);
        return ans;
    }
};
//这个版本有冗余判断
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void inOrder(TreeNode* root,vector<int>& ans)
    {
        if(root==NULL) return ;
        if(root->left!=NULL) 	//冗余
            inOrder(root->left,ans);
        ans.push_back(root->val);
        if(root->right!=NULL) 	//冗余
            inOrder(root->right,ans);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ans;
        inOrder(root,ans);
        return ans;
    }
};

98. 验证二叉搜索树

题意

  • 验证所给的二叉树是不是二叉搜索树,要求:左 < 根 < 右。
  • 要注意:整颗左子树 < 根 < 整颗右子树
  • 节点值的范围:[INT_MIN, INT_MAX]

解法

基于match(root,l,r)考虑每一个节点 root :

  • 若 root == NULL,则返回 true;
  • 若 root != NULL,则判断它的值在不在限定范围 (l ,r) 内,不在返回 false;
  • 若 root != NULL,且它的值在范围 (l ,r) 内,则只有当 root->left 和 root->right 都满足时,才返回 true。

注意:节点元素范围为 [INT_MIN, INT_MAX],所以 root 的值的范围应该比 int 大(因为是开区间),否则,若节点为 INT_MIN 或 INT_MAX ,会误判。(比如只有一个节点,节点的值为 INT_MAX,如果将范围设为(INT_MIN, INT_MAX)的话,会误判。)文章来源地址https://www.toymoban.com/news/detail-418622.html

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool match(TreeNode* root,long long l,long long r)
    {
        if(root==NULL) return true;
        if(root->val>=r || root->val<=l) return false;
        return match(root->left,l,root->val)&&match(root->right,root->val,r);
    }
    bool isValidBST(TreeNode* root) {
        return match(root,LLONG_MIN,LLONG_MAX);
    }
};

到了这里,关于【LeetCode高频100题-3】冲冲冲(持续更新23.2.1)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • LeetCode算法题解(动态规划)|LeetCoed62. 不同路径、LeetCode63. 不同路径 II

    题目链接:62. 不同路径 题目描述: 一个机器人位于一个  m x n   网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径? 示例 1: 示例 2:

    2024年02月05日
    浏览(53)
  • 23届秋招前端笔面经合辑(持续更新)

    平时笔面经都会发在牛客,实时更新,欢迎订阅~ 23届秋招前端笔面经合辑 求职之前,先上牛客,就业找工作一站解决。互联网IT技术/产品/运营/硬件/汽车机械制造/金融/财务管理/审计/银行/市场营销/地产/快消/管培生等等专业技能学习/备考/求职神器,在线进行企业校招实习

    2024年02月07日
    浏览(37)
  • 代码随想录Day33 LeetCode T62不同路径 LeetCode T63 不同路径II

    动规五部曲 1.确定dp数组含义 2.确定递推公式 3.初始化数组 4.确定遍历方式 5.打印dp数组查看分析问题 题目链接:62. 不同路径 - 力扣(LeetCode) 注:n行m列而不是m行n列 1.确定dp数组含义 代表到达此下标有多少条路径 2.确定递推公式 因为只能向右或者向下走,所以到达i,j这个点的

    2024年02月06日
    浏览(51)
  • LeetCode刷题笔记【30】:动态规划专题-2(不同路径、不同路径 II)

    参考前文 参考文章: LeetCode刷题笔记【29】:动态规划专题-1(斐波那契数、爬楼梯、使用最小花费爬楼梯) LeetCode链接:https://leetcode.cn/problems/unique-paths/description/ 动态规划 : 创建m×n的数组, 对应这个地图, 数组 val 表示 有几种方法可以走到这一格 最开始, 第一行和第一列v

    2024年02月09日
    浏览(59)
  • 【LeetCode热题100】打卡第23天:最小覆盖&子集

    大家好,我是知识汲取者,欢迎来到我的LeetCode热题100刷题专栏! 精选 100 道力扣(LeetCode)上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,熟练掌握这 100 道题,你就已经具备了在代码世界通行的基本能力。在此专栏中,我们将会涵盖各种

    2024年02月09日
    浏览(35)
  • 【Leetcode】62.不同路径

    一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径? 示例1: 示例2: 示例3: 示例4: 提示: 1 = m, n = 100 题目数

    2024年02月15日
    浏览(35)
  • 动态规划 Leetcode 62 不同路径

    Leetcode 62 学习记录自代码随想录 要点:1.二维表格,想到(i,j)去代表其坐标,dp数组也因此为二维数组; 2.递推公式 d p [ i ] [ j ] dp[i][j] d p [ i ] [ j ] 的上一步只能是其左边或上边,所以 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] dp[i][j]=dp[i-1][j]+dp[i][j-1] d p [ i ] [ j ] =

    2024年03月13日
    浏览(42)
  • leetcode每日一题:62. 不同路径

    系列:动态规划 语言:java 难度:中等 题目来源:Leetcode62. 不同路径 开启动态规划章节了!!欢迎您在留言和我一起完成每日打卡,以后每天8点半前发布每日一题。 原题链接:Leetcode62. 不同路径 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )

    2023年04月22日
    浏览(45)
  • 100道基于Android毕业设计的选题题目,持续更新

    博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W+,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 大家好,我是程序员徐师兄、今天给大家谈谈基于android的app开发毕设题目,以及基于android的毕业设计开题报告对应的

    2024年02月04日
    浏览(53)
  • Python获取项目路径的N种方法(持续更新)

    几乎所有的项目都需要获取当前项目的根路径,以保证项目从一个地方拷贝到另一个地方的时候不会出现路径匹配的问题,以下是工作中用过的方法。 方法1: 这个是我项目中用的方法,目前没有发现什么兼容性问题 方法2: 这个是yolo v5源码中的方法,肯定是没问题的,而且

    2024年02月02日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包