public boolean remove2(int el) {
        /*
        Search the first occurrence of the element in the array. Iterate only till size
        If element is not found return false
        Else move all the elements up by one place
            -> and decrement size by 1
         */
        int found = -1;
        for (int i = 0; i < this.size; i++) {
            if (this.arr[i] == el) {
                found = i;
                break;
            }
        }
        if (found == -1) {
            return false;
        }
        size--;
        int[] copy = new int[size];
        System.arraycopy(arr, 0, copy, 0, found);
        System.arraycopy(this.arr, found + 1, copy, found, this.size - found);
        this.arr = copy;
        return true;
    }
We have seen how dynamic arrays enable arrays to grow while still achieving constant-time amortized performance.
This problem concerns extending dynamic arrays to let them both grow and shrink on demand.
(a) Consider an underflow strategy that cuts the array size in half whenever the array falls below half full.
Give an example sequence of insertions and deletions where this strategy gives a bad amortized cost.
(b) Then, give a better underflow strategy than that suggested above, one that achieves constant amortized cost per deletion.
java8/src/main/java/com/shekhargulati/tadm/ch03/Problem3_3.java