• leetcode282


    Given a string that contains only digits 0-9 and a target value, return all possibilities to add binary operators (not unary) +, -, or *between the digits so they evaluate to the target value.
    Example 1:
    Input: num = "123", target = 6
    Output: ["1+2+3", "1*2*3"]
    Example 2:
    Input: num = "232", target = 8
    Output: ["2*3+2", "2+3*2"]
    Example 3:
    Input: num = "105", target = 5
    Output: ["1*0+5","10-5"]
    Example 4:
    Input: num = "00", target = 0
    Output: ["0+0", "0-0", "0*0"]
    Example 5:
    Input: num = "3456237490", target = 9191
    Output: []

    DFS。
    函数头:private void dfs(int offset, long cal, long lastFact, String crt, List<String> ans)
    递归定义:在中间的general状态下,offset这个index以前的数字被加减乘分割的方式已经定好了放在crt里,这种方式算出来的到目前的答案也定好了放在cal里,你接下来随便试offset和后面的数字分割的方式,等有一天试成功了你放到ans里。对了同时传一个额外信息lastFact,表示到目前为止最后一个被+-的因数,给你用来辅助现在尝试*用。
    递归拆分:这题能产生不同组合无非依赖于1.长数字怎么被分割为好几个小数字,2.分割点插的什么二元操作符。一次dfs内:首先for循环看substring要从offset开始停到哪里来取数字产生下一个因数。有了这个因数后看看如果拿前面的结果+-*这个新因数后,会怎么更新cal和lastFact,从而进一步递归。
    递归出口:当offset指不到新数字后你必须走了。如果该退场的时候发现诶我正好算出来的答案合格了,那把你现在找到的组合方式crt存进ans里。

    细节:
    1.本题难点在于解决插入乘法符号*时怎么快速更新计算结果。比如输入为1234。在某一状态,前面已经拼成了12+3,我们当前cal记下15,现在需要我们拼上新数字4。要是填+,更新结果很容易就加上去就好;如果要填*,从12+3变成12+3*4,我们不能只依靠上一个cal信息为15来快速得到答案,因为现在3不是先和12组合了而是先和4。如果记录了上一个因子lastFact的话事情就简单很多。先把lastFact从cal中减去得到上上次的答案12,再让lastFact先和当前数字乘了得到3*4,再加回上上次的结果去。所以乘法时,cal更新为cal - lastFact + lastFact * crtFact,lastFact更新为lastFact * crtFact。
    2.中间答案和因数都用Long存储不要用int。因为很可能你两个数一乘就超int了,但有时候减一减又可以拿到最后int的target,不能在中途把它们牺牲掉。
    3.注意0的corner case。0不可以和其他数组成共同的因子。如果是01234开始继续分解,第一个0只可以自己独立做因子,不可以和后面的拉帮结派组成01,012什么的。所以直接用parseLong还有缺陷,比如你不额外处理的话,000 凑0, parseLong看到00也读成0,就会给你产生00+0的不合理结果。
    4.所有数,甚至第一个数,都可以直接霸占到最后。比如12345,不是说一定要加符号进去从而第一个数最多到1234这样,如果num = “12345” target = 12345,它自身就成立了,不需要加符号。
    5.注意递归出口时的必须走了的“必须”。就是说你就算试出来的答案是错的也要走,不可以继续跑下面的代码。本题凑巧下面代码只有for循环,而且这个for循环在offset跑到最后的时候不会进去,所以不在前面写return也没关系。但写其他dfs的时候还是要小心,尽量check一下最前面出口那里要不要先写return以避免编译错误。

    实现:

    class Solution {
            private String num;
            private long target;
            private List<String> ans;
    
            public List<String> addOperators(String num, int target) {
                this.num = num;
                this.target = target;
                this.ans = new ArrayList<>();
                dfs(0, 0, 0, "");
                return ans;
            }
    
            private void dfs(int offset, long cal, long lastFact, String crt) {
    
                if (offset == num.length() && cal == target) {
                    ans.add(crt);
                }
                
                // P2: 数可以直接霸占到最后,甚至第一个数。比如12345,不是说一定要加符号进去从而第一个数最多到1234这样,如果target也是12345它自身就成立了。
                for (int i = offset; i < num.length(); i++) {
                    long fact = Long.parseLong(num.substring(offset, i + 1));
                    if (offset == 0) {
                        dfs(i + 1, cal + fact, fact, crt + num.substring(offset, i + 1));
                    } else {
                        dfs(i + 1, cal + fact, fact, crt + "+" + fact);
                        dfs(i + 1, cal - fact, -fact, crt + "-" + fact);
                        dfs(i + 1, cal - lastFact + lastFact * fact, lastFact * fact, crt + "*" + fact);    
                    }
                    // P1: 如果是01234开始继续分解,第一个0只可以自己独立做因子,不可以和后面的拉帮结派组成01,012什么的。所有直接用parseLong还有缺陷。
                    if (fact == 0) {
                        break;
                    }
                }
            }
        }

    九章实现:

    /**
    * 本参考程序来自九章算法,由 @老顽童 提供。版权所有,转发请注明出处。
    * - 九章算法致力于帮助更多中国人找到好的工作,教师团队均来自硅谷和国内的一线大公司在职工程师。
    * - 现有的面试培训课程包括:九章算法班,系统设计班,算法强化班,Java入门与基础算法班,Android 项目实战班,
    * - Big Data 项目实战班,算法面试高频题班, 动态规划专题班
    * - 更多详情请见官方网站:http://www.jiuzhang.com/?source=code
    */ 
    
    public class Solution {
        /**
         * @param num    a string contains only digits 0-9
         * @param target an integer
         * @return return all possibilities
         */
        
        void dfs(String num, int target, int start, String str, long sum, long lastF, List<String> ans) {
            if (start == num.length()) {
                if (sum == target) {
                    ans.add(str);
                }
                return;
            }
            for (int i = start; i < num.length(); i++) {
                long x = Long.parseLong(num.substring(start, i + 1));
    
                if (start == 0) {
                    dfs(num, target, i + 1, "" + x, x, x, ans);
                } else {
                    dfs(num, target, i + 1, str + "*" + x, sum - lastF + lastF * x, lastF * x, ans);
                    dfs(num, target, i + 1, str + "+" + x, sum + x, x, ans);
                    dfs(num, target, i + 1, str + "-" + x, sum - x, -x, ans);
                }
                if (x == 0) {
                    break;
                }
            }
        }
    
        public List<String> addOperators(String num, int target) {
            // Write your code here
            List<String> ans = new ArrayList<>();
            dfs(num, target, 0, "", 0, 0, ans);
            return ans;
        }
    }
  • 相关阅读:
    bash 教程 shell 基础语法
    使用 Flutter 开发 Windows 桌面应用 [MD]
    小tips:使用babelupgrade从babel6升级babel7
    JS的可选链操作符(?.)与双问号(??),你用到了吗?
    JS处理html的编码(encode)与解码(decode)
    pdf A3 到 A4
    grub4dos 制作U盘启动盘
    amixer的用法
    一个tomcat设置多个端口
    PostgreSQL 配置内存参数
  • 原文地址:https://www.cnblogs.com/jasminemzy/p/9645831.html
Copyright © 2020-2023  润新知