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];
        }

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

本题解题代码:

我们刚刚求的是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);
        }

测试:

123451
1678596
4

整体AC


总结

提示:重要经验:

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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰露可乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值