Given a string of numbers and a number of multiplication operators, what is the highest number one can calculate?

后端 未结 9 1555
醉话见心
醉话见心 2021-01-30 11:22

This was an interview question I had and I was embarrassingly pretty stumped by it. Wanted to know if anyone could think up an answer to it and provide the big O notation for it

9条回答
  •  一整个雨季
    2021-01-30 12:11

    Yet another Java implementation. This is DP top down, aka memoization. It also prints out the actual components besides the max product.

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class MaxProduct {
    
        private static Map cache = new HashMap<>();
    
        private static class Key {
            int operators;
            int offset;
    
            Key(int operators, int offset) {
                this.operators = operators;
                this.offset = offset;
            }
    
            @Override
            public int hashCode() {
                final int prime = 31;
                int result = 1;
                result = prime * result + offset;
                result = prime * result + operators;
                return result;
            }
    
            @Override
            public boolean equals(Object obj) {
                if (this == obj) {
                    return true;
                }
                if (obj == null) {
                    return false;
                }
                if (!(obj instanceof Key)) {
                    return false;
                }
                Key other = (Key) obj;
                if (offset != other.offset) {
                    return false;
                }
                if (operators != other.operators) {
                    return false;
                }
                return true;
            }
        }
    
        private static class Result {
            long product;
            int offset;
            Result prev;
    
            Result (long product, int offset) {
                this.product = product;
                this.offset = offset;
            }
    
            @Override
            public String toString() {
                return "product: " + product + ", offset: " + offset;
            }
        }
    
        private static void print(Result result, String input, int operators) {
            System.out.println(operators + " multiplications on: " + input);
            Result current = result;
            System.out.print("Max product: " + result.product + " = ");
            List insertions = new ArrayList<>();
            while (current.prev != null) {
                insertions.add(current.offset);
                current = current.prev;
            }
    
            List inputAsList = new ArrayList<>();
            for (char c : input.toCharArray()) {
                inputAsList.add(c);
            }
    
            int shiftedIndex = 0;
            for (int insertion : insertions) {
                inputAsList.add(insertion + (shiftedIndex++), '*');
            }
    
            StringBuilder sb = new StringBuilder();
            for (char c : inputAsList) {
                sb.append(c);
            }
    
            System.out.println(sb.toString());
            System.out.println("-----------");
        }
    
        public static void solve(int operators, String input) {
            cache.clear();
            Result result = maxProduct(operators, 0, input);
            print(result, input, operators);
        }
    
        private static Result maxProduct(int operators, int offset, String input) {
            String rightSubstring = input.substring(offset);
    
            if (operators == 0 && rightSubstring.length() > 0) return new Result(Long.parseLong(rightSubstring), offset);
            if (operators == 0 && rightSubstring.length() == 0) return new Result(1, input.length() - 1);
    
            long possibleSlotsForFirstOperator = rightSubstring.length() - operators;
            if (possibleSlotsForFirstOperator < 1) throw new IllegalArgumentException("too many operators");
    
            Result maxProduct = new Result(-1, -1);
            for (int slot = 1; slot <= possibleSlotsForFirstOperator; slot++) {
                long leftOperand = Long.parseLong(rightSubstring.substring(0, slot));
                Result rightOperand;
                Key key = new Key(operators - 1, offset + slot);
                if (cache.containsKey(key)) {
                    rightOperand = cache.get(key);
                } else {
                    rightOperand = maxProduct(operators - 1, offset + slot, input);
                }
    
                long newProduct = leftOperand * rightOperand.product;
                if (newProduct > maxProduct.product) {
                    maxProduct.product = newProduct;
                    maxProduct.offset = offset + slot;
                    maxProduct.prev = rightOperand;
                }
            }
    
            cache.put(new Key(operators, offset), maxProduct);
            return maxProduct;
        }
    
        public static void main(String[] args) {
            solve(5, "1826456903521651");
            solve(1, "56789");
            solve(1, "99287");
            solve(2, "99287");
            solve(2, "312");
            solve(1, "312");
        }
    
    }
    

    Bonus: a bruteforce implementation for anyone interested. Not particularly clever but it makes the traceback step straightforward.

    import java.util.ArrayList;
    import java.util.List;
    
    public class MaxProductBruteForce {
    
        private static void recurse(boolean[] state, int pointer, int items, List states) {
            if (items == 0) {
                states.add(state.clone());
                return;
            }
    
            for (int index = pointer; index < state.length; index++) {
                state[index] = true;
                recurse(state, index + 1, items - 1, states);
                state[index] = false;
            }
        }
    
        private static List bruteForceCombinations(int slots, int items) {
            List states = new ArrayList<>(); //essentially locations to insert a * operator
            recurse(new boolean[slots], 0, items, states);
            return states;
        }
    
        private static class Tuple {
            long product;
            List terms;
    
            Tuple(long product, List terms) {
                this.product = product;
                this.terms = terms;
            }
    
            @Override
            public String toString() {
                return product + " = " + terms.toString();
            }
        }
    
        private static void print(String input, int operators, Tuple result) {
            System.out.println(operators + " multiplications on: " + input);
            System.out.println(result.toString());
            System.out.println("---------------");
        }
    
        public static void solve(int operators, String input) {
            Tuple result = maxProduct(input, operators);
            print(input, operators, result);
        }
    
        public static Tuple maxProduct(String input, int operators) {
            Tuple maxProduct = new Tuple(-1, null);
    
            for (boolean[] state : bruteForceCombinations(input.length() - 1, operators)) {
                Tuple newProduct = getProduct(state, input);
                if (maxProduct.product < newProduct.product) {
                    maxProduct = newProduct;
                }
            }
    
            return maxProduct;
        }
    
        private static Tuple getProduct(boolean[] state, String input) {
            List terms = new ArrayList<>();
            List insertLocations = new ArrayList<>();
            for (int i = 0; i < state.length; i++) {
                if (state[i]) insertLocations.add(i + 1);
            }
    
            int prevInsert = 0;
            for (int insertLocation : insertLocations) {
                terms.add(Long.parseLong(input.substring(prevInsert, insertLocation))); //gradually chop off the string
                prevInsert = insertLocation;
            }
    
            terms.add(Long.parseLong(input.substring(prevInsert))); //remaining of string
    
            long product = 1;
            for (long term : terms) {
                product = product * term;
            }
    
            return new Tuple(product, terms);
        }
    
        public static void main(String[] args) {
            solve(5, "1826456903521651");
            solve(1, "56789");
            solve(1, "99287");
            solve(2, "99287");
            solve(2, "312");
            solve(1, "312");
        }
    
    }
    

提交回复
热议问题