持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情
测试岗位也越来卷了,除了基本的功能测试外,还要有编程基础、脚本经验才脱颖而出。
怎么才能提高我们的编程能力呢,刷LeetCode是最佳的途径之一,话不多数,刷题走起~
一、题目描述:
-
题目内容
-
题目示例
-
题目解析
1 <= s.length <= 10**5s[i]为'0'或'1'
二、思路分析:
我们读取题目,题目要求对一个二进制的字符进行翻转,使其里面字符呈单调递增。返回最小的翻转次数。
在题目中,我们可以获取到如下几点信息💻:
- 字符串s都是由 "0" 和 "1"组成
- 单调递增规则:不能出现'0'和"1"交错的现象,因此只能有三种形式出现000..111,000...000,111..111
- 通过翻转,使"0"变成"1",或者使"1"变成"0",来达到字符串s单调递增
我们来通过如下示列2来,推理说明如下:
还记得,我们刷过的497. 非重叠矩形中的随机点题目,通过前缀和记录所有的矩形的面积。
因此,今天本题仍然使用此思路,使用前缀和来记录📝,遍历字符串前面出现的字符'0'或者"1"的个数,解答该题的思路:
-
方法一:前缀和+枚举
- 首先,通过前缀和方法计算出字符串出现字符‘1’翻转个数
- 前缀和公式:P[i+1] = p[0]+p[1]+p[2]+...+p[i]
- 当p[i]为x个1,则需要翻转的次数为len(s)-i-(p[len(s)]-p[i])个字符'0'需要去翻转
- 直到遍历完字符串s所有字符,返回最小值
- 我们定义初始结果ans时,要定义大于10**5,否则会通过不了81/93条case
class Solution(object): def minFlipsMonoIncr(self, s): """ :type s: str :rtype: int """ p = [0]*(len(s)+1) for i in range(len(s)): p[i+1] = p[i] + int(s[i]) ans = 1000000 for i in range(len(s)+1): ans = min(ans,p[i]+len(s)-i-(p[len(s)]-p[i])) return ans -
方法二:简单的动态规划
- 本题中,对于字符串s来说,只存在要么翻转字符'0'或者字符'1'两种可能
- 因此,我们只需要定义两个变量来dp0来记录翻转0次数,dp1来记录翻转1的次数
- 字符1和字符0翻转中,只存在四种情况 00,11,10,01,因此dp[i]只与dp[i-1]有关
class Solution(object): def minFlipsMonoIncr(self, s): """ :type s: str :rtype: int """ dp0 = dp1 = 0 for i in s: tmpdp0,tmpdp1 = dp0,min(dp0,dp1) if i == "1": tmpdp0 = tmpdp0 +1 else: tmpdp1 = tmpdp1 + 1 dp0,dp1 = tmpdp0,tmpdp1 return min(dp0,dp1)
三、总结:
本题,仍然考察我们前缀和使用方法,通过前缀和记录字符串左边出现1到个数,然后通过公式计算出n-i-(p[n]-p[i])个0的需要翻转的,最后遍历完整个字符串s返回最小值。同样也可以使用动态规划,因为dp[i]与dp[i-1]存在关系,只有存储下一个状态值,减少空间的浪费,AC提交记录如下:
- 时间复杂度O(n),n为字符串s的长度
- 空间复杂度O(1),无额外空间占用
以上是本期内容,欢迎大佬们点赞评论,下期见~~