华为 OD 一面算法原题

2.2 亿彩票公布调查结果

昨天,闹得沸沸扬扬的《10 万中 2.2 亿》的彩票事件,迎来了官方公告。

alt

简单来说,调查结果就是:一切正常,合规合法

关于福利彩票事件,之前的推文我们已经分析过。

甚至在后面出现《双色球 6.8 亿》事件时,还用类似的逻辑分析写了回答发到过某乎:

alt

这次所谓调查通报,其实还是没有走出使用「公信力」来进行自证的圈子。

该说的都说过了,本次不再点评。

...

回归主线。

今天接着看「华为 OD」一面算法原题。

昨天分享了一道「子序列」相关的「华为 OD」一面算法原题,很多网友表示不可思议。

那道题在 LeetCode 中是 Hard,现在连 OD 都这么卷了吗?

是的,OD 都开始卷了。

这其实不难理解。

算法在笔试面试中出现,主要是起到一个「过滤」的作用。

以前面试算法题难度普遍没有很高,是因为出到普通难度,也足以产生过滤作用,再难可能就没有候选人做出来,反而起不到过滤效果。

现如今,随着互联网大厂的各种裁员,加上应届大学生毕业人数屡创新高,连华为 OD 岗位都供远大于求了,因此算法题难度也上来了。

题目描述

平台:LeetCode

题号:943

给定一个字符串数组 words,找到以 words 中每个字符串作为子字符串的最短字符串。

如果有多个有效最短字符串满足题目条件,返回其中任意一个即可。

我们可以假设 words 中没有字符串是 words 中另一个字符串的子字符串。

示例 1:

输入:words = ["alex","loves","leetcode"]

输出:"alexlovesleetcode"

解释:"alex""loves""leetcode" 的所有排列都会被接受。

示例 2:

输入:words = ["catg","ctaagt","gcta","ttca","atgcatc"]

输出:"gctaagttcatgcatc"

提示:

  • words[i] 由小写英文字母组成
  • words 中的所有字符串互不相同

状压 DP

为了方便,将 words 记为 ws

预处理二维数组 g 来表示字符串 ws[i]ws[j] 的重叠部分的长度:若 g[i][j] = len 代表字符串 ws[i] 长度为 len 的后缀与字符串 ws[j] 长度为 len 的前缀相同。

另外用一个二进制数 status 来代表当前超级串 answs 的使用(覆盖)情况:status 的第 i 位为 1 代表字符串 ws[i] 已被使用(即 ws[i] 已是 ans 的子串),若 status 的第 i 位为 0 代表 ws[i] 未被使用

我们知道,当所有的 时,代表所有拼接方式长度均为 ,即不能通过产生重叠部分来缩短超级串的长度。

因此,最小化超级串 ans 的长度等价于最大化重叠部分的长度

定义 代表当前状态为 s 且当前最后一个使用到的字符串为 ws[i] (当前超级串 ans 的结尾部分为 ws[i])时的最大重合长度。

最终超级串的长度为所有字符串的总长度 减去最大重合长度

不失一般性考虑 可用于更新哪些状态,我们可枚举接在字符串 ws[i] 后面的字符串 ws[j] 为何值:

  1. 由于每个字符串只能使用一次,转移需要满足 s 的第 i 位为 s 的第 j 位为 的前提条件,含义为 ws[i] 已被使用,而 ws[j] 未被使用
  2. 满足前提条件 ,代表 ws[j] 可接在 ws[i] 后面,此时有状态转移方程:

接下来,考虑如何构建具体方案。

使用二维数组 记录每个状态是由哪个前驱转移而来:若有 ,代表取得最大重叠长度过程中,字符串 ws[j] 接在 ws[i] 后面。

我们从后往前对 ans 进行构造,若 ans = ws[0] + ws[1] + ... + ws[k - 1] + ws[k],我们是先找 ws[k],再通过 ws[k]ws[k - 1],直到将整个 ans 构建出来。

构造过程中使用变量解释如下:

  • ans 为具体的超级串
  • status 代表当前还有哪些字符串待拼接到,初始化为 ,代表还没有任何字符串拼接到 ans
  • idx 代表当前处理到的字符串下标,初始化通过遍历所有的 找到合适的 作为 idx
  • last 代表前一个处理到字符串下标,初始化为 -1

一些细节:当 last 不为初始值 -1 时,需要跳过 ws[idx]ws[last] 的重复部分进行拼接。

Java 代码:

class Solution {
    public String shortestSuperstring(String[] ws) {
        int n = ws.length, mask = 1 << n;
        int[][] g = new int[n][n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                String a = ws[i], b = ws[j];
                int l1 = a.length(), l2 = b.length(), len = Math.min(l1, l2);
                for (int k = len; k >= 1; k--) {
                    if (a.substring(l1 - k).equals(b.substring(0, k))) {
                        g[i][j] = k;
                        break;
                    }
                }
            }
        }
        int[][] f = new int[mask][n], p = new int[mask][n];
        for (int s = 0; s < mask; s++) {
            for (int i = 0; i < n; i++) {
                if (((s >> i) & 1) == 0continue;
                for (int j = 0; j < n; j++) {
                    if (((s >> j) & 1) == 1continue;
                    if (f[s | (1 << j)][j] <= f[s][i] + g[i][j]) {
                        f[s | (1 << j)][j] = f[s][i] + g[i][j];
                        p[s | (1 << j)][j] = i;
                    }
                }
            }
        }
        int max = f[mask - 1][0], idx = 0, last = -1, status = mask - 1;
        for (int i = 1; i < n; i++) {
            if (max < f[mask - 1][i]) {
                max = f[mask - 1][i];
                idx = i;
            }
        }
        String ans = "";
        while (status != 0) {
            if (last == -1) ans = ws[idx];
            else ans = ws[idx].substring(0, ws[idx].length() - g[idx][last]) + ans;
            last = idx;
            idx = p[status][idx];
            status ^= (1 << last);
        }
        return ans;
    }
}

Python 代码:

class Solution:
    def shortestSuperstring(self, ws: List[str]) -> str:
        n, mask = len(ws), 1 << len(ws)
        g = [[0 for _ in range(n)] for _ in range(n)]
        for i in range(n):
            for j in range(n):
                a, b = ws[i], ws[j]
                l1, l2 = len(a), len(b)
                length = min(l1, l2)
                for k in range(length, 0-1):
                    if a[l1 - k:] == b[:k]:
                        g[i][j] = k
                        break
        f = [[0 for _ in range(n)] for _ in range(mask)]
        p = [[0 for _ in range(n)] for _ in range(mask)]
        for s in range(mask):
            for i in range(n):
                if (s >> i) & 1 == 0:
                    continue
                for j in range(n):
                    if (s >> j) & 1 == 1:
                        continue
                    if f[s | (1 << j)][j] <= f[s][i] + g[i][j]:
                        f[s | (1 << j)][j] = f[s][i] + g[i][j]
                        p[s | (1 << j)][j] = i
        
        max_val = f[mask - 1][0]
        idx, last, status = 0-1, mask - 1        
        for i in range(1, n):
            if max_val < f[mask - 1][i]:
                max_val = f[mask - 1][i]
                idx = i
        ans = ""
        while status != 0:
            if last == -1:
                ans = ws[idx]
            else:
                ans = ws[idx][:len(ws[idx]) - g[idx][last]] + ans
            last = idx
            idx = p[status][idx]
            status ^= 1 << last
        return ans

C++ 代码:

class Solution {
public:
    string shortestSuperstring(vector<string>& ws) {
 int n = ws.size(), mask = 1 << n;
        vector<vector<int>> g(n, vector<int>(n, 0));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                string a = ws[i], b = ws[j];
                int l1 = a.length(), l2 = b.length(), len = min(l1, l2);
                for (int k = len; k >= 1; k--) {
                    if (a.substr(l1 - k) == b.substr(0, k)) {
                        g[i][j] = k;
                        break;
                    }
                }
            }
        }
        vector<vector<int>> f(mask, vector<int>(n, 0))p(mask, vector<int>(n, 0));
        for (int s = 0; s < mask; s++) {
            for (int i = 0; i < n; i++) {
                if (((s >> i) & 1) == 0continue;
                for (int j = 0; j < n; j++) {
                    if (((s >> j) & 1) == 1continue;
                    if (f[s | (1 << j)][j] <= f[s][i] + g[i][j]) {
                        f[s | (1 << j)][j] = f[s][i] + g[i][j];
                        p[s | (1 << j)][j] = i;
                    }
                }
            }
        }
        int max = f[mask - 1][0], idx = 0, last = -1, status = mask - 1;
        for (int i = 1; i < n; i++) {
            if (max < f[mask - 1][i]) {
                max = f[mask - 1][i];
                idx = i;
            }
        }
        string ans = "";
        while (status != 0) {
            if (last == -1) ans = ws[idx];
            else ans = ws[idx].substr(0, ws[idx].length() - g[idx][last]) + ans;
            last = idx;
            idx = p[status][idx];
            status ^= (1 << last);
        }
        return ans;
    }
};

TypeScript 代码:

function shortestSuperstring(ws: string[]): string {
    const n = ws.length, mask = 1 << n;
    const g = new Array(n).fill(0).map(() => new Array(n).fill(0));
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {
            const a = ws[i], b = ws[j];
            const l1 = a.length, l2 = b.length;
            const len = Math.min(l1, l2);
            for (let k = len; k >= 1; k--) {
                if (a.substring(l1 - k) === b.substring(0, k)) {
                    g[i][j] = k;
                    break;
                }
            }
        }
    }
    const f = new Array(mask).fill(0).map(() => new Array(n).fill(0));
    const p = new Array(mask).fill(0).map(() => new Array(n).fill(0));
    for (let s = 0; s < mask; s++) {
        for (let i = 0; i < n; i++) {
            if (((s >> i) & 1) === 0continue;
            for (let j = 0; j < n; j++) {
                if (((s >> j) & 1) === 1continue;
                if (f[s | (1 << j)][j] <= f[s][i] + g[i][j]) {
                    f[s | (1 << j)][j] = f[s][i] + g[i][j];
                    p[s | (1 << j)][j] = i;
                }
            }
        }
    }
    let max = f[mask - 1][0], idx = 0, last = -1, status = mask - 1;
    for (let i = 1; i < n; i++) {
        if (max < f[mask - 1][i]) {
            max = f[mask - 1][i];
            idx = i;
        }
    }
    let ans = "";
    while (status != 0) {
        if (last === -1) ans = ws[idx];    
        else ans = ws[idx].substring(0, ws[idx].length - g[idx][last]) + ans;
        last = idx;
        idx = p[status][idx];
        status ^= (1 << last);
    }
    return ans;
}
  • 时间复杂度:将字符串 的最大长度记为 ,预处理复杂度为 ;状态数量为 DP 复杂度为 。构造答案复杂度为 。整体复杂度为
  • 空间复杂度:

我是宫水三叶,每天都会分享算法知识,并和大家聊聊近期的所见所闻。

欢迎关注,明天见。

更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/707808.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IP地址(YACS)

题目描述 IP地址是一个长度固定为 3232 位 的 01 序列&#xff0c;给定一个IP地址&#xff0c;请将它转成点分十进制后输出。 点分十进制的转化方法如下&#xff1a;首先将IP地址分割成长度相等的四个二进制数字&#xff08;每个二进制数字的长度为 88&#xff09;&#xff0…

鸿运(通天星CMSV6车载)主动安全监控云平台敏感信息泄露漏洞

文章目录 前言声明一、系统简介二、漏洞描述三、影响版本四、漏洞复现五、修复建议 前言 鸿运主动安全监控云平台实现对计算资源、存储资源、网络资源、云应用服务进行7*24小时全时区、多地域、全方位、立体式、智能化的IT运维监控&#xff0c;保障IT系统安全、稳定、可靠运行…

unity初学问题:如何修改图片的坐标

如图&#xff0c;我们想要修改图片的轴心点坐标&#xff08;Pivot&#xff09; 选择图片组 打开编辑器在里面修改即可&#xff08;最下面的Custom Pivot&#xff09;

golang使用gorm操作mysql1

1.mysql连接配置 package daoimport ("fmt""gorm.io/driver/mysql""gorm.io/gorm""gorm.io/gorm/logger" )var DB *gorm.DB// 连接数据库&#xff0c;启动服务的时候&#xff0c;init方法就会执行 func init() {username : "roo…

浅谈 Linux 网络编程 - 网络字节序

文章目录 前言核心知识关于 小端法关于 大端法网络字节序的转换 函数 前言 在进行 socket 网络编程时&#xff0c;会用到字节流的转换函数、例如 inet_pton、htons 等&#xff0c;那么为什么要用到这些函数呢&#xff0c;本篇主要就是对这部分进行介绍。 核心知识 重点需要记…

数仓项目6.0(二)数仓

中间的几步意义就在于&#xff0c;缓存中间处理数据样式&#xff0c;避免重复计算浪费算力 分层 ODS&#xff08;Operate Data Store&#xff09; Spark计算过程中&#xff0c;存在shuffle的操作&#xff0c;而shuffle会将计算过程一分为二&#xff0c;前一阶段不执行完&…

链表之“带头双向循环链表”

目录 ​编辑 1.链表的分类 2.带头双向循环链表的实现 1.创建结构体 2.创建返回链表的头节点 3.双向链表销毁 4.双向链表打印 5.双向链表尾插 6.双向链表尾删 7.双向链表头插 8.双向链表头删 9.双向链表查找 10.双向链表在pos的前面进行插入 11.双向链表删除pos位…

ECLIP

denote the representation of the positive prompt produced by the momentum model as h ξ i h_{\xi}^{i} hξi​ 辅助信息 作者未提供代码

二刷代码随想录算法训练营第七天 |454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和

目录 一、454. 四数相加 II 二、383. 赎金信 三、15. 三数之和18. 四数之和 一、454. 四数相加 II 题目链接&#xff1a;力扣 文章讲解&#xff1a;代码随想录 视频讲解&#xff1a; 学透哈希表&#xff0c;map使用有技巧&#xff01;LeetCode&#xff1a;454.四数相加II…

蓝桥杯前端Web赛道-课程列表

蓝桥杯前端Web赛道-课程列表 题目链接&#xff1a;0课程列表 - 蓝桥云课 (lanqiao.cn) 题目要求如下&#xff1a; 分析题目我们发现其实就是需要我们手写一个分页的功能&#xff0c;根据题目的要求&#xff0c;分析如下 需要通过axios获取数据每页显示5条数据&#xff0c;默…

P1927 防护伞

题目传送门 题目描述 据说 2012 的灾难和太阳黑子的爆发有关。于是地球防卫小队决定制造一个特殊防护伞&#xff0c;挡住太阳黑子爆发的区域&#xff0c;减少其对地球的影响。由于太阳相对于地球来说实在是太大了&#xff0c;我们可以把太阳表面看作一个平面&#xff0c;中心…

黑马程序员java部分笔记(持续更新)九点六:数组的常见操作

数组的常见操作&#xff1a; 求最值 求和 交换数据 打乱数据 ---------------------------------------------------------------------------------------------------------------------------------1.求最值&#xff1a;【个人建议看看B站上的视频&#xff0c;提有意思的】…

11.vue学习笔记(组件生命周期+生命周期应用+动态组件+组件保持存活)

文章目录 1.组件生命周期2.生命周期应用2.1通过ref获取元素DOM结构2.2.模拟网络请求渲染数据 3.动态组件3.1.A&#xff0c;B两个组件 4.组件保持存活&#xff08;销毁期&#xff09; 1.组件生命周期 每个Vue组件实例在创建时都需要经历一系列的初始化步骤&#xff0c;比如设置…

Android摄像头横屏的时候_人脸预览横向显示_问题解决---Android原生开发工作笔记164

在Android系统的平板中发现一个问题,我们做的一个Android程序,横屏的时候,摄像头在上面, 然后这个时候程序中的一个人脸预览页面,横向手持平板,摄像头在上面,但是这个时候预览的摄像头画面却是很像头像朝左,也是横过来的. private int getCameraOrientation(int cameraId) {Ca…

Rocky Linux安装部署Elasticsearch(ELK日志服务器)

一、Elasticsearch的简介 Elasticsearch是一个强大的开源搜索和分析引擎&#xff0c;可用于实时处理和查询大量数据。它具有高性能、可扩展性和分布式特性&#xff0c;支持全文搜索、聚合分析、地理空间搜索等功能&#xff0c;是构建实时应用和大规模数据分析平台的首选工具。 …

Linux学习之system V

目录 一&#xff0c;system V共享内存 快速认识接口 shmget(shared memory get) shmat(shared memory attach) shmdt(shared memory delete) shmctl (shared memory control) 编写代码 综上那么共享内存与管道通信有什么区别&#xff1f; system v消息队列 system v信号…

《Effective C++》- 极精简版 41-55条

本文章属于专栏《业界Cpp进阶建议整理》 继续上篇《Effective C》- 极精简版 31-40条。本文列出《Effective C》的41-55条的个人理解的极精简版本。 40、谨慎使用多重继承 个人见解&#xff1a;这是一个性价比不高的功能&#xff0c;容易出错&#xff0c;且收益不高。java语言…

代码随想录训练营总结篇

1:刚开始学习了数据结构的时候,碰到一些树图等有点畏难,感觉刷力扣跟是一件恐怖的事情 2:在网上找了很多关于数据结构与算法的视频讲解,有听进去,但是自己动手写有点困难 3:碰到一些比较复杂的问题时需要与人讨论,加了一些代码随想录中的群,发现这里是学习算法 的天堂,大家都…

【深度学习笔记】深度卷积神经网络——NiN

网络中的网络&#xff08;NiN&#xff09; LeNet、AlexNet和VGG都有一个共同的设计模式&#xff1a;通过一系列的卷积层与汇聚层来提取空间结构特征&#xff1b;然后通过全连接层对特征的表征进行处理。 AlexNet和VGG对LeNet的改进主要在于如何扩大和加深这两个模块。 或者&am…

Android 14 权限

问题Android 14 按照视频播放类的应用 无法获取到权限。 原因是从 Android 13 开始&#xff0c;如果你的应用程序 targetSdk 指定到了 33 或以上&#xff0c;那么 READ_EXTRERNAL_STORGE 权限就完全失去了作用&#xff0c;申请它将不会产生任何效果。 与此相对应的&#xff0c…