算法题之接雨水

大概思路,先找出所有可能极小值(每次用当前值和上一值进行比较)。最后沿着每个极小值开始进行处理逆向处理,理想时间复杂度介于n和n的平方之间。不说了,上代码,此方法是个人思考,完全没有借鉴任何别人的想法,如有雷同,只是思路相同而已。

public int trap(int[] height) throws Exception {
    int containValue = 0;
    if (height.length == 0) {
        throw new Exception("数组长度不能为0");
    }
    int[] derivativeArr = new int[height.length];
    //记录为递减函数的数组下标值
    List<Integer> negativeList = new ArrayList<Integer>();
    int preValue = 0;
    for (int i = 0; i < height.length; i++) {
        if (height[i] > preValue) {//递增关系
            derivativeArr[i] = 1;
        } else if (height[i] == preValue) {//不变
            derivativeArr[i] = 0;
        } else {
            derivativeArr[i] = -1;
            negativeList.add(i);
        }
        preValue = height[i];
    }
    int[] negativeArr = new int[5];
    negativeArr[2] = 1;
    negativeArr[3] = 0;
    while (negativeArr[2] == 1) {
        negativeArr = getNegativeArr(negativeList, negativeArr[3], derivativeArr);
        int rightBoundaryValue = 0;
        int leftBoundaryValue = height[negativeArr[0] - 1];
        int rightBoundary = 0;
        int leftBoundary = negativeArr[0] - 1;
        if (negativeArr[2] == 0 && negativeArr[4] == 1) {
            //当表示为最后一个盛水容器时,判断此次容器是否能装水,当negativeArr[1]不等于0时,可能继续装水,需要derivativeArr数组在边界值以后>0的情况
            if (negativeArr[1] != 0) {
                int lastNegative = negativeArr[1];
                while (lastNegative < derivativeArr.length - 1) {
                    //找到最后一个最低谷后面的右边界值
                    if (derivativeArr[++lastNegative] > 0) {
                        if (height[lastNegative] > rightBoundaryValue) {
                            rightBoundaryValue = height[lastNegative];
                            rightBoundary = lastNegative;
                        }
                    }
                }
            }
        } else {
            //表示还有其他值
            rightBoundaryValue = height[negativeArr[1] - 1];
            rightBoundary = negativeArr[1] - 1;
        }
        //计算其值
        if (leftBoundaryValue >= rightBoundaryValue) {
            containValue += rightBoundaryValue * (rightBoundary - leftBoundary);
            for (int index = leftBoundary+1; index <= rightBoundary; index++) {
                containValue -= height[index];
            }
        } else {
            containValue += leftBoundaryValue * (rightBoundary - leftBoundary);
            for (int index = leftBoundary; index < rightBoundary; index++) {
                containValue -= height[index];
            }
        }
    }
    System.out.println("容器总值为:" + containValue);
    return containValue;
}

/**
 * @return
 * @desc 返回的数组中,数组0为左边界,
 * 数组1为右边界(为0时则表示没有找到右边界),
 * 数组2表示是否有下一个盛水容器的左边界,0即为结束
 * @author sam.ye
 * @date 2020-1-3 15:33
 */
private int[] getNegativeArr(List<Integer> negativeList, int currentValue, int[] derivativeArr) {
    int[] intArr = new int[5];
    //获得的左边界
    int leftBoundary = negativeList.get(currentValue);
    //获得右边界
    int rightBoundary = 0;
    //初始化为未找到该边界值
    Boolean findFlag = false;
    int nextNegativeValue = currentValue;
    while (nextNegativeValue < negativeList.size() && !findFlag) {
        int rightBoundaryTemp = negativeList.get(++nextNegativeValue);
        //非连续递减,寻找下一个-1的点
        if (leftBoundary != rightBoundaryTemp - 1) {
            for (int leftTemp = leftBoundary; leftTemp < rightBoundaryTemp; leftTemp++) {
                //找到右边界
                if (derivativeArr[leftTemp] > 0) {
                    rightBoundary = rightBoundaryTemp;
                    findFlag = true;
                    break;
                }
            }
            //解决边界问题,如:-1,-1,-1,0,0,1和-1,-1,-1,0,0 俩种问题情况
            if (!findFlag) {
                rightBoundary = rightBoundaryTemp;
                intArr[4]=1;
            }
        }
    }
    intArr[0] = leftBoundary;
    intArr[1] = rightBoundary;
    intArr[3] = nextNegativeValue;
    //已经到最后一个负数组
    if (nextNegativeValue == negativeList.size() - 1) {
        intArr[2] = 0;
    } else {
        intArr[2] = 1;
    }
    return intArr;
}

相关文章: