I have been working on code to iteratively partition integers and use previous results to fully partition the numbers, with the idea that using previous partitions can increase speed. So far, I have gotten performance 22x slower than recursively partitioning the integers, and haven't been able to test larger numbers due to quickly running out of memory. If anyone could help optimize the code, I would be grateful for the help.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
public class Summands {
private static HashMap<Integer, HashSet<List<Integer>>> results;
private static HashMap<Integer, HashSet<String>> recursiveResults;
private static void sort(int[] a) {
//Radix sort for int array
int i, m = a[0], exp = 1, n = a.length;
int[] b = new int[n];
for (i = 1; i < n; i++) {
if (a[i] > m) {
m = a[i];
}
}
while (m / exp > 0) {
int[] bucket = new int[n];
for (i = 0; i < n; i++)
bucket[(a[i] / exp) % n]++;
for (i = 1; i < n; i++)
bucket[i] += bucket[i - 1];
for (i = n - 1; i >= 0; i--)
b[--bucket[(a[i] / exp) % n]] = a[i];
for (i = 0; i < n; i++)
a[i] = b[i];
exp *= n;
}
}
private static void generateResults(int n) {
//iterative partitioning
results.put(n, new HashSet<>());
results.get(n).add(new ArrayList<>());
for (List<Integer> list : results.get(n)) {
list.add(n);
}
for (int i = 1; i <= Math.floorDiv(n, 2); i++) {
//get all 2 summands partitions
int a = n - i;
results.get(n).add(Arrays.asList(i, a));
}
if (n > 1) {
//Get the rest of the partitions
HashSet<List<Integer>> set = new HashSet<>(results.get(n));
for (List<Integer> equ : set) {
if (equ.size() > 1) {
if (equ.get(1) > 1) {
HashSet<List<Integer>> temp = results.get(equ.get(1));
for (List<Integer> k : temp) {
List<Integer> tempEquList = new ArrayList<>(k);
tempEquList.add(equ.get(0));
int[] tempEqu = tempEquList.stream()
.mapToInt(Integer::intValue).toArray();
sort(tempEqu);
results.get(n).add(Arrays.stream(tempEqu)
.boxed().collect(Collectors.toList()));
}
}
}
}
}
}
private static void recursivePartition(int n) {
//recursively partition
recursiveResults.put(n, new HashSet<>());
partition(n, n, "", n);
}
private static void partition(int n, int max, String prefix, int key) {
//recursive method for partitioning
if (n == 0) {
recursiveResults.get(key).add(prefix);
return;
}
for (int i = Math.min(max, n); i >= 1; i--) {
partition(n - i, i, prefix + " " + i, key);
}
}
public static void main(String[] args) {
//get number of partitions to get
int target = Integer.valueOf(args[0]);
//time the iterative version
long time1 = System.currentTimeMillis();
results = new HashMap<>(target);
//loop until done
for (int i = 1; i <= target; i++) {
System.out.println(i);
generateResults(i);
}
//time both methods
long time2 = System.currentTimeMillis();
recursiveResults = new HashMap<>(target);
for (int i = 1; i <= target; i++) {
//loop until done
System.out.println(i);
recursivePartition(i);
}
long time3 = System.currentTimeMillis();
System.out.println("Iterative time: " + String.valueOf(time2 - time1));
System.out.println("Recursive time: " + String.valueOf(time3 - time2));
/*for (Integer key : results.keySet()) {
//For ensuring proper amount of partitions
//for lower numbers. Primarily for testing
System.out.println(key + ": " + results.get(key).size());
}*/
}
}
You can generate a set of combinations of the summands of the specified number, i.e. the integer partition, using mapToObj and reduce methods. First prepare the sets of arrays of summands, and then multiply the pairs of these sets sequentially and get the Cartesian product.
Try it online!
int n = 7;
Set<int[]> partition = IntStream.range(0, n)
// prepare sets of arrays of summands
.mapToObj(i -> IntStream.rangeClosed(1, n - i)
.mapToObj(j -> new int[]{j})
// Stream<TreeSet<int[]>>
.collect(Collectors.toCollection(
// comparing the contents of two arrays
() -> new TreeSet<>(Arrays::compare))))
// intermediate output, sets of arrays of summands
.peek(set -> System.out.println(
set.stream().map(Arrays::toString).collect(Collectors.joining())))
// sequential summation of pairs of sets up to the given number
.reduce((set1, set2) -> set1.stream()
// combinations of inner arrays
.flatMap(arr1 -> {
// sum of the elements of the first array
int sum = Arrays.stream(arr1).sum();
// if the specified number is reached
if (sum == n) return Arrays.stream(new int[][]{arr1});
// otherwise continue appending summands
return set2.stream() // drop the combinations that are greater
.filter(arr2 -> Arrays.stream(arr2).sum() + sum <= n)
.map(arr2 -> Stream.of(arr1, arr2)
.flatMapToInt(Arrays::stream)
.sorted().toArray()); // the sorted array
}) // set of arrays of combinations
.collect(Collectors.toCollection( // two arrays that differ
// only in order are considered the same partition
() -> new TreeSet<>(Arrays::compare))))
// otherwise an empty set of arrays
.orElse(new TreeSet<>(Arrays::compare));
// final output, the integer partition of the specified number
partition.stream().map(Arrays::toString).forEach(System.out::println);
Intermediate output, sets of arrays of summands:
[1][2][3][4][5][6][7]
[1][2][3][4][5][6]
[1][2][3][4][5]
[1][2][3][4]
[1][2][3]
[1][2]
[1]
Final output, the integer partition of the specified number:
[1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 2]
[1, 1, 1, 1, 3]
[1, 1, 1, 2, 2]
[1, 1, 1, 4]
[1, 1, 2, 3]
[1, 1, 5]
[1, 2, 2, 2]
[1, 2, 4]
[1, 3, 3]
[1, 6]
[2, 2, 3]
[2, 5]
[3, 4]
[7]
See also: Building permutation that sums to a number efficiently
Related
I have a Q number of queries containing N elements each. Queries will be range.
[1, 3] [2, 3] [3, 4]
If we flatten out range queries we will get this.
1, 2, 3, 2, 3, 3, 4
I am trying to find a solution to create a array given below.
[1, 2, 3, 4] --> elements in range
[1, 2, 3, 1] --> their frequency array
Explanation -> Element 1 comes only one time in range queries, similarly, 2 comes two times in range queries, and so on, and at last 4 comes only one time.
Which gives a array of elements frequency as mentioned above.
But flattening out the range and iterating over it to create a array has a time complexity of O(QN) [1, 2, 3, 2, 3, 3, 4] --> [1, 2, 3, 1]
I failed to optimize it, my question is - How can we do it in the least possible time complexity (at least less than O(QN)?
I see two possible approaches. The first assumes one iteration through full range of every query. It's efficient at small ranges, but not better than O(QN):
int[] freqCount1 (final List<int[]> queries){
Map<Integer, Integer> results = new HashMap<>();
for(int[] q : queries){
for(int i = q[0]; i <= q[1]; i++){
if (!results.containsKey(i)){
results.put(i, 1);
}
else {
results.put(i, results.get(i) + 1);
}
}
}
int[] count = new int[results.size()];
List<Integer> resultsValues = new ArrayList<>(results.values());
for (int i = 0; i < resultsValues.size(); i++){
count[i] = resultsValues.get(i);
}
return count;
}
The second approach assumes determining the range for all queries altogether and then iterating through each element from the range, checking whether it's included in each of the queries. In this approach you don't need to iterate through full range of each query, so I believe this is below O(QN), assuming that the ranges overlap to some extent.
int[] freqCount2 (final List<int[]> queries){
int min = queries.stream().map(q -> q[0]).min(Integer::compareTo).get();
int max = queries.stream().map(q -> q[1]).max(Integer::compareTo).get();
int range = max - min + 1;
int[] entries = new int[range];
List<Integer> countList = new ArrayList<>();
for (int i = 0; i < range; i++){
entries[i] = i + min;
countList.add(0);
}
for (int[] q : queries) {
for (int i = 0; i < range; i++) {
if (entries[i] >= q[0] && entries[i] <= q[1]) {
countList.set(i, countList.get(i) + 1);
}
}
}
List<Integer> countListFiltered = countList.stream()
.filter(integer -> integer > 0)
.collect(Collectors.toList());
int[] count = new int[countListFiltered.size()];
for (int i = 0; i < countListFiltered.size(); i++){
count[i] = countListFiltered.get(i);
}
return count;
}
I tested in practice and with your example the first approach is much faster, but with long and overlapping ranges the second wins (I tested for [4,50000] [300000,500000] [2,100000] [3,800] [5,100000] [6,100000] [70000,900000] [8,100000])
It should be possible to reach O(Q log(Q) + N) using a sweep. The basic idea is to place the intervals on a number line. Starts and ends of the intervals are processed in ascending order while maintaining a count of "not yet closed intervals".
The following code demonstrates this:
import java.util.*;
import java.util.stream.IntStream;
public class Ranges {
public static void main(String[] args) {
List<Range> ranges = List.of(
new Range(2,7), new Range(1,6), new Range(7, 8), new Range(1, 9)
);
System.out.println(ranges);
List<Event> events = createEvents(ranges);
int open = 0;
int start = 0;
for (Event event : events) {
switch (event.type()) {
case START:
if (open > 0) {
int end = event.value();
output(start, end, open);
start = end;
} else {
start = event.value();
}
open++;
break;
case STOP:
int end = event.value();
if (open == 1 || start != end) {
output(start, end + 1, open);
start = end + 1;
}
open--;
break;
}
}
}
static List<Event> createEvents(List<Range> ranges) {
List<Event> events = new ArrayList<>();
for (Range range : ranges) {
events.add(new Event(EventType.START, range, range.start()));
events.add(new Event(EventType.STOP, range, range.end()));
}
Collections.sort(events);
return events;
}
static void output(int start, int end, int count) {
IntStream.range(start, end).forEach(value -> System.out.printf("%d %d \n", value, count));
}
/* helper types */
enum EventType {START, STOP}
static class Range {
int start, end;
Range(int start, int end) {
this.start = start;
this.end = end;
}
int start() { return start; }
int end() { return end; }
public String toString() {
return "[" + start + ", " + end + "]";
}
}
static class Event implements Comparable<Event> {
EventType type;
Range range;
int value;
Event(EventType type, Range range, int value) {
this.type = type;
this.range = range;
this.value = value;
}
#Override
public int compareTo(Event e) {
return Integer.compare(value, e.value);
}
EventType type() { return type; }
Range range() { return range; }
int value() { return value; }
}
}
Outputs
[[2, 7], [1, 6], [7, 8], [1, 9]]
1 2
2 3
3 3
4 3
5 3
6 3
7 2
8 2
9 1
(first line is the input; number and count on each following line)
Complexity is determined by sorting in O(Q log(Q)) time and by emitting the counts for each number in O(N). If I'm not wrong, complexity should be O(Q log(Q) + N).
I want to count the number of unique values in an array but I'm having trouble counting in the correct way.
int uniqueNumbers = 1;
Arrays.sort(n);
if (n.length == 0) {
uniqueNumbers = 0;
}
for ( int i = 1; i < n.length; i++) {
if (n[i] != n[i - 1]) {
uniqueNumbers++;
}
}
The problem is if an integer appears several times it still counts it as one unique number, when I want it not to be counted as a unique number.
you can utilize a set to add all the numbers, as won't allow duplicates.
int uniqueNumbers = 1;
Set<Integer> set = new HashSet<>();
Arrays.sort(n);
if (n.length == 0) {
uniqueNumbers = 0;
}
for ( int i = 0; i < n.length; i++) {
set.add(n[i];
}
System.out.println(set.size());
A nested loop to track a unique number and discard it can help resolve this task:
public static int countUnique(int ... n) {
Arrays.sort(n);
System.out.println(Arrays.toString(n));
int uniqueNumbers = 0;
for (int i = 0; i < n.length; i++) {
boolean unique = true;
for (int j = i + 1; j < n.length && n[i] == n[j]; j++, i++) {
unique = false;
}
if (unique) {
uniqueNumbers++;
}
}
return uniqueNumbers;
}
Tests:
System.out.println(countUnique(2, 1, 2, 3, 4, 6, 4));
System.out.println(countUnique(2, 1, 2, 3, 4, 1, 4));
System.out.println(countUnique(2, 1, 2, 4, 4, 1, 4));
Output:
[1, 2, 2, 3, 4, 4, 6]
3
[1, 1, 2, 2, 3, 4, 4]
1
[1, 1, 2, 2, 4, 4, 4]
0
However, because of sorting the input array, the complexity of this algorithm is O(N log N).
If it is allowed to use Set to track duplicates using the fact that Set::add returns false when an element already exists in the set, this may be implemented as follows (also, the input array does not need to be sorted, so this algorithm has O(N) complexity):
public static int countUniqueSets(int ... n) {
System.out.println(Arrays.toString(n));
Set<Integer> ones = new HashSet<>();
Set<Integer> dups = new HashSet<>();
for (int x : n) {
if (!ones.add(x)) {
dups.add(x);
}
}
System.out.println("distinct: " + ones);
System.out.println("duplicates: " + dups);
return ones.size() - dups.size();
}
Output for the same tests:
[2, 1, 2, 3, 4, 6, 4]
distinct: [1, 2, 3, 4, 6]
duplicates: [2, 4]
3
[2, 1, 2, 3, 4, 1, 4]
distinct: [1, 2, 3, 4]
duplicates: [1, 2, 4]
1
[2, 1, 2, 4, 4, 1, 4]
distinct: [1, 2, 4]
duplicates: [1, 2, 4]
0
Another approach using Stream API is to build a frequency map using Collectors.groupingBy + Collectors.counting or Collectors.summingInt and then count the entries in the map with frequency = 1:
public static int countUniqueStream(int ... n) {
System.out.println(Arrays.toString(n));
return (int) Arrays.stream(n)
.boxed()
.collect(Collectors.groupingBy(
x -> x,
Collectors.counting()
)) // Map<Integer, Long>
.entrySet()
.stream()
.filter(e -> 1 == e.getValue())
.count();
}
public static int countUniqueStreamInt(int ... n) {
System.out.println(Arrays.toString(n));
return Arrays.stream(n)
.boxed()
.collect(Collectors.groupingBy(
x -> x,
Collectors.summingInt(x -> 1)
)) // Map<Integer, Integer>
.entrySet().stream()
.filter(e -> 1 == e.getValue())
.collect(Collectors.summingInt(e -> 1));
}
There are so many ways to do so e.g. using Stream API.
Demo:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int [] arr= {1,2,3,4,2,3,4,1,4,3};
long uniqueCount = Arrays.stream(arr)
.distinct()
.count();
System.out.println(uniqueCount);
}
}
You can put the array content to set and then get the set size.
Set<Integer> targetSet = new HashSet<Integer>(Arrays.asList(n));
targetSet.size()
n is your array name as appearing in the question
You don't need a whole inner loop, you just need to check the two adjacent numbers while respecting the array limits.
private int countUnique (int... n)
{
int uniqueNumbers = 0;
if (n.length < 2)
{
uniqueNumbers = n.length;
}
else
{
Arrays.sort (n);
logger.info ("Data %s", Arrays.toString (n));
// Check first element
if (n[0] != n[1])
{
uniqueNumbers++;
}
// Check last element
if (n[n.length - 2] != n[n.length - 1])
{
uniqueNumbers++;
}
// Check middle elements
for (int i = 1; i < n.length - 1; i++)
{
if ((n[i - 1] != n[i]) && (n[i + 1] != n[i]))
{
uniqueNumbers++;
}
}
}
return uniqueNumbers;
}
The function gets only 2 parameters:
arr of numbers and n represent number of them in array.
I need recursively find and return the Minimum and Maximum in array.
In minimum complexity of 3n/2 comparison.
The code below returns MIN only. How should I make it so it returns both MIN and MAX?
public class MyClass {
public static void main(String[] args) {
int A[] = { 1, 4, 45, 6, -50, 10, 2 };
int n = A.length;
// Function calling
System.out.println(findMinMaxRec(A, n));
}
public static int findMinMaxRec(int A[], int n) {
// if size = 0 means whole array
// has been traversed
if (n == 1)
return A[0];
for (int i = 0; i < n; i++)
return Math.min(A[n - 1], findMinMaxRec(A, n - 1));
// The program NO return min and max (both)
return Math.max(A[n - 1], findMinMaxRec(A, n - 1));
}
}
Answers:
-50
45
Two versions, on in ascending order, and one in descending order :
static int[] findMinMaxRecDesc(int[] A, int n) {
if (n == 0) {
return new int[]{A[0], A[0]};
}
int[] recResult = findMinMaxRecDesc(A, n - 1);
return new int[]{Math.min(A[n - 1], recResult[0]), Math.max(A[n - 1], recResult[1])};
}
static int[] findMinMaxRecAsc(int[] A, int n) {
if (n == A.length - 1) {
return new int[]{A[n], A[n]};
}
int[] recResult = findMinMaxRecAsc(A, n + 1);
return new int[]{Math.min(A[n], recResult[0]), Math.max(A[n], recResult[1])};
}
public static void main(String[] args) {
int[] array = {1, 4, 45, 6, -50, 10, 2};
int[] result = Arrays.toString(findMinMaxRecAsc(array, array.length))
System.out.println(result); // [-50, 45]
}
And the method findMinMaxRec is called n+1 times, so it's linear, like a for-loop
I am attempting to find the maximum sum of non-consecutive subarrays of length at least k.
For example an array of [1, 2, 3, 1, 7, 9] with k = 2 should return 21 with subarrays [2,3] and [7,9] which are the 2 maximum subarrays and are non-consecutive (apart from one another) within the array.
Another example is [1, 2, 3, 4] k = 3
returns: 9, [2, 3, 4]
I am applying the method here which given an array of randomly sorted integers, calculates m number of subarrays of size k but does so by calculating a presum array making it difficult to identify the individual array values which make up the solution. As is done in this example.
Can this method be altered to show the subarrays which make up the total sum?
Below are the functions described in the above method:
// reorganize array
public static int calcProfit(List<Integer> inputArray){
int lotCount = inputArray.get(0);
inputArray.remove(0);
int maxBusiness = inputArray.get(0);
inputArray.remove(0);
// convert arrayList to int array
int[] workingArray = new int[inputArray.size()];
for(int i = 0; i < inputArray.size(); i++) {
if (inputArray.get(i) != null) {
workingArray[i] = inputArray.get(i);
}
}
System.out.println(Arrays.toString(workingArray));
int prefixArray[] = new int[lotCount + 1 - maxBusiness];
int maxArrays = (int) Math.ceil(lotCount / maxBusiness);
arraySum(prefixArray, workingArray, lotCount, maxBusiness);
System.out.println("Prefix array is" + Arrays.toString(prefixArray));
int completeArray = maxSubarray(prefixArray, maxArrays, lotCount + 1 - maxBusiness, maxBusiness, 0);
return completeArray;
}
static void arraySum(int presum[], int arr[], int n, int k)
{
for (int i = 0; i < k; i++)
presum[0] += arr[i];
// store sum of array index i to i+k
// in presum array at index i of it.
for (int i = 1; i <= n - k; i++)
presum[i] += presum[i - 1] + arr[i + k - 1] -
arr[i - 1];
}
private static int maxSubarray(int preSum[], int m, int size, int k, int start) {
// stop if array length is 0
if (m == 0) {
return 0;
}
// stop if start greater than preSum
if (start > size - 1) {
return 0;
}
System.out.println("m is : " + m + " start is : " + start);
// if including subarray of size k
int includeMax = preSum[start] + maxSubarray(preSum,m - 1, size, k, start + k);
// search next possible subarray
int excludeMax = maxSubarray(preSum, m, size, k, start + 1);
System.out.println("exclude max is : " + excludeMax + " include max is " + includeMax);
// return max
return Math.max(includeMax, excludeMax);
}
You can solve the given problem in O(n) using dynamic programming by maintaining a prefix sum array to quickly calculate the sum of a subarray of size k along with maintaining a trace array which records the action taken at each step of the array. Here's an implementation for the same: https://ideone.com/VxKzUn
The ideology behind the approach is that for every element in the array, we have an option to create our sub-array starting from this element or leave it out and move to the next element, thus giving us an optimal sub-structure the recurrence relation of which can be formulated as:
f(n) = max{ sum(arr[n], .. , arr[n + k]) + f(n + k + 1), f(n + 1) }
from collections import defaultdict
dp = defaultdict(lambda: -1)
prefixsum = []
trace = []
def getSubArraySum(i, j):
if i == 0:
return prefixsum[j]
return (prefixsum[j] - prefixsum[i - 1])
def rec(cur, arr, k):
if cur >= len(arr):
return 0
if dp[cur] != -1:
return dp[cur]
# Assuming that all the elements in the array is positive,
# else set s1 and s2 to -Infinity
s1 = -1; s2 = -1
# If we choose the subarray starting at `cur`
if cur + k - 1 < len(arr):
s1 = getSubArraySum(cur, cur + k - 1) + rec(cur + k + 1, arr, k)
# If we ignore the subarray starting at `cur`
s2 = rec(cur + 1, arr, k)
dp[cur] = max(s1, s2)
if s1 >= s2:
trace[cur] = (True, cur + k + 1)
return s1
trace[cur] = (False, cur + 1)
return s2
def getTrace(arr, trace, k):
itr = 0
subArrays = []
while itr < len(trace):
if trace[itr][0]:
subArrays.append(arr[itr : itr + k])
itr = trace[itr][1]
return subArrays
def solve(arr, k):
global dp, trace, prefixsum
dp = defaultdict(lambda: -1)
trace = [(False, 0)] * len(arr)
prefixsum = [0] * len(arr)
prefixsum[0] = arr[0]
for i in range(1, len(arr)):
prefixsum[i] += prefixsum[i - 1] + arr[i]
print("Array :", arr)
print("Max sum: ", rec(0, arr, k))
print("Subarrays: ", getTrace(arr, trace, k))
print("-- * --")
solve([1, 2, 3, 4], 3)
solve([1, 2, 3, 1, 7, 9] , 2)
The output from the above code is,
Array : [1, 2, 3, 4]
Max sum: 9
Subarrays: [[2, 3, 4]]
-- * --
Array : [1, 2, 3, 1, 7, 9]
Max sum: 21
Subarrays: [[2, 3], [7, 9]]
-- * --
I am trying to write a recursive function to produce all permutations of an array.
static int permus[] = new int[] { 1, 2, 3, 4, 5 };
static void testPermu(int start)
{
// Print it
System.out.println(Arrays.toString(permus));
int k;
for (int i = start + 1; i < permus.length; i++) {
// swap
k = permus[start];
permus[start] = permus[i];
permus[i] = k;
testPermu(i);
// unswap
k = permus[start];
permus[start] = permus[i];
permus[i] = k;
}
}
It's invoked as testPermu(0) and should produce all permutations, however that does not work. How can I fix it?
It needs to be recursive, each time the function is invoked, it should get a fresh permutation.
output now is
[1, 2, 3, 4, 5]
[2, 1, 3, 4, 5]
[2, 3, 1, 4, 5]
[2, 3, 4, 1, 5]
[2, 3, 4, 5, 1]
[2, 3, 5, 4, 1]
[2, 4, 3, 1, 5]
[2, 4, 3, 5, 1]
[2, 5, 3, 4, 1]
[3, 2, 1, 4, 5]
[3, 2, 4, 1, 5]
[3, 2, 4, 5, 1]
[3, 2, 5, 4, 1]
[4, 2, 3, 1, 5]
[4, 2, 3, 5, 1]
[5, 2, 3, 4, 1]
You can see that many of the permutations are missing.
I'm writing it in Java but I'll understand example in C, javascript or anything else as long as it's not using some library tricks not available in Java.
Three corrections are needed in order to work:
print only if (start == permus.length-1), otherwise you'll see duplicates
start the for loop from i = start, not i = start + 1
recursively call testPermu(start + 1); instead of testPermu(i);
Here is a full example:
package eric.math;
import java.util.Arrays;
public class Permute {
// swap 2 elements of an array,
void swap(int[] arr, int x, int y) {
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
/**
* print permutations of array
* #param arr
* original int array,
*/
void permute(int[] arr) {
permute(arr, 0, arr.length - 1);
}
/**
* print permutations of array
*
* #param arr
* original int array,
* #param i
* start index
* #param n
* end index
*/
void permute(int[] arr, int i, int n) {
int j;
if (i == n)
System.out.println(Arrays.toString(arr));
else {
for (j = i; j <= n; j++) {
swap(arr, i, j);
permute(arr, i + 1, n);
swap(arr, i, j); // backtrack
}
}
}
public static void main(String[] args) {
int arr[] = { 1, 2, 3 };
new Permute().permute(arr);
}
}
#Enric solution is nice, but using solution below we can avoid 80 swaps and perform only 24 swaps.
static void permutation(int[] a, int i, int j) {
for (; j < a.length && i < a.length; j++) {
int[] temp = null;
if (i != j) {
temp = swap(a, i, j);
System.out.println(Arrays.toString(temp));
}else{
temp = a;
}
permutation(temp, i + 1, i + 1);
}
}
public static void main(String[] args) {
int[] a = { 0, 1, 2, 3 };
permutation(a, 0, 0);
}
Another approach:
static ArrayList<ArrayList<Integer>> getPermutation(ArrayList<Integer> ints) {
if (ints.size() == 1) {
ArrayList<ArrayList<Integer>> list = new ArrayList<>();
list.add(ints);
return list;
} else {
ArrayList<ArrayList<Integer>> list = new ArrayList<>();
for (Integer i: ints) {
ArrayList<Integer> subList = new ArrayList<>(ints);
subList.remove(i);
ArrayList<ArrayList<Integer>> subListNew = getPermutation(subList);
for (ArrayList<Integer> _list: subListNew) {
ArrayList<Integer> local = new ArrayList<>();
local.add(i);
local.addAll(_list);
list.add(local);
}
}
return list;
}
}
This method first selects an element, removes it and obtains a sub-list, then produces a permutation of the sub-list until the list size becomes 1.
I like #tony200910041 approach but maybe someone would like a cleaner and more generic version of it:
public static <T> List<List<T>> getPermutations(List<T> list) {
if (list.size() == 1)
return Collections.singletonList(list);
List<List<T>> perms = new ArrayList<>();
for (T element: list) {
List<T> subList = new ArrayList<>(list);
subList.remove(element);
List<List<T>> subPerms = getPermutations(subList);
for (List<T> subPerm: subPerms) {
List<T> perm = new ArrayList<>();
perm.add(element);
perm.addAll(subPerm);
perms.add(perm);
}
}
return perms;
}
Sort the list before passing it to the getPermutations() function if you want your permutations in ascending order.
Try with
testPermu(start + 1);
You can do it simply without recursion
public static Integer[] permutate(int i)
{
int length = permus.length;
Integer[] result = new Integer[length];
List<Integer> chosen = new ArrayList<Integer>(Arrays.asList(permus));
int divider = 1;
for (int j=2; j<length; j++)
{
divider *= j;
}
for (int j=length; j>1; j--)
{
int index = i/divider;
result[length - j] = chosen.remove(index);
i = i - divider * (i/divider);
divider = divider / (j-1);
}
result[length -1] = chosen.remove(0);
return result;
}
How about the following algorithm (given in pseudocode)
iterate over elements:
pick one of the element at random
call function again on the remaining elements
if elements.size == 1
return or print
This should produce a valid permutation at each run. If you want all possible permutations, just accumulate as you iterate, then you should have all permutations.