• LeetCode高频题:最长公共子序列,玩游戏A和游戏B,两兄弟加起来最多可以获得多少奖品


    LeetCode高频题:最长公共子序列,玩游戏A和游戏B,两兄弟加起来最多可以获得多少奖品?

    提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目
    互联网大厂们在公司养了一大批ACM竞赛的大佬们,吃完饭就是设计考题,然后去考应聘人员,你要做的就是学基础树结构与算法,然后打通任督二脉,以应对波云诡谲的大厂笔试面试题!
    你要是不扎实学习数据结构与算法,好好动手手撕代码,锻炼解题能力,你可能会在笔试面试过程中,连题目都看不懂!比如华为,字节啥的,足够让你读不懂题
    在这里插入图片描述


    题目

    一、情节
    双胞胎小弟小王和小李来自小镇,最近一起报名参加了小镇的闯关游戏,官方也为参赛选手准备了翻译机,办公本,录音笔,耳机啥的精美奖品,但是想获得礼物,得经历一番考验,终于大赛到了……

    二、游戏规则
    俩兄弟分配到不同的闯关主题,分别为游戏A,和游戏B;
    A和B游戏均设有关卡,但关卡数不一定相同,主办方预先为每一个关卡设置了一个奖品,如果通过则获得该奖品,否则不行,但是允许选手继续通过下一个关卡;
    关卡间是否同通过没有关系
    闯关结束后,分别对两兄弟手中的奖品按照其获得的顺序一一匹配,如果两兄弟奖品完全一样,则获得的奖品都可以带回家,否则无法获得。

    三、问题
    两兄弟加起来最多可以获得多少分份奖品?

    输入描述:
    为了方便对比,官方将奖品编号
    输入为2行字符串
    第一行是代表游戏A下每个关卡提供的礼品编号
    第二行是代表游戏B下每个关卡提供的礼品编号
    礼物的编号范围是字符a–z和数字0–9,游戏关卡数为1–100范围内的整数

    输出描述:
    两兄弟加起来最多可以获得的奖品数量


    一、审题

    示例:
    输入
    123451
    1678596
    输出
    4


    你认为互联网大厂的题目怎么考你???可不就是改编LeetCode高频题来考吗

    换汤不换药……
    换汤不换药……
    换汤不换药……

    你瞅瞅

    说了半天,输入是啥???2个字符串
    输出是啥,要求俩字符串对比,里面的相同编号的个数????这是啥???
    求最长公共子序列的长度啊
    管你字符是a–z还是0–9啊

    就是求最长公共子序列长度len,这是一个人得到的奖品
    两兄弟能得到最多的奖品数就是2*len

    因此,大厂的题目就是给你绕半天,希望你有基础能力学过基础数据结构与算法,直接就能破解本题

    最长公共子序列的长度

    我说过的
    【1】求字符串s1和s2的最长公共子序列的长度
    你看看我那个文章就知道,只需要一行代码搞定本题

    我再说一遍
    2个字符串的动态规划典型的就是多样本位置对应模型,讨论填表的时候,只看位置i和j的情况

    我们定义一个表格dp
    维度N*M
    N是s1字符串长度
    M是s2字符串长度

    我们定义dpij是啥?从s1的0–i范围与s2的0–j范围上的最长公共子序列的长度是?

    有了这个表,非常简单,咱就是填一个表
    最后要啥结果?len = dp[N-1][M-1],即s1整个串,和s2整个串的最长公共子序列长度是??
    在这里插入图片描述
    (0)那么我们填写第dp00格子
    就是s1和s20位置相同吗?相同就是1,否则就是0

    (1)填第0行,dp0j
    只有s1的0字符,和s2的0–j范围内对比
    显然,只要s2的0–j有一个字符和s1[0]相等,那就是1,否则就不行
    因此,咱们先对比s2[j]是否与s1[0]相等?是就填1【看下面粉色?】
    在这里插入图片描述

    否?那就要看看dp[0][j-1]了,就看看s20–j-1上还有没有可能,反正之前填好的,如果前面有一个能对上,就可以填1
    【看上面粉色?左边那些格子的情况了】

    这个你懂?

    (1)同理,填第0列,dpi0
    一样的道理,然你对你看看s1的0–i范围内,有没有一个字符与s2[0]相等
    就先看s1[i]是否与s2[0]相等?是,那就dpi0=1【看下面蓝色?的格子】
    在这里插入图片描述
    否则,就只能看看s1的0–i-1范围内,有没有一个字符与s2[0]相等,
    即dpi0=dp[i-1][0],如果前面有一个字符能对上就行

    okay
    第0行,第0列都对上了,剩下的就是常规填表任意位置dpij格子
    因为我们最后要右下角的格子
    所以宏观调度呢?就从上到下,每一行,都是从左往右填写格子,这个思路我讲了多次了哦!

    (2)那么任意位置dpij怎么填呢???
    我说过了:我们定义dpij是啥?从s1的0–i范围与s2的0–j范围上的最长公共子序列的长度是

    咱们就围绕这个定义来玩
    在这里插入图片描述
    有这么几种可能性:
    【1】就是压根,s1和s2的最长公共子序列,既不以s1的i字符结尾,也不以s2的j字符结尾
    这种情况dpij就跟0–i-1和0–j-1没区别对吧?
    你想想,都不以ij结尾,那跟不加ij字符,而和前面已经有的字符串,的最长公共子序列有啥区别呢?
    比如:
    在这里插入图片描述
    既然d不是e,那有没有d和e没用,直接dpij=dp[i-1][j-1]
    懂?

    【2】同理,你想到了,s1和s2的最长公共子序列,不以s1的i字符结尾,以s2的j字符结尾
    这种情况dpij就跟0–i-1和0–j没区别对吧?
    你懂的
    不一i结尾,i可以不要,只看s1的0–i-1呗
    在这里插入图片描述
    【3】同理,你想到了,s1和s2的最长公共子序列,以s1的i字符结尾,不以s2的j字符结尾
    这种情况dpij就跟0–i和0–j-1没区别对吧?
    你懂的
    不一j结尾,j可以不要,只看s2的0–j-1呗
    在这里插入图片描述
    【4】同理,你想到了,s1和s2的最长公共子序列,以s1的i字符结尾,以s2的j字符结尾
    这种情况就得要求s1[i]=s2[j]
    所以就是相当于同时增了1个字符,那就是dpij=dp[0–i-1][0–j-1] + 1
    你懂的
    以ij结尾
    在这里插入图片描述

    okay,我们的填表规则,基本就OK了

    当然你要注意,其实情况【2】【3】实际上在求的时候,直接包含了情况【1】
    所以省掉情况【1】

    咱们手撕代码:

            //最长公共子序列:
            public static int longestCommonSubSequenceDP(String s1, String s2){
                int N = s1.length();
                int M = s2.length();
                char[] str1 = s1.toCharArray();
                char[] str2 = s2.toCharArray();
    
                //我说过了:我们定义dpij是啥?**从s1的0–i范围与s2的0–j范围上的最长公共子序列的长度是**?
                int[][] dp = new int[N][M];
                //(0)那么我们填写第dp00格子
                //就是s1和s20位置相同吗?相同就是1,否则就是0
                dp[0][0] = str1[0] == str2[0] ? 1 : 0;
                //(1)填第0行,dp0j
                //只有s1的0字符,和s2的0--j范围内对比
                for (int j = 1; j < M; j++) {
                    dp[0][j] = str1[0] == str2[j] ? 1 : dp[0][j -1];
                }
                //(1)同理,填第0列,dpi0
                //一样的道理,然你对你看看s1的0--i范围内,有没有一个字符与s2[0]相等
                for (int i = 1; i < N; i++) {
                    dp[i][0] = str1[i] == str2[0] ? 1 : dp[i - 1][0];
                }
    
                //dpij看最长公共子序列是否与s1的i和s2的j字符的情况,情况23覆盖情况1,如果ij字符相同才有情况4
                for (int i = 1; i < N; i++) {
                    for (int j = 1; j < M; j++) {
                        dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);//情况23
                        if (str1[i] == str2[j])
                            dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 1] + 1);//情况4与他们互斥的,只能其中一个
                    }
                }
    
                return dp[N - 1][M - 1];
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    这个代码你必须熟悉,因为经常互联网大厂笔试面试都变着方的考你的

    本题解题代码:

    我们刚刚求的是2个字符串的最长公共子序列的长度len,它是一个人的最长长度

    本题要求的是2兄弟最终获得的奖品数量,不就是2*len吗?

    手撕代码,直接搞定

    public static void main(String[] args) {
                Scanner in = new Scanner(System.in);
    
                String s1 = in.nextLine();
                String s2 = in.nextLine();
                int ans = 2 * longestCommonSubSequenceDP(s1, s2);
                System.out.println(ans);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试:

    123451
    1678596
    4
    
    • 1
    • 2
    • 3

    整体AC


    总结

    提示:重要经验:

    1)互联网大厂的笔试面试题,就是变着方考你基础的数据结构与算法,所以基础数据结构与算法你得熟透了
    2)涉及到给你的是2个参数,那么就要考虑是不是多样本位置对应模型的动态规划,分清楚ij格子的状况和ij位置的关系就行
    3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

  • 相关阅读:
    Linux SDIO-WiFi 协议栈
    前端面经 强缓存与协商缓存
    UI自动化测试(弹出框,多窗口)
    茂莱光学科创板上市:拟募资4亿 范一与范浩兄弟为实控人
    Deployment控制器
    2022-7月报
    学了一天java,我总结了这些知识点
    uniapp-秋云图表 ucharts echarts 对比与关系
    如何实现Spring的事务管理功能:@Transactional声明式事务
    谷歌浏览器安装 vue-devtools 拓展,仅需3分钟,提供插件
  • 原文地址:https://blog.csdn.net/weixin_46838716/article/details/126202526