LeetCode:累加数【306】 LeetCode:累加数【306】

题目描述

累加数是一个字符串,组成它的数字可以形成累加序列。

一个有效的累加序列必须至少包含 3 个数。除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和。

给定一个只包含数字 '0'-'9' 的字符串,编写一个算法来判断给定输入是否是累加数。

说明: 累加序列里的数不会以 0 开头,所以不会出现 1, 2, 03 或者 1, 02, 3 的情况。

示例 1:

输入: "112358"
输出: true 
解释: 累加序列为: 1, 1, 2, 3, 5, 8 。1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8

示例 2:

输入: "199100199"
输出: true 
解释: 累加序列为: 1, 99, 100, 199。1 + 99 = 100, 99 + 100 = 199

进阶:
你如何处理一个溢出的过大的整数输入?

题目分析

   累加数是一个由一组数字拼合成的字符串,除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和

   采用的方式还是递归回溯框架。这道题涉及的一个重要问题是怎么把数字从字符串中划分出来,再没有更好的方法前,我们只能把所有的可能性提取出来。

    public void DFS(List<List<Integer>> ans,String str,List<Integer> list,int start)
    {
        //递归结束条件
        if(list.size()==3)
        {
            ans.add(new ArrayList<>(list));
            return;
        }
     //业务逻辑处理
        for(int i=start;i<str.length();i++)
        {
            String part  = str.substring(start,i+1);
            list.add(Integer.valueOf(part));
            DFS(ans,str,list,i+1);
            list.remove(list.size()-1);
        }
    }

  但是这里我们改变一下,因为我们并不需要保存所有的结果,我们要验证是否存在从第三个数字开始的数字是前否是两个数字的和,所以前两个数字我们是要需要考虑所有的情况的,但是接下来的数字我们要看是否是前两个数字的和,即前两个数字的所有可能性的和中是否存在于接下来的字符串里面。所以当我们list的尺寸是大于2开始要进行分支判断。

public boolean DFS(String str,List<Integer> list,int start)
    {
        //递归结束条件
        if(start==str.length())
        {
            //如果小于三的话,说明无法找到第三个数是前两个数的和,这样的返回是false。
            return list.size()>2;
        }
        //找到第一个数的情况下,找第二个数
        if(list.size()<2)
        {
            for(int i=start;i<str.length();i++)
            {
                String part  = str.substring(start,i+1);
                list.add(Integer.valueOf(part));
                if(DFS(str,list,i+1))
                    return true;
                list.remove(list.size()-1);
            }
        }
        //从第三个数开始要判断是否是前两个数字的和
        else{
            Integer nextVal = list.get(list.size()-1)+list.get(list.size()-2);
            String next = String.valueOf(nextVal);
            if(str.substring(start).startsWith(next))
            {
                list.add(nextVal);
                if(DFS(str,list,start+next.length()))
                    return true;
                list.remove(list.size()-1);
            }
        }
        return false;
    }
}

  这样只有在所有路径都跑完了以后无论可走的情况下,最后才会返回false,只要有一个条路径走通就会返回true。但是最后通过了自定义样例,还是无法AC,原因在于我们没有考虑处理大数的问题,所以这里的Integer要换成BigInteger

Java题解

public boolean isAdditiveNumber(String num) {
        return helper(num, new ArrayList<BigInteger>());
    }

    public boolean helper(String remain, List<BigInteger> cur){
        if(remain.length()==0)
            return cur.size()>=3;
        if(cur.size()<2)
        {
            for(int i=0;i<remain.length();i++)
            {
                String part =remain.substring(0,i+1);
                if(part.length()>1&&part.startsWith("0"))
                    continue;
                cur.add(new BigInteger(part));
                if(helper(remain.substring(i+1),cur))
                    return true;
                cur.remove(cur.size()-1);
            }
        }else {
            BigInteger nextVal  = cur.get(cur.size()-1).add(cur.get(cur.size()-2));
            String next  = String.valueOf(nextVal);
            if(remain.startsWith(next))
            {
                cur.add(nextVal);
                if(helper(remain.substring(next.length()),cur))
                    return true;
                cur.remove(cur.size()-1);
            }
        }
        return false;
    }