力扣每日打卡

92 阅读7分钟

1631最小体力消耗路径 2023-12-11

题目描述

你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) ,且你希望去最右下角的格子 (rows-1, columns-1) (注意下标从 0 开始编号)。你每次可以往  四个方向之一移动,你想要找到耗费 体力 最小的一条路径。

一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。

请你返回从左上角走到右下角的最小 体力消耗值 。

题解

看到这题的第一个想法就是回溯法加剪枝,但是发现超出时间限制,于是看了题解。

方法一:二分查找

是否存在一条从左上角到右下角的路径,其经过的所有边权的最大值不超过x?基本思路就是只允许经过边长不大于x的边。二分的核心思想就是left=0,right=maxvalue,然后取mid。如果当前能够找到一条路径到达终点则right=mid-1,并且把此时的x记录下来,否则left=mid+1,增大x继续查找。

时间复杂度为O(mnlogC)logC是查找x的时间mn是遍历地图的时间。

在抄写代码的过程中一个abs的括号出错查了半天。

方法二:并查集

我们将这 mn 个节点放入并查集中,实时维护它们的连通性。

由于我们需要找到从左上角到右下角的最短路径,因此我们可以将图中的所有边按照权值从小到大进行排序,并依次加入并查集中。当我们加入一条权值为 x 的边之后,如果左上角和右下角从非连通状态变为连通状态,那么 x 即为答案

关于并查集我也做过几次,但其实依旧不是很熟悉,它的核心思想就是动态维护一堆树,只要满足某个条件就可以把树归并起来,树上的所有节点都有一个共同的根。

本题是给矩阵的每个格一个id,然后把所有联通的边不断放进去,这样每次加入新的边就有可能改变联通条件,从小到大不断放入,如果终点和起点联通说明满足最终的条件了。

并查集核心的就是findset以及归并的步骤。

值得多次推敲。

这两种解法的核心都是找x而不是找路径。

方法三:最短路

这其实也是dijstra的算法,只不过路径的长度不是边长之和而是最大边长的值,根据定义的不同,每次选择下一个点的规则也不一样,本题直接用最小堆的数据结构返回所有边长中最小的值。这样到达终点时就能确保路径最短,也就是路径上最大边长的值最小。大开眼界!

dist存储的则是每个节点到出发点的最大距离,需要不断更新。

2696. 删除子串后的字符串最小长度

题目描述

给你一个仅由 大写 英文字符组成的字符串 s 。

你可以对此字符串执行一些操作,在每一步操作中,你可以从 s 中删除 任一个 "AB" 或 "CD" 子字符串。

通过执行操作,删除所有 "AB" 和 "CD" 子串,返回可获得的最终字符串的 最小 可能长度。

注意,删除子串后,重新连接出的字符串可能会产生新的 "AB" 或 "CD" 子串。

解答

这题值得严重反思,看到题目首先想的是用什么方法,比如双指针,比如动态规划,但是这题很明显的就是栈的应用,而且是特别天然适合栈的一道题,可我愣是没有想出来,一直在尝试节省空间的情况下试图用双指针解答。

看了参考第一眼,知道是栈之后瞬间就明白过来了,这题也就很简单了,不需赘述。

2645. 构造有效字符串的最少插入数

给你一个字符串 word ,你可以向其中任何位置插入 "a"、"b" 或 "c" 任意次,返回使 word 有效 需要插入的最少字母数。

如果字符串可以由 "abc" 串联多次得到,则认为该字符串 有效

这题还是比较好笑的,我第一眼想到分情况讨论,用支持向量机的方式来做,虽然真让我做出来了,而且状态设置也很合理,主要有三个状态分别是'a','ab','abc',然后依据当前输入的字符来判断是否要添加。

可是当我看到官方题解的时候发现自己还是太天真。第一种是动态规划,第二种是暴力求解,只要当前字符小于前一个字符,说明肯定不在同一组,不断统计有多少组最后减去实际的长度就是要插入值,感觉就是我这种解法的一种更高提炼,没有考虑那么多细节最后也能做出来,其实还是对这题的理解足够深才能这么写,要学的东西还很多啊。

2182. 构造限制重复的字符串

给你一个字符串 s 和一个整数 repeatLimit ,用 s 中的字符构造一个新字符串 repeatLimitedString ,使任何字母 连续 出现的次数都不超过 repeatLimit 次。你不必使用 s 中的全部字符。

返回 字典序最大的 **repeatLimitedString 。

如果在字符串 a 和 b 不同的第一个位置,字符串 a 中的字母在字母表中出现时间比字符串 b 对应的字母晚,则认为字符串 a 比字符串 b 字典序更大 。如果字符串中前 min(a.length, b.length) 个字符都相同,那么较长的字符串字典序更大。

这题很有意思,有意思的不是思路,而是字符串的一些方法,我看到本题首先想到的就是贪心算法,统计所有字符的个数,然后从后向前,如果超过repeatlimit就把前一个字符放进去,然后重复。

但我第一遍做的时候却说超出内存限制,发现我用的是operator +,这个方法每次都会构造一个新的字符串因此会占用大量的内存,于是我查了字符串的一些方法,有insert,有append,有push_back,但是append只限于字符串,所以就需要insert和push_back,相比起来insert可以插入任意位置,但是本题我只需要再最后一个位置就行,所以用push_back就可以在原字符串后面不断添加。值得记住。

2865. 美丽塔 I

给你一个长度为 n 下标从 0 开始的整数数组 maxHeights 。

你的任务是在坐标轴上建 n 座塔。第 i 座塔的下标为 i ,高度为 heights[i] 。

如果以下条件满足,我们称这些塔是 美丽 的:

  1. 1 <= heights[i] <= maxHeights[i]
  2. heights 是一个 山脉 数组。

如果存在下标 i 满足以下条件,那么我们称数组 heights 是一个 山脉 数组:

  • 对于所有 0 < j <= i ,都有 heights[j - 1] <= heights[j]
  • 对于所有 i <= k < n - 1 ,都有 heights[k + 1] <= heights[k]

请你返回满足 美丽塔 要求的方案中,高度和的最大值 。

这题一开始就是想到循环,当第i个元素为山峰时的结果,需要两边遍历,依次递减,时间复杂度O(n^2),看了题解后,很巧妙,用了两次单调栈,然后是两个数组,一个储存的是从第一个元素到第i个元素满足条件的和,另一个是从最后一个到第i个的,然后遍历的时候用单调栈,如果当前高度小于那就一直弹出直到大于等于,这是前面的和就是prefix[i],从当前到第i个就是(i-j)* maxheights[i] 了,非常巧妙。后面的也是一样。