本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 [BaguTree Pro] 知识星球提问。

T1. 最大字符串配对数目(Easy)

  • 标签:散列表

T2. 构造最长的新字符串(Medium)

  • 标签:模拟

T3. 字符串连接删减字母(Medium)

  • 标签:状态 DP

T4. 统计没有收到请求的服务器数目(Medium)

  • 标签:排序、滑动窗口、离散化


T1. 最大字符串配对数目(Easy)

  1. https://leetcode.cn/problems/find-maximum-number-of-string-pairs/

题解(散列表)

题目说明所有字符串不相同,因此我们可以枚举每个字符串,检查其反转是否存在,模板类似于两数之和;

  • 扩展:如果字符串存在重复,可以将配对的字符分组再按两两配对计算;
  • 扩展:如果字符串长度很长会存在散列冲突,可以调整 U 为较大素数。
  1. class Solution {
  2. fun maximumNumberOfStringPairs(words: Array<String>): Int {
  3. val U = 26
  4. val set = HashSet<Int>()
  5. var ret = 0
  6. for (word in words) {
  7. if (word.length != 2) continue
  8. val key = (word[0] - 'a') * U + (word[1] - 'a')
  9. val reversedKey = (word[1] - 'a') * U + (word[0] - 'a')
  10. if (set.contains(reversedKey)) ret ++
  11. set.add(key)
  12. }
  13. return ret
  14. }
  15. }

复杂度分析:

  • 时间复杂度:$O(L)$ 需要访问每个单词的每个字符;
  • 空间复杂度:$O(n)$ 散列表空间。

T2. 构造最长的新字符串(Medium)

  1. https://leetcode.cn/problems/construct-the-longest-new-string/

题解(模拟)

根据题意分析,我们总可以将 ABAB..ABAB 置于结果中间,再将 AA 或 BB 置于两边。此时所有 AB 都可选,而 AA BB 最多只能选择较少者 + 1,分类讨论即可:

  1. class Solution {
  2. fun longestString(x: Int, y: Int, z: Int): Int {
  3. return if (x == y) {
  4. (x + y + z) * 2
  5. } else {
  6. (Math.min(x, y) * 2 + 1 + z) * 2
  7. }
  8. }
  9. }

复杂度分析:

  • 时间复杂度:$O(1)$
  • 空间复杂度:$O(1)$

T3. 字符串连接删减字母(Medium)

  1. https://leetcode.cn/problems/decremental-string-concatenation/

题解(状态 DP)

  • 对于每个字符串 [i],有拼接到前方或拼接到后方两种方案;
  • 当考虑 join(i, i + 1) 时,我们只需要关心两个字符串的首尾 4 个字符,对于中间的字符是不关心的。因此在遍历到字符串 [i] 时,我们检查以 [i - 1] 为结尾的子问题的可能方案,并维护以 [i] 为结尾的子问题的所有方案。
  1. class Solution {
  2. fun minimizeConcatenatedLength(words: Array<String>): Int {
  3. val INF = 0x3F3F3F3F
  4. val n = words.size
  5. val dp = Array(n) { Array(26) { IntArray(26) { INF } }}
  6. // 起始状态
  7. dp[0][words[0][0] - 'a'][words[0][words[0].length - 1] - 'a'] = words[0].length
  8. for (i in 1 until n) {
  9. val word = words[i]
  10. val x = word[0] - 'a'
  11. val y = word[word.length - 1] - 'a'
  12. // 枚举子问题状态
  13. for (j in 0 until 26) {
  14. for (k in 0 until 26) {
  15. // 拼接到前方
  16. if (y == j) {
  17. dp[i][x][k] = Math.min(dp[i][x][k], dp[i - 1][j][k] + word.length - 1)
  18. } else {
  19. dp[i][x][k] = Math.min(dp[i][x][k], dp[i - 1][j][k] + word.length)
  20. }
  21. // 拼接到后方
  22. if (x == k) {
  23. dp[i][j][y] = Math.min(dp[i][j][y], dp[i - 1][j][k] + word.length - 1)
  24. } else {
  25. dp[i][j][y] = Math.min(dp[i][j][y], dp[i - 1][j][k] + word.length)
  26. }
  27. }
  28. }
  29. }
  30. var ret = INF
  31. for (j in 0 until 26) {
  32. for (k in 0 until 26) {
  33. ret = Math.min(ret, dp[n - 1][j][k])
  34. }
  35. }
  36. return ret
  37. }
  38. }

复杂度分析:

  • 时间复杂度:$O(n·C^2)$ C= 26
  • 空间复杂度:$O(n·C^2)$

T4. 统计没有收到请求的服务器数目(Medium)

  1. https://leetcode.cn/problems/count-zero-request-servers/

题解一(暴力)

线性扫描日志,并线性扫描查询列表,将日志记录投递到对应的查询中,同时使用散列表对相同服务器去重。

  1. class Solution {
  2. fun countServers(n: Int, logs: Array<IntArray>, x: Int, queries: IntArray): IntArray {
  3. val m = queries.size
  4. val sets = Array(m) { HashSet<Int>() }
  5. val ret = IntArray(m)
  6. // 暴力
  7. for (log in logs) {
  8. for ((i, query) in queries.withIndex()) {
  9. if (log[1] in query - x .. query) {
  10. sets[i].add(log[0])
  11. }
  12. }
  13. }
  14. // 输出
  15. for (i in 0 until m) {
  16. ret[i] = n - sets[i].size
  17. }
  18. return ret
  19. }
  20. }

复杂度分析:

  • 时间复杂度:$O(nm)$ 超出时间限制;
  • 空间复杂度:$O(nm)$ 散列表空间,最坏情况下每个查询中包含所有服务器记录。

题解二(排序 + 滑动窗口 + 离散化)

需要注意题目中的单调性,对于日志时间 log_i < log_j,当 log_i 时间晚于 query_k 时,那么日志时间更晚的 log_k 必然无法投递到 query_k 中,而暴力算法中没有利用单调性质。因此,我们先对 log 日志列表和 queries 查询列表按时间顺序排序,再来使用滑动窗口来维护每个查询中覆盖的日志信息。

  1. class Solution {
  2. fun countServers(n: Int, logs: Array<IntArray>, x: Int, queries: IntArray): IntArray {
  3. val l = logs.size
  4. val m = queries.size
  5. val ret = IntArray(m)
  6. // 查询索引
  7. val indexs = Array(m) { it }
  8. // 排序
  9. Arrays.sort(logs) { i1, i2 ->
  10. i1[1] - i2[1]
  11. }
  12. Arrays.sort(indexs) { i1, i2 ->
  13. queries[i1] - queries[i2]
  14. }
  15. // 滑动窗口 + 离散化
  16. var i = 0
  17. var j = 0
  18. val cnts = HashMap<Int, Int>()
  19. for (id in indexs) {
  20. val to = queries[id]
  21. if (to <= x) throw IllegalStateException()
  22. // 拓展右指针
  23. while (j < l && logs[j][1] <= to) {
  24. cnts[logs[j][0]] = cnts.getOrDefault(logs[j][0], 0) + 1
  25. j++
  26. }
  27. // 收缩左指针
  28. while (i < l && logs[i][1] < to - x) {
  29. cnts[logs[i][0]] = cnts[logs[i][0]]!! - 1
  30. if (cnts[logs[i][0]]!! == 0) cnts.remove(logs[i][0])
  31. i++
  32. }
  33. ret[id] = n - cnts.size
  34. }
  35. return ret
  36. }
  37. }

复杂度分析:

  • 时间复杂度:$O(mlgm + llogl + m + l)$ 瓶颈在排序;
  • 空间复杂度:$O(m + n)$ 查询索引数组空间 + 散列表空间。

往期回顾

LeetCode 双周赛 107(2023/06/24)滑动窗口与离散化的更多相关文章

  1. LeetCode 双周赛 102,模拟 / BFS / Dijkstra / Floyd

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 大家好,欢迎来到小彭的 LeetCode 周赛解题报告. 昨晚是 LeetCode 双周赛第 102 场,你 ...

  2. LeetCode 双周赛 98,脑筋急转弯转不过来!

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 大家好,我是小彭. 昨晚是 LeetCode 第 98 场双周赛,你参加了吗?这场周赛需要脑筋急转弯,转不过 ...

  3. 刷爆 LeetCode 双周赛 100,单方面宣布第一题最难

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 大家好,我是小彭. 上周末是 LeetCode 第 100 场双周赛,你参加了吗?这场周赛整体没有 Hard ...

  4. LeetCode 双周赛 101,DP/中心位贪心/裴蜀定理/Dijkstra/最小环

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 大家好,我是小彭. 这周比较忙,上周末的双周赛题解现在才更新,虽迟但到哈.上周末这场是 LeetCode 第 ...

  5. [leetcode]346. Moving Average from Data Stream滑动窗口平均值

    Given a stream of integers and a window size, calculate the moving average of all integers in the sl ...

  6. leetcode 3 Longest Substring Without Repeating Characters(滑动窗口)

    用滑动窗口的思想来做.用一个unordered_map来查询之前的char有没有在现在的窗口中. class Solution { public: int lengthOfLongestSubstri ...

  7. Leetcode 30 串联所有单词的子串 滑动窗口+map

    见注释.滑动窗口还是好用. class Solution { public: vector<int> findSubstring(string s, vector<string> ...

  8. [每日一题2020.06.16] leetcode双周赛T3 5423 找两个和为目标值且不重叠的子数组 DP, 前缀和

    题目链接 给你一个整数数组 arr 和一个整数值 target . 请你在 arr 中找 两个互不重叠的子数组 且它们的和都等于 target .可能会有多种方案,请你返回满足要求的两个子数组长度和的 ...

  9. LeetCode双周赛#36

    1604. 警告一小时内使用相同员工卡大于等于三次的人 题目链接 题意 给定两个字符串数组keyName和keyTime,分别表示名字为keytime[i]的人,在某一天内使用员工卡的时间(格式为24 ...

  10. leetcode 双周赛9 进击的骑士

    一个坐标可以从 -infinity 延伸到 +infinity 的 无限大的 棋盘上,你的 骑士 驻扎在坐标为 [0, 0] 的方格里. 骑士的走法和中国象棋中的马相似,走 “日” 字:即先向左(或右 ...

随机推荐

  1. 修复kube-proxy证书权限过大问题

    修复kube-proxy证书权限过大问题 之前kube-proxy服务都是用admin集群证书,造成权限过大不安全,后续该问题,将在文档中修复 请关注 https://github.com/cby-c ...

  2. Java 框架面试题-Spring Boot自定义配置与自动配置共存

    Spring Boot 是一个快速开发框架,可以简化 Spring 应用程序的开发,其中自定义配置是其中一个非常重要的特性. 在 Spring Boot 中,自定义配置允许开发者以自己的方式来配置应用 ...

  3. 还原win10任务管理器的内存dump功能之——程序逆向分析(待完成)

    逆向分析工作基本完成,笔记待完成.

  4. 【python爬虫】爬取美女图片

    一,导入包文件 os:用于文件操作.这里是为了创建保存图片的目录 re:正则表达式模块.代码中包含了数据处理,因此需要导入该模块 request:请求模块.通过该模块向对方服务器发送请求获取数据包 l ...

  5. 生产事故-走近科学之消失的JWT

    入职多年,面对生产环境,尽管都是小心翼翼,慎之又慎,还是难免捅出篓子.轻则满头大汗,面红耳赤.重则系统停摆,损失资金.每一个生产事故的背后,都是宝贵的经验和教训,都是项目成员的血泪史.为了更好地防范和 ...

  6. CSS笔记(待完善)

    CSS笔记 css权重 ID(100)> class(10)> element(1) css最高权重 !important 块元素(block) 可以设置宽度和高度,独立成行. h1~h6 ...

  7. 读《mysql是怎样运行的》有感

    最近读了一本书<mysql是怎样运行的>,读完后在大体上对mysql的运行有一定的了解.在以前,我对mysql有以下的为什么: InnoDB中的表空间.段.区和页是什么? redo log ...

  8. Django笔记三十之log日志记录详解

    本文首发于公众号:Hunter后端 原文链接:Django笔记三十之log日志的记录详解 这一节介绍在 Django 系统里使用 logging 记录日志 以下是一个简单的 logging 模块示例, ...

  9. 还不知道怎么 Mock ,用这 6款工具!

    以下是几个常用的国外可以mock测试的工具,供参考: MockServer: MockServer 是一个开源的 API mock 测试工具,提供了强大的模拟服务器和 mock 服务功能.MockSe ...

  10. 【有问必答】搭建uniapp项目流程手把手教学

    前言 缘由 博友有问,狗哥必答 前段时间,博友加本狗微信,询问uniapp的学习方法.本狗资历浅薄,没有专门学过uniapp,只能将自己日常开发uniapp的基本流程和步骤进行分享,希望可以略尽绵薄之 ...