力扣 306. 累加数

题目来源:https://leetcode-cn.com/problems/additive-number/

大致题意:
给一个由数字组成的字符串,将其分为大于等于 3 个的子串,从第三个开始,每个子串都等于其前两个子串转化为整数的和。如果子串长度大于 1,那么不能以 0 开头
如果字符串可以满足上述条件,那么返回 true,否则返回 false

思路

枚举前两个子串的所有可能性

根据每次枚举的前两个子串,算出第三个子串,然后判断是否与实际上的第三个子串相等,若相等,可以根据第三个子串是否为字符串末尾来进行下一步操作:若是末尾,那么表示满足条件,返回 true;否则,将第二个子串和第三个子串相加,重复这个操作

枚举

具体枚举时,不用将两个子串都枚举,只需要枚举第二个子串即可:

  • 若第二个子串开始位置为 secondStart,结束位置为 secondEnd
  • 那么第一个子串开始位置默认为 0,结束位置为 secondStart - 1

代码

public class IsAdditiveNumber {
    public boolean isAdditiveNumber(String num) {
        int n = num.length();
        if (n < 3) {
            return false;
        }
        // 枚举第二个子串的起始位置
        for (int secondStart = 1; secondStart < n - 1; secondStart++) {
            // 如果第一个子串以 0 开头,那么当其长度不能大于 1
            if (num.charAt(0) == '0' && secondStart != 1) {
                continue;
            }
            for (int secondEnd = secondStart; secondEnd < n - 1; secondEnd++) {
                // 如果第二个子串以 0 开头,那么当其长度不能大于 1
                if (num.charAt(secondStart) == '0' && secondEnd != secondStart) {
                    continue;
                }
                // 本轮枚举符合条件,直接返回结果
                if (checkValid(secondStart, secondEnd, num)) {
                    return true;
                }
            }
        }
        return false;
    }

    // 检查本轮枚举是否可以让字符串符合条件
    public boolean checkValid(int secondStart, int secondEnd, String num) {
        // 获取第一个子串的起始位置
        int firstStart = 0;
        int firstEnd = secondStart - 1;
        int n = num.length();
        while (secondEnd < n - 1) {
            // 计算出下一个子串
            String third = stringAdd(firstStart, firstEnd, secondStart, secondEnd, num);
            // 计算出下一个子串的起始位置
            int thirdStart = secondEnd + 1;
            int thirdEnd = secondEnd + third.length();
            // 如果结束位置大于字符串长度,或者算出的子串和实际不匹配,表示本轮枚举不符合条件
            if (thirdEnd >= n || !third.equals(num.substring(thirdStart, thirdEnd + 1))) {
                return false;
            }
            // 如果结束位置为字符串末尾,那么表示计算完毕,本轮枚举符合条件
            if (thirdEnd == n - 1) {
                return true;
            }
            // 字符串还有剩余,需要继续计算剩余位置是否符合条件
            // 更新要求和的两个子串
            firstStart = secondStart;
            firstEnd = secondEnd;
            secondStart = thirdStart;
            secondEnd = thirdEnd;
        }
        return false;
    }

    // 字符串加法

    /**
     *
     * @param firstStart    第一个子串开头位置
     * @param firstEnd      第一个子串结尾位置
     * @param secondStart   第二个子串开头位置
     * @param secondEnd     第二个子串结尾位置
     * @param num           原字符串
     * @return              两个子串的和
     */
    public String stringAdd(int firstStart, int firstEnd, int secondStart, int secondEnd, String num) {
        StringBuffer sum = new StringBuffer();
        // 进位
        int carry = 0;
        // 从低位到高位开始计算
        // 当还有一个子串未遍历完,或者还有进位时,需要继续运算
        while (firstEnd >= firstStart || secondEnd >= secondStart || carry != 0) {
            int cur = carry;
            // 第一个子串未遍历完
            if (firstEnd >= firstStart) {
                cur += num.charAt(firstEnd--) - '0';
            }
            // 第二子串未遍历完
            if (secondEnd >= secondStart) {
                cur += num.charAt(secondEnd--) - '0';
            }
            // 更新进位
            carry = cur / 10;
            // 取出当前位结果
            sum.append(cur % 10);
        }
        // 因为是从低位到高位算的,需要取反
        sum.reverse();
        return sum.toString();
    }
}
上一篇:Photoshop教程:极坐标滤镜的简单应用


下一篇:1.大数据概述