LeetCode 周赛 347(2023/05/28)二维空间上的 LIS 最长递增子序列问题

熵流
• 阅读 546
本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。

周赛 347 概览

T1. 移除字符串中的尾随零(Easy)

  • 标签:模拟、字符串

T2. 对角线上不同值的数量差(Easy)

  • 标签:前后缀分解

T3. 使所有字符相等的最小成本(Medium)

  • 标签:模拟、贪心

T4. 矩阵中严格递增的单元格数(Hard)

  • 标签:排序、动态规划

LeetCode 周赛 347(2023/05/28)二维空间上的 LIS 最长递增子序列问题


T1. 移除字符串中的尾随零(Easy)

https://leetcode.cn/problems/remove-trailing-zeros-from-a-string/

题解(模拟)

基于 StringBuilder:

class Solution {
    fun removeTrailingZeros(num : String): String {
        if (num.length == 1) return num
        val builder = StringBuilder(num)
        while (builder.last() == '0') {
            builder.deleteCharAt(builder.lastIndex)
        }
        return builder.toString()
    }
}

基于正则表达式匹配:

class Solution {
    fun removeTrailingZeros(num : String): String {
        return num.replace(Regex("0*$"), "")
    }
}

复杂度分析:

  • 时间复杂度:$O(n)$
  • 空间复杂度:$O(1)$ 不考虑结果字符串

T2. 对角线上不同值的数量差(Easy)

https://leetcode.cn/problems/difference-of-number-of-distinct-values-on-diagonals/

题解(前后缀分解)

第一次扫描增加正权,第二次扫描增加负权:

class Solution {
    fun differenceOfDistinctValues(grid: Array<IntArray>): Array<IntArray> {
        // 两次扫描
        val n = grid.size
        val m = grid[0].size
        val ret = Array(n) { IntArray(m) }
        
        for (row in 0 until n) {
            var i = row
            var j = 0
            val set = HashSet<Int>()
            while (i < n && j < m) {
                ret[i][j] += set.size
                set.add(grid[i][j])
                i++
                j++
            }
        }
        
        for (col in 1 until m) {
            var i = 0
            var j = col
            val set = HashSet<Int>()
            while (i < n && j < m) {
                ret[i][j] = set.size
                set.add(grid[i][j])
                i++
                j++
            }
        }

        for (row in 0 until n) {
            var i = row
            var j = m - 1
            val set = HashSet<Int>()
            while (i >= 0 && j >= 0) {
                ret[i][j] = Math.abs(ret[i][j] - set.size)
                set.add(grid[i][j])
                i--
                j--
            }
        }
        
        for (col in 0 until m - 1) {
            var i = n - 1
            var j = col
            val set = HashSet<Int>()
            while (i >= 0 && j >= 0) {
                ret[i][j] = Math.abs(ret[i][j] - set.size)
                set.add(grid[i][j])
                i--
                j--
            }
        }
        return ret
    }
}

复杂度分析:

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

T3. 使所有字符相等的最小成本(Medium)

https://leetcode.cn/problems/minimum-cost-to-make-all-characters-equal/

题解一(模拟)

从中间开始翻转,将不符合目标的字符向两端推,选择反转到 ‘1’ 和 ‘0’ 两个方案的最优解:

class Solution {
    
    private fun op(s:String, target:Char) :Long {
        val n = s.length
        var ret = 0L
        var flag = true
        for (i in n / 2 - 1 downTo 0) {
            if ((flag && s[i] != target) || (!flag && s[i] == target)) {
                ret += i + 1
                flag = !flag
            }
        }
        flag = true
        for (i in n / 2 until n) {
            if ((flag && s[i] != target) || (!flag && s[i] == target)) {
                ret += n - i
                flag = !flag
            }
        }
        return ret
    }
    
    fun minimumCost(s: String): Long {
        return Math.min(op(s,'0'), op(s,'1'))
    }
}

复杂度分析:

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

题解二(找规律)

当相邻字符串不相等时,必然需要反转。如果接近左边往左边翻转的成本更低,同时,如果接近右边,往右边翻转的成本更低。

class Solution {
    fun minimumCost(s: String): Long {
        val n = s.length
        var ret = 0L
        for (i in 1 until n) {
            if (s[i - 1] != s[i]) {
                ret += Math.min(i, n - i)
            }
        }
        return ret
    }
}

复杂度分析:

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

T4. 矩阵中严格递增的单元格数(Hard)

https://leetcode.cn/problems/maximum-strictly-increasing-cells-in-a-matrix/
  • 错误思路:

从最大值开始逆向推导,但是最优路径不一定会经过最大值。

  • 正确思路:

只有小的数字才能到大的数字,因此我们先将所有数字进行排序,对于每个数字储存其对应的所有位置。此时,每个位置的 LIS 最长序列长度只跟其排序前面的数字中位于同行和同列的数字有关,即前面数字且处于同行同列的最长路径 + 1。

class Solution {
    fun maxIncreasingCells(mat: Array<IntArray>): Int {
        val n = mat.size
        val m = mat[0].size
        var ret = 0
        // 排序
        val map = TreeMap<Int, MutableList<IntArray>>()
        for (i in 0 until n) {
            for (j in 0 until m) {
                map.getOrPut(mat[i][j]) { LinkedList<IntArray>() }.add(intArrayOf(i, j))
            }
        }
        val rowMax = IntArray(n)
        val colMax = IntArray(m)
        // 枚举
        for ((x, indexs) in map) {
            val mx = IntArray(indexs.size)
            // LIS
            for (i in indexs.indices) {
                mx[i] = Math.max(rowMax[indexs[i][0]], colMax[indexs[i][1]]) + 1
                ret = Math.max(ret, mx[i])
            }
            for (i in indexs.indices) {
                rowMax[indexs[i][0]] = Math.max(rowMax[indexs[i][0]], mx[i])
                colMax[indexs[i][1]] = Math.max(colMax[indexs[i][1]], mx[i])
            }
        }
        return ret
    }
}

复杂度分析:

  • 时间复杂度:$O(nm·lg(nm))$ 瓶颈在排序
  • 空间复杂度:$O(nm)$

往期回顾

点赞
收藏
评论区
推荐文章
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Wesley13 Wesley13
4年前
UIWebView长按保存图片和识别图片二维码的实现方案(使用缓存)
0x00需求:长按识别UIWebView中的二维码,如下图长按识别二维码0x01方案1:给UIWebView增加一个长按手势,激活长按手势时获取当前UIWebView的截图,分析是否包含二维码。核心代码:略优点:流程简单,可以快速实现。不足:无法实现保存UIWebView中图片,如果当前We
Stella981 Stella981
4年前
React Hooks实现异步请求实例—useReducer、useContext和useEffect代替Redux方案
<blockquote本文是学习了2018年新鲜出炉的ReactHooks提案之后,针对<strong异步请求数据</strong写的一个案例。注意,本文假设了:<br1.你已经初步了解<codehooks</code的含义了,如果不了解还请移步<ahref"https://reactjs.org/docs/hooksintro.html
Wesley13 Wesley13
4年前
Java面试
<divclass"htmledit\_views"id"content\_views"<pid"maintoc"<strong目录</strong</p<pid"Java%E5%9F%BA%E7%A1%80%EF%BC%9Atoc"style"marginleft:40px;"<ahref"Java%E5%
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Stella981 Stella981
4年前
Prometheus监控学习笔记之PromQL简单示例
0x00简单的时间序列选择返回度量指标http_requests_total的所有时间序列样本数据:http_requests_total返回度量指标名称为http_requests_total,标签分别是job"apiserver",handler"/api/comments"
Stella981 Stella981
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Easter79 Easter79
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Stella981 Stella981
4年前
JVM 字节码指令表
字节码助记符指令含义0x00nop什么都不做0x01aconst\_null将null推送至栈顶0x02iconst\_m1将int型1推送至栈顶0x03iconst\_0将int型0推送至栈顶0x04iconst\_1将int型1推送至栈顶0x05ic