简体   繁体   中英

Changing 2D ArrayList code to 2D array code

I found this code online and it works well to permute through the given array and return all possible combinations of the numbers given. Does anyone know how to change this code to incorporate a 2D array instead?

public static ArrayList<ArrayList<Integer>> permute(int[] numbers) {
    ArrayList<ArrayList<Integer>> permutations = new ArrayList<ArrayList<Integer>>();

    permutations.add(new ArrayList<Integer>());

    for ( int i = 0; i < numbers.length; i++ ) {

        ArrayList<ArrayList<Integer>> current = new ArrayList<ArrayList<Integer>>();
        for ( ArrayList<Integer> p : permutations ) {
            for ( int j = 0, n = p.size() + 1; j < n; j++ ) {
                ArrayList<Integer> temp = new ArrayList<Integer>(p);
                temp.add(j, numbers[i]);
                current.add(temp);
            }
        }
        permutations = new ArrayList<ArrayList<Integer>>(current);
    }

    return permutations;
}  

This is what I have attempted:

public static int[][] permute(int[] numbers){
    int[][] permutations = new int[24][4];
    permutations[0] = new int[4];
    for ( int i = 0; i < numbers.length; i++ ) {
        int[][] current = new int[24][4];
        for ( int[] permutation : permutations ) {
            for ( int j = 0; j < permutation.length; j++ ) {
                permutation[j] = numbers[i];
                int[] temp = new int[4];
                current[i] = temp;

            }

        }
        permutations = current;
    }
    return permutations;

}  

However this returns all zeroes. I chose 24 and 4 because that is the size of the 2D array that I need. Thanks

It's not really that easy. The original code exploits the more dynamic behaviour of ArrayList , so a bit of hand coding will be necessary. There are many correct thoughts in your code. I tried to write an explanation of the issues I saw, but it became too long, so I decided to modify your code instead.

The original temp.add(j, numbers[i]); is the hardest part to do with arrays since it invloves pushing the elements to the right of position j one position to the right. In my version I create a temp array just once in the middle loop and shuffle one element at a time in the innermost loop.

public static int[][] permute(int[] numbers) {
    // Follow the original here and create an array of just 1 array of length 0
    int[][] permutations = new int[1][0];
    for (int i = 0; i < numbers.length; i++) {
        // insert numbers[i] into each possible position in each array already in permutations.
        // create array with enough room: when before we had permutations.length arrays, we will now need:
        int[][] current = new int[(permutations[0].length + 1) * permutations.length][];
        int count = 0; // number of new permutations in current
        for (int[] permutation : permutations) {
            // insert numbers[i] into each of the permutation.length + 1 possible positions of permutation.
            // to avoid too much shuffling, create a temp array
            // and use it for all new permutations made from permutation.
            int[] temp = Arrays.copyOf(permutation, permutation.length + 1);
            for (int j = permutation.length; j > 0; j--) {
                temp[j] = numbers[i];
                // remember to make a copy of the temp array
                current[count] = temp.clone();
                count++;
                // move element to make room for numbers[i] at next position to the left
                temp[j] = temp[j - 1];
            }
            temp[0] = numbers[i];
            current[count] = temp.clone();
            count++;
        }
        assert count == current.length : "" + count + " != " + current.length;
        permutations = current;
    }
    return permutations;
}

My trick with the temp array means I don't get the permutations in the same order as in the origianl code. If this is a requirement, you may copy permutation into temp starting at index 1 and shuffle the opposite way in the loop. System.arraycopy() may do the initial copying.

The problem here is that you really need to implement properly the array version of the ArrayList.add(int,value) command. Which is to say you do an System.arraycopy() and push all the values after j, down one and then insert the value at j. You currently set the value. But, that overwrites the value of permutation[j], which should actually have been moved to permutations[j+1] already.

So where you do:

permutation[j] = numbers[i];    

It should be:

System.arraycopy(permutation,j, permutations, j+1, permutations.length -j);
permutation[j] = numbers[i];

As the ArrayList.add(int,value) does that. You basically wrongly implemented it as .set().

Though personally I would scrap the code and go with something to dynamically make those values on the fly. A few more values and you're talking something prohibitive with regard to memory. It isn't hard to find the nth index of a permutation. Even without allocating any memory at all. (though you need a copy of the array if you're going to fiddle with such things without incurring oddities).

public static int[] permute(int[] values, long index) {
    int[] returnvalues = Arrays.copyOf(values,values.length);
    if (permutation(returnvalues, index)) return returnvalues;
    else return null;

}
public static boolean permutation(int[] values, long index) {
    return permutation(values, values.length, index);
}

private static boolean permutation(int[] values, int n, long index) {
    if ((index == 0) || (n == 0))  return (index == 0);
    int v = n-(int)(index % n);
    int temp = values[n];
    values[n] = values[v];
    values[v] = temp;
    return permutation(values,n-1,index/n);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM