本次刷题日记的第 61 篇,力扣题为:926. 将字符串翻转到单调递增,中等
一、题目描述:
继续做一些字符串的题,本次还是带有函数特性的单调递增翻转字符串
二、这道题考察了什么思想?你的思路是什么?
翻转字符串成单点递增的,看看都展示了哪些重要信息:
- 题目中给出的一个字符串,里面的字符只有
0
和1
,且顺序不定,也不会有其他多余的字符种类 - 题目要求我们编写程序将字符串中的
0
翻转成1
,或者是将1
翻转成0
,只要能够达到最终的字符串是单调递增的题目不需要咱们真的在原字符串上进行翻转,只需要返回需要翻转的次数即可,且还需要明确达到目的的翻转次数要是最小的 - 什么是单调递增,如果这个字符串最终结果是 全
0
或者 全1
,那么算是单点递增的,另外如果0
和1
都在同一个字符串中的情况下,一定是0
开头,1
结尾,且相邻字符是一样的,除了字符串中间的0
过渡到1
的时候
分析
那么我们看了上述重要信息,知道单调递增是怎回事之后,我们是需要来考虑如何翻转的事情了
其实将原字符串翻转成单调递增的字符串不麻烦,很轻易就能够想到,直接将字符串中的 0
全部翻转成全 1
,或者全 1
翻转成 0
,得到的结果一定是单调递增的
可是,题目还有一个要求是,我们得到的结果翻转次数要是最小的才可以
那么接下来,咱么你要考虑的是,如何有想法的翻转,而不是无脑的翻转
翻转无非两种,即,0
翻转成 1
,或者将 1
翻转成 0
那我们如何判断要进行哪一种翻转呢?
思考片刻,我们知道当前位置的字符,是否需要翻转成 0
/ 1
是依赖于当前字符的前一个字符翻转成啥来决定的,例如
- 如果字符串就是一个 "0" ,咱们可以定义 2 个变量来记录当前字符需要翻转成
0
/1
的次数
0 |
例如上述字符串,dp[0][0] = 0 , dp[0][1] = 1 ,什么意思呢?
也就是说上述的第 0 个字符,将他翻转成 0
,需要翻转 0 次,将他翻转成 1
需要翻转 1 次
又如:
1 |
则,就有 dp[0][0] = 1 , dp[0][1] = 0
再如:
0 | 1 |
同样的逻辑和方法,就有
dp[0][0] = 0 , dp[0][1] = 1
dp[1][0] = dp[0][0] = 0, dp[1][1] =0 + min(dp[0][0], dp[0][1]) = 0
啥意思呢?
对于需要翻转成字符0
, 如果是需要是单调递增的话,那么他的前面必须是 0 ,因此需要直接将前面的字符明确需要翻转成 0 的次数 直接赋值即可
那么对于需要翻转成字符1
, 需要是单调递增的话,他的前面可以是 0
,也可以是 1
,所以其实直接将前面字符串明确翻转成 0 的次数,或者是 1 的次数直接加上即可,但是题目要求我们是翻转最小的次数,因此需要求前面翻转次数的最小值
看到这里,相信思路应该会很清晰了吧,自己可以推演一下就能更加深刻了,这个其实就是使用了动态规划的方法
需要整体字符串满足单调递增,那么局部也需要是满足单调递增的,直到将字符串 s 完全遍历,得到的结果,咱们去 翻转成 0 的次数 与 翻转成 1 的次数的最小值即可
三、编码
根据上述逻辑和分析,我们就可以翻译成如下代码
编码的时候,咱们初始化可以将 dp0 , 和 dp1 都赋值为 0,表示至少翻转 0 次
编码如下:
func minFlipsMonoIncr(s string) int { dp0, dp1 := 0, 0 for _, v := range s { tmp0, tmp1 := dp0, min(dp0, dp1) if v == '1'{ tmp0++ }else{ tmp1++ } dp0, dp1 = tmp0, tmp1 } return min(dp0, dp1) } func min(a, b int) int { if a < b { return a } return b }
四、总结:
就目前这种实现方式来看,时间复杂度是非常明确的,咱们遍历了一遍 s 字符串,因此时间复杂度是 O(n)
空间复杂度是 O(1) , 又因为咱们引入的变量都是常数级别的空间消耗
原题地址:926. 将字符串翻转到单调递增
今天就到这里,学习所得,若有偏差,还请斧正
欢迎点赞,关注,收藏
朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力
好了,本次就到这里
技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。
我是阿兵云原生,欢迎点赞关注收藏,下次见~