代碼隨想錄算法訓練營|第五十六天|392.判断子序列、1035.不相交的线、115.不同的子序列。刷题心得(c++)

这篇具有很好参考价值的文章主要介绍了代碼隨想錄算法訓練營|第五十六天|392.判断子序列、1035.不相交的线、115.不同的子序列。刷题心得(c++)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

讀題

392.判断子序列

自己看到题目的第一想法

看完代码随想录之后的想法

115.不同的子序列

看完代码随想录之后的想法

392.判断子序列 - 實作

思路

原始思路

代碼隨想錄思路

Code

原始思路

代碼隨想錄思路

115.不同的子序列 - 實作

思路

Code

總結

自己实现过程中遇到哪些困难

今日收获,记录一下自己的学习时长

相關資料

392.判断子序列

115.不同的子序列


讀題

392.判断子序列

自己看到题目的第一想法

這題跟最長公共子序列基本一致,只需要將公共子序列的加法改為減法,並且在不相等的時候找最小值就好了。

看完代码随想录之后的想法

我的想法其實跟卡哥的剛好反過來,我是將所有數組初始化為s的長度,因為看到了提示是說要用到減法,但看到卡哥的做法,減法指的是刪除t的字符串,這點我把他想為是取縱向與橫向中最小的部分,雖然代碼過了,但是基本思維是不一樣的,

115.不同的子序列

看完代码随想录之后的想法

s有多少方式可以將s刪除成t,思考了很久,終於對於為甚麼是dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j],查看了許多資料後,對於這個點終於知道了,dp[i - 1][j - 1]我思考了很久,後來發現就是如果要先知道之前的比對狀況做為計算的基礎,之後我也可以不使用s[i - 1] 那我就要知道不使用s[i - 1]的比對狀況是甚麼,兩者相加,就會是s[i - 1]使用與不使用的狀況。

392.判断子序列 - 實作

思路

原始思路

  1. 定義DP數組以及下標的含意

    dp[i][j] 代表 0~ i - 1 的t 有 0 ~ j - 1 的s 中的子序列個數為dp[i][j]

  2. 遞推公式

    分成兩種狀態相同與不相同

    不相同的話需要看之前的序列有沒有重複,之前包括兩個方面,縱向與橫向關係,要取最小的

    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);

    相同的時候,因為之前的數都考慮過縱向與橫向的關係,可以直接從左上角減一代表有一個數包含

    dp[i][j] = dp[i - 1][j - 1] - 1;

  3. 根據遞推公式、題意以及定義,確定DP數組如何初始化

    都初始化為s.size() 如果t的子序列包含全部s,最終的dp[t.size()][s.size()] ==0 則代表不完全包含

  4. 確定遍歷順序

    因為需要左上角的數據來進行遍歷,所以是由前往後。

代碼隨想錄思路

  1. 定義DP數組以及下標的含意

    dp[i][j] 代表 i - 1結尾的字符串s和j - 1為結尾的字符串t,相同子序列長度為dp[i][j]

    i - 1 跟 j - 1的原因是因為在做遞推時,i、j 是由 1 開始,所以要用i - 1 、 j - 1來進行定義

  2. 遞推公式

    分成兩種狀態相同與不相同

    • if (s[i - 1] == t[j - 1])
      • t中找到了一个字符在s中也出現過
      • 因為我的dp[i][j] 表示的是以s[i - 1]以及t[ j - 1]因為相同,所以我要在沒有當前的s[i-1] t[j - 1]的 s[i - 2] t[j - 2]的基礎上也就是dp[i - 1][j - 1] 的基礎上+1
    • if(s[i - 1] ≠ t[j - 1)
      • 相當於t 要刪除元素,因為 t的字符串中,這個位置並沒有s的字串,所以要刪除
      • 如果是t要刪除元素,那就是取t[j - 2] 這個不包含t[ j -1]的最大值,但s是要比較的子序列,所以s不用動,也就是說這個dp[i][j]會是由s[i - 1][t - 2]所組成,所對應的dp數組是dp[i][j] = dp[i][j - 1]。
  3. 根據遞推公式、題意以及定義,確定DP數組如何初始化

    都初始化為0如果t的子序列包含全部s,最終的dp[t.size()][s.size()] ==s.size()則代表不完全包含

  4. 確定遍歷順序

    因為需要左上角的數據來進行遍歷,所以是由前往後。

Code

原始思路

class Solution {
public:
    bool isSubsequence(string s, string t) {
        vector<vector<int>> dp (t.size() + 1, vector<int>(s.size() + 1, s.size()));
        for(int i = 1; i < t.size() + 1; i++) {
            for(int j = 1; j < s.size() + 1; j++) {
                if(t[i - 1] == s[j - 1]) dp[i][j] = dp[i - 1][j - 1] - 1;
                else dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]);
            }
        }
        if(dp[t.size()][s.size()]  == 0) return true;
        else return false;
    }
};

代碼隨想錄思路

class Solution {
public:
    bool isSubsequence(string s, string t) {
        vector<vector<int>> dp (s.size() + 1, vector<int>(t.size() + 1, 0));

        for(int i = 1; i <= s.size(); i++) {
            for(int j = 1; j <= t.size(); j++) {
                if(s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
                else dp[i][j] = dp[i][j - 1];
            }
        }
        if(dp[s.size()][t.size()] == s.size()) return true;
        else return false;
    }
};

115.不同的子序列 - 實作

思路

  1. 定義DP數組以及下標的含意

    dp[i][j] 代表 i - 1結尾的字符串s的子序列中和j - 1為結尾的字符串t的各數為dp[i][j]

  2. 遞推公式

    分成兩種狀態相同與不相同

    • if (s[i - 1] == t[j - 1])
      • 如果**s[i - 1]t[j - 1]**相等,那麼我們可以使用來匹配。
      • 計算之前,我們需要知道**s的前i - 2個字符和t的前j - 2個字符的匹配情況,這正是dp[i - 1][j - 1]**的意義。
      • 即使**s[i - 1]存在,我們也可以選擇不使用它來匹配t[j - 1]。在這種情況下,我們需要知道s的前i-2個字符和t的前j - 1個字符的匹配情況,這是dp[i - 1][j]**的意義。
      • 綜合上述兩點,當**s[i - 1]t[j - 1]相等時,递推公式可以表示為:dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]**。
    • if(s[i - 1] ≠ t[j - 1)
      • 相當於s 要刪除元素,因為 s的字符串中,這個位置並沒有t的字串,所以要刪除
      • 如果是s要刪除元素,那就是取s[i - 2] 這個不包含s[ i -1]的最大值,但t是要比較的子序列,所以t不用動,也就是說這個dp[i][j]會是由s[i - 2]t[j - 1]所組成,所對應的dp數組是dp[i][j] = dp[i - 1][j]。
  3. 根據遞推公式、題意以及定義,確定DP數組如何初始化

    dp[i][0] 一定都是1,因為把s全部刪除後出現空字符的個數就是一

    dp[0][j] 因為s無論如何都無法變成t,所以都是0

    dp[0][0] 空字符串s可以刪除0個元素變成空字符串t,所以等於1

  4. 確定遍歷順序

    因為需要左上角的數據來進行遍歷,所以是由前往後。

Code

class Solution {
public:
    int numDistinct(string s, string t) {
        vector<vector<uint64_t>> dp(s.size() + 1, vector<uint64_t>(t.size() + 1, 0));
        for(int i = 0 ; i <= s.size(); i++) {
            dp[i][0] = 1;
        }
        for (int i = 1; i <= s.size(); i++) {
            for (int j = 1; j <= t.size(); j++) {
                if (s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + dp[i -1 ][j];
                else dp[i][j] = dp[i - 1][j];
            }
        }
        return dp[s.size()][t.size()];
    }
};

總結

自己实现过程中遇到哪些困难

今天最主要的困難點在於不同的子序列,透過許多不同的方法,去釐清,後來才慢慢比較清晰了,只是這個還需要多琢磨,自己對於這部分的清晰度還需要再加強

今日收获,记录一下自己的学习时长

今天大概花了四小時,主要是去理解不同的子序列問題,在這個問題中花費了很久時間,才對題解有一些了解

相關資料

● 今日学习的文章链接和视频链接

392.判断子序列

https://programmercarl.com/0392.判断子序列.html

115.不同的子序列

https://programmercarl.com/0115.不同的子序列.html文章来源地址https://www.toymoban.com/news/detail-737687.html

到了这里,关于代碼隨想錄算法訓練營|第五十六天|392.判断子序列、1035.不相交的线、115.不同的子序列。刷题心得(c++)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 算法训练第五十八天

    总结:今日事单调栈的开端,还是挺巧妙的。 496. 下一个更大元素 I - 力扣(LeetCode) 代码: 739. 每日温度 - 力扣(LeetCode)

    2024年02月09日
    浏览(23)
  • 第五十五天

        CSS3 ●背景 CSS3 中包含几个新的背景属性,提供更大背景元素控制: •background-image:添加背景图片。不同的背景图像和图像用逗号隔开,所有的图片中显示在最顶端的为第一张。 •background-size:指定背景图像的大小。CSS3以前,背景图像大小由图像的实际大小决定。  

    2024年02月12日
    浏览(28)
  • 第五十五回:命名路由(Route)

    我们在上一章回中介绍了BoxDecoration Widget相关的内容,本章回中将介绍命名路由(Route).闲话休提,让我们一起Talk Flutter吧。 我们在这里介绍的命名路由是路由(Route)中的一种,主要用来当作导航,通过导航跳转到不同的页面,它和我们前面章回中介绍的路由类似,只不过是给路由

    2024年02月09日
    浏览(48)
  • sqlilabs第五十九六十关

    手工注入 报错注入 手工注入

    2024年01月18日
    浏览(30)
  • 第五十九回: Slider Widget

    我们在上一章回中介绍了Form Widget相关的内容,本章回中将介绍 Slider Widget.闲话休提,让我们一起Talk Flutter吧。 我们在这里说的 Slider Widget是一种滑动条组件,通过滑动来控制不同的进度,它类似进度条,不过需要我们让去去滑动它的是进度,在实际项目中经常用它来调节音

    2024年02月09日
    浏览(28)
  • 第五十六章 Unity 音频播放

    Unity可以导入大多数标准音频文件格式,精通于在3D 空间中播放声音,还可根据需要提供其他效果。虽然播放声音是一件非常简单的事情,但是为了模拟现实直接中的各种声音效果,Unity会提供各种各样的组件来实现。 首先,我们需要了解“多普勒效应”。他是一名奥地物理

    2024年02月07日
    浏览(26)
  • 代码随想录第五十九天

    题目链接 : 下一个更大元素 II 自己的思路 :没想到哈哈哈哈!! 正确思路 :这个题在单调栈的情况下转了一个弯,就是需要取一个模操作,用来模拟一个数组的循环过程!!!! 代码 : 题目链接 : 接雨水 自己的思路 :想不到!!!! 正确思路 :利用单调栈来存储之前遍历的值

    2024年02月11日
    浏览(30)
  • 代码随想录-刷题第五十六天

    先介绍单调栈类型的题目, 通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时就要想到可以用单调栈 。时间复杂度为O(n)。 单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优

    2024年01月17日
    浏览(29)
  • 第五十八章 Unity 发布PC平台

    本章节我们介绍一些如何打包游戏到PC平台,这里重点介绍如何制作Windows操作系统下的游戏包。首先,我们创建一个“PcDemo”工程,然后简单布置一下场景内容,如下 想要打包发布Unity项目,我们可以在菜单栏选择“File”→ “Build Settings”菜单命令。 在Platform列表中显然了我

    2024年02月11日
    浏览(24)
  • 第五十三章 Unity 移动平台输入(上)

    在移动设备上,Input 类提供对触摸屏、加速度计和地理/位置输入的访问。这里我们简单介绍Input类对于触摸屏的支持。Input.Touches是一个触摸数组,每个数组元素代表着手指在屏幕上的触碰状态Input.Touch。Input.Touch 数据结构表示: fingerId 触摸索引 deltatime 从最后状态到当前状态

    2024年02月03日
    浏览(25)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包