'Minimum moves to transform a list so that each element equals its own frequency
Given a sorted array like [1,2,4,4,4]. Each element in the array should occur exactly same number of times as element. For Example 1 should occur 1 time, 2 should occur 2 times, n should occur n times, After minimum number of moves, the array will be rendered as [1,4,4,4,4]
Original                          Shifted                   Min Moves       Reason
[1,2,4,4,4]                       [1,4,4,4,4]               2               delete 2 and insert 4
[1, 1, 3, 4, 4, 4]                [1,4,4,4,4]               3               delete 1,3 an insert 4
[10, 10, 10]                      []                        3               delete all 10s
[1, 1, 1, 1, 3, 3, 4, 4, 4, 4, 4] [1, 3, 3, 3, 4, 4, 4, 4]  5               delete 1,1,1,4 and insert 3
We are allowed to delete/drop some elements totally, as explained above.
I need to find the minimum number of rotations/moves required to get the shifted version. So, I have written below logic to find the min number of moves required on original array.
public static int minMoves(int[] data) {
    Map<Integer, Integer> dataMap = new HashMap<>();
    for(int i=0; i<data.length;i++) {
        if(dataMap.containsKey(data[i])) {
            dataMap.put(data[i], dataMap.get(data[i])+1);
        }else {
            dataMap.put(data[i], 1);
        }
    }
    
    System.out.println("Map - "+dataMap);
    
    int[] minOperations = {0};      
    dataMap.forEach((digit,frequency)->{            
        if(digit!=frequency) {
            if(digit<frequency) {
                minOperations[0] += (frequency-digit);
            }else if(digit>frequency && (digit-frequency)<=minOperations[0]) {
                minOperations[0] += digit-frequency;
            }else {
                minOperations[0] += frequency;
            }   
        }                               
        System.out.println(digit+"  "+frequency+"  "+minOperations[0]);
    });     
    return minOperations[0];
}
The above logic is working fine for above stated cases. But it's failing for few cases.
Failed Case - [1, 2, 2, 2, 5, 5, 5, 8] should return 4, But it's returning 5.
I feel my solution has few problems
- Not optimistic/Less performant
- Failing on edge cases
- Not following any algorithmic approach
Please help to point out. What is the right approaches/algorithms available to solve this in more efficient manner.
More Explanation:
There is an array A of N integers sorted in non-decreasing order. In one move, you can either remove an integer from A or insert an integer before or after any element of A. The goal is to achieve an array in which all values X that are present in the array occur exactly X times.
Given A = [1, 2, 2, 2, 5, 5, 5, 8], your function should retum 4. You can delete the 8 and one occurrence of 2, and insert 5 twice, resulting in [1, 2, 2, 5, 5, 5, 5, 5] after four moves. Notice that after the removals, there is no occurrence of 8 in the array anymore.
given an array A retums the minimum number of moves after which every value X in the array occurs exactly X times. Note that it is permissible to remove some values entirely, if appropriate.
What is the minimum number of moves after which every value X in the array occurs exactly X times?
Solution 1:[1]
The error is in this comparison:
(digit-frequency)<=minOperations[0]
There is no logic in comparing with the intermediate, running sum minOperations[0]. It should compare the following two:
- How many insert operations are needed to get to the required number of digits -- this is the left side of the comparison (OK) 
- How many delete operations are needed to remove all these digits, this is - frequency
So that comparison should be:
digit - frequency <= frequency
Some other remarks:
- As you say the input is sorted, there is no need to create a Map. You can immediately count the number of digits as you iterate from left to right through the array, and at the same time update - minOperations.
- There is no need to make - minOperationsan array. It can be just a primitive.
- The number of expressions to check can be reduced a bit, by using - absand- min
Here is how you could update your code:
import java.lang.Math.*;
// ...
public static int minMoves(int[] data) {
    int minOperations = 0;
    for(int i = 0, j = 0; i < data.length; i = j) {
        while (j < data.length && data[i] == data[j]) j++;
        int frequency = j - i;
        minOperations += Math.min(Math.abs(data[i] - frequency), frequency);
    }
    return minOperations;
}
Solution 2:[2]
Try this :
public static int minMovements(Integer[] array) {
    int numberOfMoves = 0;
    List<Integer> arrayList = List.of(array);
    List<Integer> uniques = arrayList.stream().distinct().collect(Collectors.toList());
    for (Integer e : uniques) {
      int ocurrences = (int) arrayList.stream().filter(o -> o == e).count();
      numberOfMoves += Integer.min(Math.abs(e - ocurrences), ocurrences);
    }
    return numberOfMoves;
  }
Solution 3:[3]
private static void findMinMoves(int[] data) {
    Map<Integer, Integer> dataMap = new HashMap<>();
    for (int i = 0; i < data.length; i++) {
        if (dataMap.containsKey(data[i])) {
            dataMap.put(data[i], dataMap.get(data[i]) + 1);
        } else {
            dataMap.put(data[i], 1);
        }
    }
    int[] minOperations = {0};
    dataMap.forEach((digit, occurrence) -> {
        if (digit != occurrence) {
            if (digit < occurrence) {
                minOperations[0] += (occurrence - digit);
            } else if (digit > occurrence) {
                minOperations[0] += Math.min(Math.abs(occurrence - digit), occurrence);
            } else {
                minOperations[0] += occurrence;
            }
        }
    });
    System.out.println("Minimum occurrences" + minOperations[0]);
}
Time Complexity : O(n) Space complexity: O(n)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | trincot | 
| Solution 2 | Saiprashanth | 
| Solution 3 | aakash kumar | 
