Find a Value of a Mysterious Function Closest to Target

Winston was given the above mysterious function func. He has an integer array arr and an integer target and he wants to find the values l and r that make the value |func(arr, l, r) - target| minimum possible.

Return the minimum possible value of |func(arr, l, r) - target|.

Notice that func should be called with the values l and r where 0 <= l, r < arr.length.

Example 1:

Input: arr = [9,12,3,7,15], target = 5
Output: 2
Explanation: Calling func with all the pairs of [l,r] = [[0,0],[1,1],[2,2],[3,3],[4,4],[0,1],[1,2],[2,3],[3,4],[0,2],[1,3],[2,4],[0,3],[1,4],[0,4]], Winston got the following results [9,12,3,7,15,8,0,3,7,0,0,3,0,0,0]. The value closest to 5 is 7 and 3, thus the minimum difference is 2.

Example 2:

Input: arr = [1000000,1000000,1000000], target = 1
Output: 999999
Explanation: Winston called the func with all possible values of [l,r] and he always got 1000000, thus the min difference is 999999.

Example 3:

Input: arr = [1,2,4,8,16], target = 0
Output: 0

Constraints:

  • 1 <= arr.length <= 10^5

  • 1 <= arr[i] <= 10^6

  • 0 <= target <= 10^7

// Similar to LC:898
// O(N*32)
class Solution {
    public int closestToTarget(int[] arr, int target) {
        int ans = Integer.MAX_VALUE;
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < arr.length; i++) {
            Set<Integer> newSet = new HashSet<>();
            newSet.add(arr[i]);
            for (int x : set)
                newSet.add(x & arr[i]);
            for (int x : newSet)
                ans = Math.min(ans, Math.abs(target - x));
            set = newSet;
        }
        return ans;
    }
}

// O(N*logN*logN)
// Fixing 'leftpointer' & searching for right pointer
// also using the fact that and & operation
// always results in <= value
class Solution {
    static class SegmentTree {
        int[] tree, arr;
        int n;

        SegmentTree(int[] arr) {
            n = arr.length;
            this.arr = arr;
            tree = new int[4 * n];
            buildTree(0, n - 1, 1);
        }

        private void buildTree(int start, int end, int index) {
            if (start == end) {
                tree[index] = arr[start];
                return;
            }
            int mid = start + (end - start) / 2;
            buildTree(start, mid, 2 * index);
            buildTree(mid + 1, end, 2 * index + 1);
            tree[index] = tree[2 * index] & tree[2 * index + 1];
        }

        public int query(int l, int r) {
            return queryHelper(0, n - 1, 1, l, r);
        }

        private int queryHelper(int start, int end, int index, int L, int R) {
            if (start > R || end < L)
                return Integer.MAX_VALUE;
            else if (start >= L && end <= R)
                return tree[index];
            int mid = start + (end - start) / 2;
            return queryHelper(start, mid, 2 * index, L, R) & queryHelper(mid + 1, end, 2 * index + 1, L, R);
        }
    }

    public int closestToTarget(int[] arr, int target) {
        SegmentTree tree = new SegmentTree(arr);
        int distance = Integer.MAX_VALUE;
        for (int i = 0; i < arr.length; i++) {
            int start = i, end = arr.length - 1;
            while (start <= end) {
                int mid = start + (end - start) / 2;
                int AND = tree.query(i, mid);
                if (AND == target)
                    return 0;
                else if (AND > target)
                    start = mid + 1;
                else
                    end = mid - 1;
                distance = Math.min(distance, Math.abs(target - AND));
            }
        }
        return distance;
    }
}

Last updated