[亚麻高频题] LCP 19. 秋叶收藏集

题目描述&链接

Leetcode - LCP 19 : 寻找能够满足"rrryyyrr" 这种形式的最小翻转次数。

题目思路

[亚麻高频题] Leetcode.926 属于同类型的题目,稍微加了一点难度。

1. 前缀和

同样可以使用前缀和进行计算,我们维护一个数组记录第i个位置前"r"树叶的总数,并可以通过前缀和求差来求出相应"y"树叶的个数。不同于LC926的01翻转我们这里要维护三个区间:

[0,i]: 红树叶1; [i+1, j]: 黄树叶; [j+1, end]: 红树叶2

[0,end] 维护"r..yyy..r"格式的翻转次数:

         i - cntR[0, i]   ([0, i]处需要翻转的"y"的个数) +

         cntR[0, j] - cntR[0, i]  ([i, j]处需要翻转"r"的个数)

         (end - j + cntR[0,end] - cntR[0, j])  ([j, end]处需要翻转"y"的个数)

需要进行两层遍历分别遍历 i,j,代码如下 :

 public int minimumOperations(String leaves) {
        // 前缀和,记录每一个位置r的个数,暴力会超时,需要优化
        // 题目要求只能[2,n-1]位置可以有y
        int n = leaves.length();
        int[] cr = new int[n+1];
        cr[0] = 0;
        for(int i=1; i<=n; i++) {
            cr[i] = cr[i-1] + (leaves.charAt(i-1)=='r'? 1:0);
        }

        int res = n;

        for(int i=1; i<n; i++) {
            for(int j=n-1; j>i; j--) {
                res = Math.min(res, i-cr[i] + cr[j]-cr[i] + n-j-(cr[n]-cr[j]));
            }
        }

        return res;
}

时间复杂度: O(N^{2}) ; 空间复杂度: O(N);这种思路很好理解但是遗憾的是会超时。

2. 动态规划

题目有着明确的状态(红1,黄2,红3),这种有明确状态求最值问题通常都让我们联想到是不是可以用DP求解。首先DP状态如何定义,和LC926一样我们可以建立二维数组dp[N][3]保存状态,dp[i][0/1/2]表示前面i-1个元素保持题目格式情况下当前位置i翻转成 红1/黄1/红2 的最小翻转次数。 接下来如何确定状态转移方程,我们需要考虑三种情况:

1. 当前位置i是红1:那么前面一定只能是全红1 :

         dp[i][0] = dp[i-1][0] + (arr[i]=="y")

2. 当前位置i是黄1: 那么前面可以是全红1"rrrr" 或者 红1和黄1都有"rrryyy" :

         dp[i][1] = min(dp[i-1][0], dp[i-1][1]) + (arr[i]=="r")

3. 当前位置i是红2: 那么前面可以是红1黄1 或者 红1黄1红2都有:

        dp[i][2] = min(dp[i-1][1], dp[i-1][2]) + (arr[i]=="y")

状态和转移方程已经有了,接下来就是状态初始化由于求最小值 dp[*][0]都定义成+ \infty,最后直接返回dp[end][2]。注意这里dp[end][0/1]虽然也能计算出来但是没有意义因为叶子格式不符合提议。 

public int minimumOperations(String leaves) {
        // dp做法
        int n = leaves.length();

        // 状态 - dp[i][0/1/2] -> 前i满足条件当前位置为0/1/2的最小反转数
        int[][] dp = new int[n][3];

        // 初始化 - 第一位必须是0
        dp[0][0] = leaves.charAt(0)=='r'? 0: 1;
        dp[0][1] = Integer.MAX_VALUE;
        dp[0][2] = Integer.MAX_VALUE;
        dp[1][2] = Integer.MAX_VALUE;
        for(int i=1; i<n; i++) {
            dp[i][0] = dp[i-1][0] + (leaves.charAt(i)=='r'? 0: 1);
            dp[i][1] = Math.min(dp[i-1][0], dp[i-1][1]) + (leaves.charAt(i)=='y'? 0: 1);
            if(i>=2) dp[i][2] =  Math.min(dp[i-1][1], dp[i-1][2]) + (leaves.charAt(i)=='r'? 0: 1);
            
        }

        return dp[n-1][2];
    }

时间复杂度: O(N); 空间复杂度: O(N)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值