ArrayList randomize with index change for all elements - java

How can I randomize arrayList
so that old index must not be the same as new index for all elements
for example
with a list with 3 items
after arrayList randomize
old index<->new index
1<-->2 <--different
2<-->1 <--different
3<-->3 <--same is not allowed
I want to make sure it will be
1<-->3 <--different
2<-->1 <--different
3<-->2 <--different

Collections.shuffle(List<?> list)
This should work with Lists which don't contain null values:
static <T> void shuffleList(List<T> list) {
List<T> temp = new ArrayList<T>(list);
Random rand = new Random();
for (int i = 0; i < list.size(); i++) {
int newPos = rand.nextInt(list.size());
while (newPos == i||temp.get(newPos)==null) {
newPos = rand.nextInt(list.size());
}
list.set(i, temp.get(newPos));
temp.set(newPos,null);
}
}
For list with null values:
static <T> void shuffleList(List<T> list) {
List<T> temp = new ArrayList<T>(list);
Integer [] indexes=new Integer[list.size()];
for (int i=0;i<list.size();i++){
indexes[i]=i;
}
Random rand = new Random();
for (int i = 0; i < list.size(); i++) {
int newPos = rand.nextInt(list.size());
while (newPos == i||indexes[newPos]==null) {
newPos = rand.nextInt(list.size());
}
list.set(i, temp.get(newPos));
indexes[newPos]=null;
}
}

That's something you have to implement yourself.
The shuffle is probably a series of random swaps (e.g. swap 1 -> 4,
swap 3 -> 2).
Keep track of each element's new position (e.g. 4 3 2
1 5 for a list with 5 elements and the above shuffle operations).
If any element is still at it's old place (5 in that example),
keep on shuffling.
Sounds like fun.

var numExist = [];
while(numExist.length!=array.length){
var randomizer = new Random();
int i =0;
var num = randomizer.nextInt(array.length);
if(!numExist.contains(num)){
array[i]=array[num];
numExist.add(num);
i++;
}
}

The following is a variation of Fisher-Yates which caters to the possibility that at least one item will remain in its original position.
The current Collections.shuffle() does not perform a complete randomization of the list.
public static void shuffle(List<Integer> list) {
Random r = new Random();
int size = list.size();
boolean flag = true;
for (int i = size - 1; i >= 0 && flag; i--) {
int pos = r.nextInt(i + 1);
if (list.get(i) == pos) {
if (i == 0) {
flag = false;
break;
}
// counter the upcoming decrement by incrementing i
i++;
continue;
}
int temp = list.get(i);
list.set(i, list.get(pos));
list.set(pos, temp);
}
// At this juncture, list.get(0) points to itself so choose a random candidate
// and swap them.
if (!flag) {
int pos = r.nextInt(size - 1) + 1;
int temp = list.get(0);
list.set(0, list.get(pos));
list.set(pos, list.get(0));
}
}
There may still be eventual problems but I used the following code to test the
shuffle with no problems detected.
for (int k = 0; k < 100000; k++) {
List<Integer> list =
IntStream.range(0, 52).boxed().collect(Collectors.toList());
System.out.println("Test run #" + k);
// Collections.shuffle(list);
shuffle(list);
for (int i = 0; i < list.size(); i++) {
if (i == list.get(i)) {
System.out.printf("Oops! List.get(%d) == %d%n", list.get(i), i);
}
}
}

Related

Maximum items to retain after removing k items from array

I have an array of numbers, I want to delete k items such that they are next to each other such that the number of distinct elements in the array after deletion is maximum.
Example:
Input:
arr = [2,3,1,1,2]
k = 2
Ans: 3
Explanation:
Remove elements at index 3 & 4 which are 1 and 2 in array. Then array becomes [2,3,1] so it has 3 different elements.
This is my code:
int delete(int[] arr, int k) {
int n = arr.length;
int max = -1;
for (int i = 0; i < n - k + 1; i++) {
Set<Integer> set = new HashSet<>();
for (int j = 0; j < n; j++) {
if (i == j) {
j = j + k - 1;
} else {
set.add(arr[j]);
}
}
max = Math.max(set.size(), max);
}
return max;
}
How to reduce the time complexity for this problem. Because the size of array can be upto 1000000 and also the size of k is upto the array size. Each arraycelement can be upto 1000000
Here's a solution in O(N): It uses a map containing the number of occurrences of each number:
You start by filling the map with the elements from k to n-1 (in other words, the array without the first k elements), then you iterate and the first element and remove the last.
static int delete2(int[] arr, int k) {
int n = arr.length;
Map<Integer,Integer> map = new HashMap<>();
for (int i = k; i < n; i++) {
Integer value = arr[i];
if (!map.containsKey(value)) {
map.put(value, 1);
} else {
map.put(value, map.get(value)+1);
}
}
int max = map.size();
for (int i = 0; i < n-k; ++i) {
Integer value = arr[i];
if (!map.containsKey(value)) {
map.put(value, 1);
} else {
map.put(value, map.get(value)+1);
}
value = arr[i+k];
Integer count = map.get(value);
if (count == 1) {
map.remove(value);
} else {
map.put(value, count-1);
}
max = Math.max(map.size(), max);
}
return max;
}
If I understand correctly, you want to delete k adjacent elements such that the resulting set of set of arr - k elements is as large as possible.
Just test each candidate set (there are n sets to try).
So something like this should work
int delete(int[] arr, int k) {
int n = arr.length;
int max = -1;
Set<Integer> rem = new HashSet<>();
for (int i= 0; i<n; i++) {
rem.add(arr[i]);
}
for (int i = 0; i < n - k + 1; i++) {
Set<Integer> candidate = new HashSet<>();
for (int j = i; j < i + k; j++) {
candidate.add(arr[j]);
}
rem.removeAll(candidate);
if (rem.size() > max){
max = rem.size();
} else {
candidate.forEach((e) -> {
rem.add(e);
});
}
}
// you could also return the actual candidate set that produces the maximum
return max;
}
The set operation in the loop are all order k. So resulting time is order n*k.
int delete(int[] arr, int k) {
// step 1: traverse the array exactly once and make a hashtable
// with counts of each unique element
Map<Integer, Integer> elemCounts = new HashMap<>();
for (int e : arr) {
int ct = elemCounts.getOrDefault(e, 0);
elemCounts.put(e, ct + 1);
}
// step 2: traverse through the array exactly once more, and
// keep track of the adjacent elements which produce the least
// disturbance.
// step 2a: for the first k elements, see what removing them would
// do to the overall uniqueness of the array
int numPermanentRemovals = 0;
for (int i = 0; i < k; i++) {
int ct = elemCounts.get(arr[i]);
elemCounts.put(arr[i], ct - 1);
if (ct - 1 == 0) {
numPermanentRemovals += 1;
}
}
// step 2b: for the remainder of the array, track the rolling
// numPermanentRemovals for k adjacent elements
int minDisruption = numPermanentRemovals;
int minDisruptionIndex = 0;
for (int i = k; i < arr.length; i++) {
// put back the element at the start of the current window
int stct = elemCounts.get(arr[i - k]);
elemCounts.put(arr[i - k], stct + 1);
if (stct == 0) {
numPermanentRemovals -= 1;
}
// take out the element being added to the new window
int edct = elemCounts.get(arr[i]);
elemCounts.put(arr[i], edct - 1);
if (edct - 1 == 0) {
numPermanentRemovals += 1;
}
// if this minimum disruption index is a new floor, then
// replace the original
if (numPermanentRemovals < minDisruption) {
minDisruption = numPermanentRemovals;
minDisruptionIndex = i - k + 1;
}
// short-circuit if we find a perfect solution
if (minDisruption == 0) {
break;
}
}
return minDisruptionIndex;
}

Splitting an array at multiple points using an index point

I have come across many examples to split the given array or array list into two arrays or multiple arrays using an index point. I tried them and they are working perfectly. My question is, is it possible to split the array into multiple arrays of varying chunk size given the index point?
For example:
array[] = {10,1,2,3,10,4,5,10,6,7,10,8,10};
index_value = 10;
Then the output should be four arrays such as:
arr1[] = {1,2,3}
arr2[] = {4,5}
arr3[] = {6,7}
arr4[] = {8}
I was able to split them and display the results when the given array is static with no changes. But implementing the same for an array with random numbers and random size was hard. I need to store the split values in many sub arrays and not just printing the values.
For this solution, the index_value does not have to be at the start or end of the array:
int[] arr = new int[]{10,10,1,10,1,2,3,10,4,5,10,6,7,10,8,10,9,8,7,6,5,4,3,10,1,2,3,4,5,6,7,10,5,4,10,10};
int index_value = 10;
/** walk through the array and create the arraylist of arraylists */
ArrayList<ArrayList<Integer>> al = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> currAl = null;
for (int i=0; i < arr.length; i++) {
if (arr[i] == index_value) {
if (currAl != null && currAl.size() > 0)
al.add(currAl);
currAl = new ArrayList<Integer>();
} else {
if (currAl == null)
currAl = new ArrayList<Integer>();
currAl.add(arr[i]);
}
}
if (arr[arr.length-1]!= index_value && currAl.size() > 0) {
al.add(currAl);
}
/** print out the arraylist of arraylists */
for (int i=0; i < al.size(); i++) {
currAl = al.get(i);
for (int j=0; j < currAl.size(); j++) {
System.out.print(currAl.get(j) + " ");
}
System.out.println();
}
You can build your arrays by using the ArrayList class to fill in your values
array[] = {10,1,2,3,10,4,5,10,6,7,10,8,10};
index_value = 10;
ArrayList<ArrayList<int>> allLists = new ArrayList<ArrayList<int>>();
ArrayList<int> currentList;
for (int i = 0;i < array.length;i++)
{
//in case your array doesn't contain the index_value at index 0
//check for the null case
if (array[i] == index_value || currentList == null)
{
currentList = new ArrayList<int>();
allLists.add(currentList);
}
else
{
currentList.add(array[i]);
}
}
if (allLists.size() > 0 && allLists.get(allLists.size() - 1).size() == 0)
{
allLists.remove(allLists.size() - 1);
}
What you should have is an ArrayList that contains ArrayLists that contain the numbers you are interested in. If the index_value is repeated twice in a row, however, you will end up with empty lists (which can be removed later). This includes the final list, which I automatically remove if it is empty (since your example lists the index_value as being at both the start and the end.
If you would like the output to be in arrays, you can just call .toArray() on the ArrayList
You might try the following strategy: look for your marker boundaries, form an array from each segment as encountered, and put result in a Vector (for example).
package com.splitter;
import java.util.Vector;
public class Splitter {
/**
* #param args
*/
public static void main(String[] args) {
int[] array = {10, 1,2,3,10,4,5,10,6,7,10,8,10};
Vector <int[]> result;
result = split(array,10);
for (int i = 0; i < result.size(); i++) {
int[] split = result.get(i);
System.out.println("Array " + i);
for (int j=0; j<split.length; j++) {
System.out.println(split[j]);
}
}
}
private static Vector<int[]> split(int[] array, int value) {
Vector<int[]> result = new Vector<int[]>();
int loc = 0;
int start = 0;
boolean isInside = false;
while (loc < array.length) {
if (array[loc] == value) {
if (isInside) { // make array from start to here
// make an array from start+1 to loc-1
System.out.println(" .." + start + " " + loc + " v=" + array[loc] );
int[] split = new int[loc - start - 1];
for (int i = 0; i < split.length; i++) {
split[i] = array[start+1+i];
}
result.add(split);
isInside = true;
}
start = loc;
isInside = true;
}
loc++;
}
return result;
}
}
I tried in NetBeans, debug, and works well.
The values will be stored like in a ArrayList with more ArrayLists inside, like this:
arrayOfIntList.get(0) = > 1,2,3
arrayOfIntList.get(0).get(0) -> 1
arrayOfIntList.get(0).get(1) -> 2
arrayOfIntList.get(0).get(2) -> 3
arrayOfIntList.get(1) = > 4,5
arrayOfIntList.get(1).get(0) -> 4
arrayOfIntList.get(1).get(1) -> 5
arrayOfIntList.get(2) = > 6,7
arrayOfIntList.get(2).get(0) -> 6
arrayOfIntList.get(2).get(1) -> 7
arrayOfIntList.get(3) = > 8
arrayOfIntList.get(3).get(0) -> 8
import java.util.ArrayList;
public class Javaprueba {
public static void main(String[] args) {
int[] myarray = {10,1,2,3,10,4,5,10,6,7,10,8,10};
int splitterInt = 10;
int j = 0;
int k = 0;
ArrayList<Integer> tempArray = new ArrayList<Integer>();
ArrayList<ArrayList<Integer>> arrayOfIntList = new ArrayList<ArrayList<Integer>>();
for(int i=0; i<myarray.length; i++){
if(myarray[i] != splitterInt){
tempArray.add(j, myarray[i]);
j++;
}else{
if(tempArray.size() > 0){
arrayOfIntList.add(k, tempArray);
k++;
tempArray = new ArrayList<Integer>();
j=0;
}
}
if(i == myarray.length-1 && tempArray.size()>0){
arrayOfIntList.add(k, tempArray);
}
}
}
}

Finding multiple modes in an array of integers with 1000 elements

So I need a way to find the mode(s) in an array of 1000 elements, with each element generated randomly using math.Random() from 0-300.
int[] nums = new int[1000];
for(int counter = 0; counter < nums.length; counter++)
nums[counter] = (int)(Math.random()*300);
int maxKey = 0;
int maxCounts = 0;
sortData(array);
int[] counts = new int[301];
for (int i = 0; i < array.length; i++)
{
counts[array[i]]++;
if (maxCounts < counts[array[i]])
{
maxCounts = counts[array[i]];
maxKey = array[i];
}
}
This is my current method, and it gives me the most occurring number, but if it turns out that something else occurred the same amount of times, it only outputs one number and ignore the rest.
WE ARE NOT ALLOWED TO USE ARRAYLIST or HASHMAP (teacher forbade it)
Please help me on how I can modify this code to generate an output of array that contains all the modes in the random array.
Thank you guys!
EDIT:
Thanks to you guys, I got it:
private static String calcMode(int[] array)
{
int[] counts = new int[array.length];
for (int i = 0; i < array.length; i++) {
counts[array[i]]++;
}
int max = counts[0];
for (int counter = 1; counter < counts.length; counter++) {
if (counts[counter] > max) {
max = counts[counter];
}
}
int[] modes = new int[array.length];
int j = 0;
for (int i = 0; i < counts.length; i++) {
if (counts[i] == max)
modes[j++] = array[i];
}
toString(modes);
return "";
}
public static void toString(int[] array)
{
System.out.print("{");
for(int element: array)
{
if(element > 0)
System.out.print(element + " ");
}
System.out.print("}");
}
Look at this, not full tested. But I think it implements what #ajb said:
private static int[] computeModes(int[] array)
{
int[] counts = new int[array.length];
for (int i = 0; i < array.length; i++) {
counts[array[i]]++;
}
int max = counts[0];
for (int counter = 1; counter < counts.length; counter++) {
if (counts[counter] > max) {
max = counts[counter];
}
}
int[] modes = new int[array.length];
int j = 0;
for (int i = 0; i < counts.length; i++) {
if (counts[i] == max)
modes[j++] = array[i];
}
return modes;
}
This will return an array int[] with the modes. It will contain a lot of 0s, because the result array (modes[]) has to be initialized with the same length of the array passed. Since it is possible that every element appears just one time.
When calling it at the main method:
public static void main(String args[])
{
int[] nums = new int[300];
for (int counter = 0; counter < nums.length; counter++)
nums[counter] = (int) (Math.random() * 300);
int[] modes = computeModes(nums);
for (int i : modes)
if (i != 0) // Discard 0's
System.out.println(i);
}
Your first approach is promising, you can expand it as follows:
for (int i = 0; i < array.length; i++)
{
counts[array[i]]++;
if (maxCounts < counts[array[i]])
{
maxCounts = counts[array[i]];
maxKey = array[i];
}
}
// Now counts holds the number of occurrences of any number x in counts[x]
// We want to find all modes: all x such that counts[x] == maxCounts
// First, we have to determine how many modes there are
int nModes = 0;
for (int i = 0; i < counts.length; i++)
{
// increase nModes if counts[i] == maxCounts
}
// Now we can create an array that has an entry for every mode:
int[] result = new int[nModes];
// And then fill it with all modes, e.g:
int modeCounter = 0;
for (int i = 0; i < counts.length; i++)
{
// if this is a mode, set result[modeCounter] = i and increase modeCounter
}
return result;
THIS USES AN ARRAYLIST but I thought I should answer this question anyways so that maybe you can use my thought process and remove the ArrayList usage yourself. That, and this could help another viewer.
Here's something that I came up with. I don't really have an explanation for it, but I might as well share my progress:
Method to take in an int array, and return that array with no duplicates ints:
public static int[] noDups(int[] myArray)
{
// create an Integer list for adding the unique numbers to
List<Integer> list = new ArrayList<Integer>();
list.add(myArray[0]); // first number in array will always be first
// number in list (loop starts at second number)
for (int i = 1; i < myArray.length; i++)
{
// if number in array after current number in array is different
if (myArray[i] != myArray[i - 1])
list.add(myArray[i]); // add it to the list
}
int[] returnArr = new int[list.size()]; // create the final return array
int count = 0;
for (int x : list) // for every Integer in the list of unique numbers
{
returnArr[count] = list.get(count); // add the list value to the array
count++; // move to the next element in the list and array
}
return returnArr; // return the ordered, unique array
}
Method to find the mode:
public static String findMode(int[] intSet)
{
Arrays.sort(intSet); // needs to be sorted
int[] noDupSet = noDups(intSet);
int[] modePositions = new int[noDupSet.length];
String modes = "modes: no modes."; boolean isMode = false;
int pos = 0;
for (int i = 0; i < intSet.length-1; i++)
{
if (intSet[i] != intSet[i + 1]) {
modePositions[pos]++;
pos++;
}
else {
modePositions[pos]++;
}
}
modePositions[pos]++;
for (int modeNum = 0; modeNum < modePositions.length; modeNum++)
{
if (modePositions[modeNum] > 1 && modePositions[modeNum] != intSet.length)
isMode = true;
}
List<Integer> MODES = new ArrayList<Integer>();
int maxModePos = 0;
if (isMode) {
for (int i = 0; i< modePositions.length;i++)
{
if (modePositions[maxModePos] < modePositions[i]) {
maxModePos = i;
}
}
MODES.add(maxModePos);
for (int i = 0; i < modePositions.length;i++)
{
if (modePositions[i] == modePositions[maxModePos] && i != maxModePos)
MODES.add(i);
}
// THIS LIMITS THERE TO BE ONLY TWO MODES
// TAKE THIS IF STATEMENT OUT IF YOU WANT MORE
if (MODES.size() > 2) {
modes = "modes: no modes.";
}
else {
modes = "mode(s): ";
for (int m : MODES)
{
modes += noDupSet[m] + ", ";
}
}
}
return modes.substring(0,modes.length() - 2);
}
Testing the methods:
public static void main(String args[])
{
int[] set = {4, 4, 5, 4, 3, 3, 3};
int[] set2 = {4, 4, 5, 4, 3, 3};
System.out.println(findMode(set)); // mode(s): 3, 4
System.out.println(findMode(set2)); // mode(s): 4
}
There is a logic error in the last part of constructing the modes array. The original code reads modes[j++] = array[i];. Instead, it should be modes[j++] = i. In other words, we need to add that number to the modes whose occurrence count is equal to the maximum occurrence count

how to get the most common character in an array?

Suppose I have an integer array like this:
{5,3,5,4,2}
and I have a method which returns the most common character
public int highestnumber(String[] num) {
int current_number = Integer.parseInt(num[0]);
int counter = 0;
for (int i = 1; i < num.length; ++i) {
if (current_number == Integer.parseInt(num[i])) {
++counter;
} else if (counter == 0) {
current_number = Integer.parseInt(num[i]);
++counter;
} else {
--counter;
}
}
return current_number;
}
but if I have multiple common character then i need to get the number which is closest to one(1), like if i have an array like this:
{5,5,4,4,2};
then the method should return 4, what should I do for this?
As per what I understand your question,
What you have to done is,
1. Create ArrayList from your int[]
2. Use HashMap for find duplicates, which one is unique
3. Sort it as Ascending order,
4. First element is what you want..
EDIT: Answer for your question
int[] arr = {5, 4, 5, 4, 2};
ArrayList<Integer> resultArray = new ArrayList<Integer>();
Set<Integer> set = new HashSet<Integer>();
for (int i = 0; i < arr.length; i++)
{
if (set.contains(arr[i]))
{
System.out.println("Duplicate value found at index: " + i);
System.out.println("Duplicate value: " + arr[i]);
resultArray.add(arr[i]);
}
else
{
set.add(arr[i]);
}
}
Collections.sort(resultArray);
for (int i = 0; i < resultArray.size(); i++)
{
Log.e("Duplicate Values:", resultArray.get(i) + "");
}
Your need is,
int values = resultArray.get(0);
Sort the array then count runs of values.
Fast way.
Create a counter int array one element for each number. Go through the array once and increment corresponding counter array for each number. Set highest number to first counter element then go through and change highest number to current element only if it is bigger than highest number, return highest number.
public int highestNumber(String[] num){
int[] count = new int[10];
int highest_number = 0;
int highest_value = 0;
for(int i = 0; i < num.length; i++)
count[Integer.parseInt(num[i])]++;;
for(int i = 0; i < count.length; i++)
if(count[i] > highest_value){
highest_number = i;
highest_value = count[i];
}
return highest_number;
}
10x slower but without other array.
Create three ints one for number and two for counting. Go through the array once for each int and increment current counting each time it shows up, if bigger that highest count, set to highest count and set highest number to current count. Return highest number.
public int highestNumber(String[] num){
int highest_number = 0;
int highest_value = 0;
int current_value = 0;
for(int i = 0; i < 10; i++){
for(int j = 0; j < num.length; j++)
if(i == Integer.parseInt(num[j]))
current_value++;
if(current_value > highest_value){
highest_value = current_value;
highest_number = i;
}
current_value = 0;
}
return highest_number;
}
The first is obviously much faster but if for whatever reason you don't want another array the second one works too.
You can also try this:
import java.util.TreeMap;
public class SmallestFrequentNumberFinder {
public static int[] stringToIntegerArray(String[] stringArray) {
int[] integerArray = new int[stringArray.length];
for (int i = 0; i < stringArray.length; i++) {
integerArray[i] = Integer.parseInt(stringArray[i]);
}
return integerArray;
}
public static int getSmallestFrequentNumber(int[] numbers) {
int max = -1;
Integer smallestFrequentNumber = null;
TreeMap<Integer, Integer> frequencyMaper = new TreeMap<Integer, Integer>();
for (int number : numbers) {
Integer frequency = frequencyMaper.get(number);
frequencyMaper.put(number, (frequency == null) ? 1 : frequency + 1);
}
for (int number : frequencyMaper.keySet()) {
Integer frequency = frequencyMaper.get(number);
if (frequency != null && frequency > max) {
max = frequency;
smallestFrequentNumber = number;
}
}
return smallestFrequentNumber;
}
public static void main(String args[]) {
String[] numbersAsString = {"5", "5", "4", "2", "4", "4", "2", "2"};
final int[] integerArray = stringToIntegerArray(numbersAsString);
System.out.println(getSmallestFrequentNumber(integerArray));
}
}

Create an int array of int arrays that contains all possible sums that add up to a given number

I'm completely new in Java. I am writing an Android game, and I need to generate an array of int arrays that contains all possible sums (excluding combinations that contains number 2 or is bigger than 8 numbers) that add up to a given number.
For example:
ganeratePatterns(5) must return array
[patternNumber][summandNumber] = value
[0][0] = 5
[1][0] = 1
[1][1] = 1
[1][2] = 1
[1][3] = 1
[1][4] = 1
[2][0] = 3
[2][1] = 1
[2][2] = 1
[3][0] = 4
[3][1] = 1
I already try to do this like there Getting all possible sums that add up to a given number
but it's very difficult to me to make it like this http://introcs.cs.princeton.edu/java/23recursion/Partition.java.html
Solution
int n = 10;
int dimension = 0;
//First we need to count number of posible combinations to create a 2dimensionarray
for(List<Integer> sumt : new SumIterator(n)) {
if(!sumt.contains(2) && sumt.size() < 9) {
dimension++;
}
}
int[][] combinationPattern = new int[dimension][];
int foo = 0;
for(List<Integer> sum : new SumIterator(n)) {
if(!sum.contains(2) && sum.size() < 9) {
System.out.println(sum);
combinationPattern[foo] = toIntArray(sum);
foo++;
}
}
It's work not 100% correctly, and very pretty, but it is enough for my game
I have used SumIterator class from here SumIterator.class
I have to changed this code for(int j = n-1; j > n/2; j--) { to this for(int j = n-1; j >= n/2; j--) { because old version doesn't return all combinations (like [5,5] for 10)
And I used toIntArray function. I have founded hare on StackOverflow, but forget a link so here it's source:
public static int[] toIntArray(final Collection<Integer> data){
int[] result;
// null result for null input
if(data == null){
result = null;
// empty array for empty collection
} else if(data.isEmpty()){
result = new int[0];
} else{
final Collection<Integer> effective;
// if data contains null make defensive copy
// and remove null values
if(data.contains(null)){
effective = new ArrayList<Integer>(data);
while(effective.remove(null)){}
// otherwise use original collection
}else{
effective = data;
}
result = new int[effective.size()];
int offset = 0;
// store values
for(final Integer i : effective){
result[offset++] = i.intValue();
}
}
return result;
}
This is not the most beautiful code, but it does what you would like, having modified the code you referenced. It is also quite fast. It could be made faster by staying away from recursion (using a stack), and completely avoiding String-to-integer conversion. I may come back and edit those changes in. Running on my pretty outdated laptop, it printed the partitions of 50 (all 204226 of them) in under 5 seconds.
When partition(N) exits in this code, partitions will hold the partitions of N.
First, it builds an ArrayList of string representations of the sums in space-delimited format (example: " 1 1 1").
It then creates a two-dimensional array of ints which can hold all of the results.
It splits each String in the ArrayList into an array of Strings which each contain only a single number.
For each String, it creates an array of ints by parsing each number into an array.
This int array is then added to the two-dimensional array of ints.
Let me know if you have any questions!
import java.util.ArrayList;
public class Partition
{
static ArrayList<String> list = new ArrayList<String>();
static int[][] partitions;
public static void partition(int n)
{
partition(n, n, "");
partitions = new int[list.size()][0];
for (int i = 0; i < list.size(); i++)
{
String s = list.get(i);
String[] stringAsArray = s.trim().split(" ");
int[] intArray = new int[stringAsArray.length];
for (int j = 0; j < stringAsArray.length; j++)
{
intArray[j] = Integer.parseInt(stringAsArray[j]);
}
partitions[i] = intArray;
}
}
public static void partition(int n, int max, String prefix)
{
if(prefix.trim().split(" ").length > 8 || (prefix + " ").contains(" 2 "))
{
return;
}
if (n == 0)
{
list.add(prefix);
return;
}
for (int i = Math.min(max, n); i >= 1; i--)
{
partition(n - i, i, prefix + " " + i);
}
}
public static void main(String[] args)
{
int N = 50;
partition(N);
/**
* Demonstrates that the above code works as intended.
*/
for (int i = 0; i < partitions.length; i++)
{
int[] currentArray = partitions[i];
for (int j = 0; j < currentArray.length; j++)
{
System.out.print(currentArray[j] + " ");
}
System.out.println();
}
}
}

Categories

Resources