• 求最长的只含两种元素的连续子数组的长度(动态规划)


    LeetCode题号904 水果成篮,地址:https://leetcode-cn.com/problems/fruit-into-baskets/

    题目说得挺复杂,但是实际上就是求出一个连续子数组,只含有两种元素且长度最长,主要思路来自最大连续子数组和算法(动态规划解释)

    题目举例:

      输入:[3,3,3,1,2,1,1,2,3,3,4]
      输出:5
      解释:[1,2,1,1,2]

    具体思路:

    记原数组为A,定义和A等长的数组B,数组中的元素B[i]表示的含义为以a[i]为结束的最长的只含两种元素的连续子数组,比如:

    A = [3,3,3,1,2]
    B[0] = 1  => 是子数组[1        ]的长度
    B[1] = 2  => 是子数组[1,3      ]的长度
    B[2] = 3  => 是子数组[1,3,3    ]的长度
    B[3] = 4  => 是子数组[1,3,3,1  ]的长度
    B[4] = 2  => 是子数组[      1,2]的长度
    

      显然可以知道的是,B中的最大值,就是整个问题的解,下面探讨B[i+1]和B[i]之间的关系:

    注意到每个B[i]都代表一个子数组,所以其实也可以看做是子数组的生成过程

    ① B中的元素种类小足2,那就直接把A[i]加入子数组,同时注意更新元素种类数量(上述例子中的B[0]、B[1])

    ② B中的元素种类为2,在细分两种情况:

      如果A[i+1]是B[i]中两种元素之一,那么B[i+1] = B[i] + 1(上述例子中的B[2]、B[3])

      如果A[i+1]不是B[i]中两种元素之一,那么需要保留靠后面的一种,并且只能保留最后面的那一段,以保持连续性(上述例子中的B[4])

    构造完成之后输出最大值即可。和最大连续子数组和算法(动态规划解释)类似,这个算法在实现过程可以进行编程上的优化,B[i+1]只和B[i]、A[i+1]相关,最大值也可以边算边记录,子数组并不需要整个记录,具体代码如下:

    class Solution {
    public:
        int totalFruit(vector<int>& tree) {
            int typeCount = 0;        // 当前子数组中有多少类数字
            int type1, type2;         // 每个类的数字
            int type1Last, type2Last; // 最后一段的起点,因为替换类型的时候要保留最后一段
            int subLen = 0;           // 当前子数组长度
            int max = 0;              // 最大值
            
            for (int i = 0; i < tree.size(); i++) {
                if (typeCount == 0) {
                    typeCount = 1;
                    type1 = tree[i];
                    type1Last = i;
                    subLen++;
                } else if (typeCount == 1) {
                    if (tree[i] != type1) {
                        type2 = tree[i];
                        type2Last = i;
                        typeCount = 2;
                    }
                    subLen++;
                } else {
                    if (tree[i] != type1 && tree[i] != type2) {
                        // 只保留最后一段
                        if (type1Last > type2Last) {
                            type2 = tree[i];
                            type2Last = i;
                            subLen = i - type1Last + 1;
                        } else {
                            type1 = tree[i];
                            type1Last = i;
                            subLen = i - type2Last + 1;
                        }
                    } else {
                        // 更新最后一段的位置
                        if (tree[i] == type1 && type1Last < type2Last)
                            type1Last = i;
                        else if (tree[i] == type2 && type2Last < type1Last)
                            type2Last = i;
                        subLen++;
                    }
                }
                
                max = max > subLen ? max : subLen;
            }
            
            return max;        
        }
    };
    

      在具体实现中,对于类型的管理、最后一段的位置的更新可能会有点绕,但这并不是本算法的重点,理清楚了基本算法,剩下的实际上只要细心点就可以理清楚的。

  • 相关阅读:
    关于二叉树遍历的一点想法
    Mysqldump导入数据库很慢的解决办法
    javascript笔记收集
    再次讨论二叉树--如何根据先序和中序推选后序
    一道图的题目-拓扑序概念
    一道哈夫曼二叉树题目--稍微容易一点
    一道哈夫曼树的题目--好不容易
    证明二叉树节点数公式
    一道二叉树题目---顺序存储二叉树位置同层的关系
    POJ 3253 Fence Repair(贪心)
  • 原文地址:https://www.cnblogs.com/guobaoxu/p/10850582.html
Copyright © 2020-2023  润新知