Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Choose best combinations of operators to find target number

I have an array of operations and a target number.

The operations could be

+ 3
- 3
* 4
/ 2

I want to find out how close I can get to the target number by using those operations.

I start from 0 and I need to iterate through the operations in that order, and I can choose to either use the operation or not use it.

So if the target number is 13, I can use + 3 and * 4 to get 12 which is the closest I can get to the target number 13.

I guess I need to compute all possible combinations (I guess the number of calculations is thus 2^n where n is the number of operations).

I have tried to do this in java with

import java.util.*;

public class Instruction {
    public static void main(String[] args) {
        // create scanner
        Scanner sc = new Scanner(System.in);

        // number of instructions
        int N = sc.nextInt();

        // target number
        int K = sc.nextInt();

        //
        String[] instructions = new String[N];

        // N instructions follow
        for (int i=0; i<N; i++) {
            //
            instructions[i] = sc.nextLine();
        }

        //
        System.out.println(search(instructions, 0, N, 0, K, 0, K));
    }

    public static int search(String[] instructions, int index, int length, int progressSoFar, int targetNumber, int bestTarget, int bestDistance) {
        //
        for (int i=index; i<length; i++) {
            // get operator
            char operator = instructions[i].charAt(0);

            // get number
            int number = Integer.parseInt(instructions[i].split("\\s+")[1]);

            //
            if (operator == '+') {
                progressSoFar += number;
            } else if (operator == '*') {
                progressSoFar *= number;
            } else if (operator == '-') {
                progressSoFar -= number;
            } else if (operator == '/') {
                progressSoFar /= number;
            }

            //
            int distance = Math.abs(targetNumber - progressSoFar);

            // if the absolute distance between progress so far
            // and the target number is less than what we have
            // previously accomplished, we update best distance
            if (distance < bestDistance) {
                bestTarget = progressSoFar;
                bestDistance = distance;
            }

            //
            if (true) {
                return bestTarget;
            } else {
                return search(instructions, index + 1, length, progressSoFar, targetNumber, bestTarget, bestDistance);
            }
        }
    }
}

It doesn't work yet, but I guess I'm a little closer to solving my problem. I just don't know how to end my recursion.

But maybe I don't use recursion, but should instead just list all combinations. I just don't know how to do this.

If I, for instance, have 3 operations and I want to compute all combinations, I get the 2^3 combinations

111
110
101
011
000
001
010
100

where 1 indicates that the operation is used and 0 indicates that it is not used.

It should be rather simple to do this and then choose which combination gave the best result (the number closest to the target number), but I don't know how to do this in java.

like image 481
Jamgreen Avatar asked Apr 01 '16 13:04

Jamgreen


People also ask

Can the target number be calculated by applying +-*/operations?

Given a list of numbers and a target number, write a program to determine whether the target number can be calculated by applying "+-*/" operations to the number list? You can assume () is automatically added when necessary. An operator should be put between each two consecutive numbers. So each number has to be used.

How to find two numbers that add up to a specific number?

Given an array of integers, find two numbers such that they add up to a specific target number. The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that you returned answers (both index1 and index2) are not zero-based.

Which operator should be used between two consecutive numbers?

An operator should be put between each two consecutive numbers. So each number has to be used. For example, given {1,2,3,4} and 21, return true. Because (1+2)* (3+4)=21 This is a partition problem which can be solved by using depth first search.

What happens when target reaches 0 in an array?

If target reaches 0, we increment the count. If we have processed all elements of the array and target is not reached, count remains unchanged. Below is recursive implementation of above idea.


1 Answers

In pseudocode, you could try brute-force back-tracking, as in:

// ops: list of ops that have not yet been tried out
// target: goal result
// currentOps: list of ops used so far
// best: reference to the best result achieved so far (can be altered; use
//     an int[1], for example)
// opsForBest: list of ops used to achieve best result so far
test(ops, target, currentOps, best, opsForBest)
      if ops is now empty,
         current = evaluate(currentOps)
         if current is closer to target than best,
            best = current
            opsForBest = a copy of currentOps
      otherwise, 
         // try including next op
         with the next operator in ops,
            test(opsAfterNext, target, 
                currentOps concatenated with next, best, opsForBest)
         // try *not* including next op
         test(opsAfterNext, target, currentOps, best, opsForBest)

This is guaranteed to find the best answer. However, it will repeat many operations once and again. You can save some time by avoiding repeat calculations, which can be achieved using a cache of "how does this subexpression evaluate". When you include the cache, you enter the realm of "dynamic programming" (= reusing earlier results in later computation).


Edit: adding a more OO-ish variant

Variant returning the best result, and avoiding the use of that best[] array-of-one. Requires the use of an auxiliary class Answer with fields ops and result.

// ops: list of ops that have not yet been tried out
// target: goal result
// currentOps: list of ops used so far
Answer test(ops, target, currentOps, opsForBest)
      if ops is now empty,
         return new Answer(currentOps, evaluate(currentOps))
      otherwise, 
         // try including next op
         with the next operator in ops,
            Answer withOp = test(opsAfterNext, target, 
                currentOps concatenated with next, best, opsForBest)
         // try *not* including next op
         Answer withoutOp = test(opsAfterNext, target, 
                currentOps, best, opsForBest)
         if withOp.result closer to target than withoutOp.target,
            return withOp
         else
            return withoutOp
like image 145
tucuxi Avatar answered Sep 30 '22 07:09

tucuxi