Related
I am working on this problem which seems very straigtforward:
For n number of dies return all the permutations.
Eg. n = 1, output = [[1],[2],[3],[4],[5],[6]]
Eg. n = 2, output = [[1, 1],[1, 2],[1, 3],[1, 4],[1, 5],[1, 6], [2, 1], ..... [6, 6]]
So I have solved it using recursion where the current solution uses previous results and builds on it:
public class Dice {
private static List<List<Integer>> getCombinations(int n) {
List<List<Integer>> result = new ArrayList<>();
// base cases
if (n == 0) {
return result;
}
if (n == 1) {
for (int i = 1; i <= 6; i++){
List<Integer> list = new ArrayList<>();
list.add(i);
result.add(list);
}
}
// general case
List<List<Integer>> prevResult = getCombinations(n - 1);
for (List<Integer> prevlist: prevResult){
for (int i = 1; i <= 6; i++){
List<Integer> list = new ArrayList<>(prevlist);
list.add(i);
result.add(list);
}
}
memo.put(n, result);
return result;
}
public static void main(String[] args) {
System.out.println("val = " + getCombinations(4));
}
}
I wanted to ask if I am right about the time complexity, which I think would be:
Time Complexity = O(b^d)
where b=branching factor and d=depth of recursion tree
= O(6^n)
Is this right?
Also I had 2 additional questions:
Is there a way I can memoize the above to reduce the time complexity?
Is there another better algorithm that I can use to solve this?
If you want to use an iterative approach rather than recursive, you could consider using a Deque:
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
/** Prints the permutations of rolling N dice with M faces. */
final class DiceRollPermutations {
private DiceRollPermutations() {}
public static void main(String[] args) {
if (args.length != 2) {
System.err.println("Usage: java DiceRollPermutations <numDice> <numFaces>");
System.exit(1);
}
int numDice = Integer.parseInt(args[0]);
int numFaces = Integer.parseInt(args[1]);
Deque<List<Integer>> diceRollPermutations = getDiceRollPermutations(numDice, numFaces);
System.out.printf(
"All possible permutations (%d) for rolling %d %s with %d %s:%n",
diceRollPermutations.size(),
numDice,
numDice == 1 ? "die" : "dice",
numFaces,
numFaces == 1 ? "face" : "faces");
for (List<Integer> permutation : diceRollPermutations) {
System.out.println(permutation);
}
}
public static Deque<List<Integer>> getDiceRollPermutations(int numDice, int numFaces) {
Deque<List<Integer>> permutations = new ArrayDeque<>();
permutations.offer(new ArrayList<Integer>());
for (int i = 1; i <= numDice; i++) {
int numPermutations = permutations.size();
for (int j = 1; j <= numPermutations; j++) {
List<Integer> perm = permutations.pollFirst();
for (int k = 1; k <= numFaces; k++) {
List<Integer> permClone = new ArrayList<>(perm);
permClone.add(k);
permutations.offer(permClone);
}
}
}
return permutations;
}
}
Example Usage 1:
$ java DiceRollPermutations 2 6
All possible permutations (36) for rolling 2 dice with 6 faces:
[1, 1]
[1, 2]
[1, 3]
[1, 4]
[1, 5]
[1, 6]
[2, 1]
[2, 2]
[2, 3]
[2, 4]
[2, 5]
[2, 6]
[3, 1]
[3, 2]
[3, 3]
[3, 4]
[3, 5]
[3, 6]
[4, 1]
[4, 2]
[4, 3]
[4, 4]
[4, 5]
[4, 6]
[5, 1]
[5, 2]
[5, 3]
[5, 4]
[5, 5]
[5, 6]
[6, 1]
[6, 2]
[6, 3]
[6, 4]
[6, 5]
[6, 6]
Example Usage 2:
$ java DiceRollPermutations 3 6
All possible permutations (216) for rolling 3 dice with 6 faces:
[1, 1, 1]
[1, 1, 2]
[1, 1, 3]
[1, 1, 4]
[1, 1, 5]
[1, 1, 6]
[1, 2, 1]
[1, 2, 2]
[1, 2, 3]
[1, 2, 4]
[1, 2, 5]
[1, 2, 6]
[1, 3, 1]
[1, 3, 2]
[1, 3, 3]
[1, 3, 4]
[1, 3, 5]
[1, 3, 6]
[1, 4, 1]
[1, 4, 2]
[1, 4, 3]
[1, 4, 4]
[1, 4, 5]
[1, 4, 6]
[1, 5, 1]
[1, 5, 2]
[1, 5, 3]
[1, 5, 4]
[1, 5, 5]
[1, 5, 6]
[1, 6, 1]
[1, 6, 2]
[1, 6, 3]
[1, 6, 4]
[1, 6, 5]
[1, 6, 6]
[2, 1, 1]
[2, 1, 2]
[2, 1, 3]
[2, 1, 4]
[2, 1, 5]
[2, 1, 6]
[2, 2, 1]
[2, 2, 2]
[2, 2, 3]
[2, 2, 4]
[2, 2, 5]
[2, 2, 6]
[2, 3, 1]
[2, 3, 2]
[2, 3, 3]
[2, 3, 4]
[2, 3, 5]
[2, 3, 6]
[2, 4, 1]
[2, 4, 2]
[2, 4, 3]
[2, 4, 4]
[2, 4, 5]
[2, 4, 6]
[2, 5, 1]
[2, 5, 2]
[2, 5, 3]
[2, 5, 4]
[2, 5, 5]
[2, 5, 6]
[2, 6, 1]
[2, 6, 2]
[2, 6, 3]
[2, 6, 4]
[2, 6, 5]
[2, 6, 6]
[3, 1, 1]
[3, 1, 2]
[3, 1, 3]
[3, 1, 4]
[3, 1, 5]
[3, 1, 6]
[3, 2, 1]
[3, 2, 2]
[3, 2, 3]
[3, 2, 4]
[3, 2, 5]
[3, 2, 6]
[3, 3, 1]
[3, 3, 2]
[3, 3, 3]
[3, 3, 4]
[3, 3, 5]
[3, 3, 6]
[3, 4, 1]
[3, 4, 2]
[3, 4, 3]
[3, 4, 4]
[3, 4, 5]
[3, 4, 6]
[3, 5, 1]
[3, 5, 2]
[3, 5, 3]
[3, 5, 4]
[3, 5, 5]
[3, 5, 6]
[3, 6, 1]
[3, 6, 2]
[3, 6, 3]
[3, 6, 4]
[3, 6, 5]
[3, 6, 6]
[4, 1, 1]
[4, 1, 2]
[4, 1, 3]
[4, 1, 4]
[4, 1, 5]
[4, 1, 6]
[4, 2, 1]
[4, 2, 2]
[4, 2, 3]
[4, 2, 4]
[4, 2, 5]
[4, 2, 6]
[4, 3, 1]
[4, 3, 2]
[4, 3, 3]
[4, 3, 4]
[4, 3, 5]
[4, 3, 6]
[4, 4, 1]
[4, 4, 2]
[4, 4, 3]
[4, 4, 4]
[4, 4, 5]
[4, 4, 6]
[4, 5, 1]
[4, 5, 2]
[4, 5, 3]
[4, 5, 4]
[4, 5, 5]
[4, 5, 6]
[4, 6, 1]
[4, 6, 2]
[4, 6, 3]
[4, 6, 4]
[4, 6, 5]
[4, 6, 6]
[5, 1, 1]
[5, 1, 2]
[5, 1, 3]
[5, 1, 4]
[5, 1, 5]
[5, 1, 6]
[5, 2, 1]
[5, 2, 2]
[5, 2, 3]
[5, 2, 4]
[5, 2, 5]
[5, 2, 6]
[5, 3, 1]
[5, 3, 2]
[5, 3, 3]
[5, 3, 4]
[5, 3, 5]
[5, 3, 6]
[5, 4, 1]
[5, 4, 2]
[5, 4, 3]
[5, 4, 4]
[5, 4, 5]
[5, 4, 6]
[5, 5, 1]
[5, 5, 2]
[5, 5, 3]
[5, 5, 4]
[5, 5, 5]
[5, 5, 6]
[5, 6, 1]
[5, 6, 2]
[5, 6, 3]
[5, 6, 4]
[5, 6, 5]
[5, 6, 6]
[6, 1, 1]
[6, 1, 2]
[6, 1, 3]
[6, 1, 4]
[6, 1, 5]
[6, 1, 6]
[6, 2, 1]
[6, 2, 2]
[6, 2, 3]
[6, 2, 4]
[6, 2, 5]
[6, 2, 6]
[6, 3, 1]
[6, 3, 2]
[6, 3, 3]
[6, 3, 4]
[6, 3, 5]
[6, 3, 6]
[6, 4, 1]
[6, 4, 2]
[6, 4, 3]
[6, 4, 4]
[6, 4, 5]
[6, 4, 6]
[6, 5, 1]
[6, 5, 2]
[6, 5, 3]
[6, 5, 4]
[6, 5, 5]
[6, 5, 6]
[6, 6, 1]
[6, 6, 2]
[6, 6, 3]
[6, 6, 4]
[6, 6, 5]
[6, 6, 6]
I am creating unique subsequences of size 2 using below code. How can I create subsequences of different sizes. Size would be dynamic.
For example, [1 2 3 4] -> [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
For size 3, it would be , [[1, 2, 3], [1, 2, 4], [2, 3, 4]]
public static int getTheSubseq(List<Integer> AList){
List<List<Integer>> li = new ArrayList<>();
for (int i = 0; i < AList.size(); i++){
for(int j =i+1; j < AList.size(); j++){
List<Integer> temp = new ArrayList<>();
temp.add(AList.get(i));
temp.add(AList.get(j));
li.add(temp);
}
}
System.out.println(li);
return 1;
}
Using recursion you could build the subsequences as follows:
private void buildSubsequence( List<Integer> source, int targetSize,
List<List<Integer>> result, Stack<Integer> currentSubsequence, int currentIndex ) {
//We don't want to iterate beyond the point where we can't build a complete subsequence.
//Thus we'll need to subtract the number of still needed elements
//(target count - number of elements already in the subsequence - 1 for this call)
int maxIndex = source.size() - ( targetSize - currentSubsequence.size() - 1);
//iterate over each index from the current one to this call's max
for( int i = currentIndex; i < maxIndex; i++ ) {
//add the element at that index to the subsequence
currentSubsequence.push( source.get( i ) );
//if we're done make a copy
if( currentSubsequence.size() == targetSize ) {
result.add( new ArrayList<Integer>( currentSubsequence) );
} else { //if we're not done, get the next element
buildSubsequence( source, targetSize, result, currentSubsequence, i + 1 );
}
//remove the last element added by push() to have it replaced with the next one
currentSubsequence.pop();
}
}
Then you call it like this:
List<Integer> source = Arrays.asList( 1,2,3,4,5,6 );
List<List<Integer>> result = new LinkedList<>();
buildSubsequence( source, 3, result, new Stack<>(), 0 );
That creates the following subsequences:
[1, 2, 3]
[1, 2, 4]
[1, 2, 5]
[1, 2, 6]
[1, 3, 4]
[1, 3, 5]
[1, 3, 6]
[1, 4, 5]
[1, 4, 6]
[1, 5, 6]
[2, 3, 4]
[2, 3, 5]
[2, 3, 6]
[2, 4, 5]
[2, 4, 6]
[2, 5, 6]
[3, 4, 5]
[3, 4, 6]
[3, 5, 6]
[4, 5, 6]
Note that this is just one way to solve it. :)
Currently i am trying to create a method to sort an arraylist of stack of integer lexicographical for my assignment. Currently this is what i had, however, right now i am facing a problem.
Collections.sort(arrayList, new Comparator<Stack<Integer>>(){
public int compare(Stack<Integer> list1, Stack<Integer> list2){
int result = 0;
for (int i = 0; i <= list1.size() - 1 && result == 0; i++)
{
result = list2.get(i).compareTo(list1.get(i));
}
return result;
}
});
When i try to input [[1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 3], [1, 1, 1, 3, 1], [1, 1, 3, 1, 1], [1, 3, 1, 1, 1], [3, 1, 1, 1, 1], [1, 1, 3, 3], [1, 3, 1, 3], [1, 3, 3, 1], [3, 1, 1, 3], [3, 1, 3, 1], [3, 3, 1, 1], [1, 4, 4], [4, 1, 4], [4, 4, 1], [3, 3, 3]] as the arraylist of stack of integer and manage to get this as the result:
Output: [[4, 4, 1], [4, 1, 4], [3, 3, 3], [3, 3, 1, 1], [3, 1, 3, 1], [3, 1, 1, 3], [3, 1, 1, 1, 1], [1, 4, 4], [1, 3, 3, 1], [1, 3, 1, 3], [1, 3, 1, 1, 1], [1, 1, 3, 3], [1, 1, 3, 1, 1], [1, 1, 1, 3, 1], [1, 1, 1, 1, 3], [1, 1, 1, 1, 1, 1]]
As you can see that is not lexicographic and this is what i am aiming for
Expected output: [[1, 4, 4], [3, 3, 3], [4, 1, 4], [4, 4, 1], [1, 1, 3, 3], [1, 3, 1, 3], [1, 3, 3, 1], [3, 1, 1, 3], [3, 1, 3, 1], [3, 3, 1, 1], [1, 1, 1, 1, 3], [1, 1, 1, 3, 1], [1, 1, 3, 1, 1], [1, 3, 1, 1, 1], [3, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1]]
Here is the question, Where did i get it wrong? how does .compareTo works?
Edit:
Apparently, my professor make a misunderstanding on the meaning of lexicographically. However, the expected output is the output what my professor desire
You need to first check if one of the stacks is shorter than the other. If not you need to compare the elements of list1 against list2, not the other way around.
Collections.sort(arrayList, new Comparator<Stack<Integer>>(){
public int compare(Stack<Integer> list1, Stack<Integer> list2){
int result = Integer.compare(list1.size(), list2.size());
for (int i = 0; result == 0 && i < list1.size(); i++)
{
result = Integer.compare(list1.get(i), list2.get(i));
}
return result;
}
});
As this is an assignment I will put you on what I think is the right direction, but I won't solve the programming for you:
compare() is a method defined in the interface Comparator<T> that is supposed to return -1, 0, or 1 depending if the first object passed in as a parameter is less, equal, or greater than the second object passed in as a parameter.
The expected objects are of type T which you define when you declare the class.
In the compare() method you write, you have to resolve whatever comparison method you want to implement, to a -1, a 0, or a 1.
How you get to those values depends on how you evaluate an object of T type to be less, equal or greater than other object of the same type.
On another side, Array.sort() will use the Comparator as fit to make comparisons between two elements of the array, and return as a final result the ordered Array.
If I understood your clarification, an array [1,1,1], for ordering purposes should be interpreted as a String "111";
So in terms of programming the Comparator, what will be compared (the T) would be arrays of integers.
And to compare two arrays of integers, the elements of each array should be extracted and sticked together to form a String. Once you have both Strings, you can see how they compare to each other.
If our concepts of lexicographically ordered is the same, looks like the problem is that you are using compareTo inverted (list2 compareTo list1 instead of list1 compareTo list2).
After some modifications your code will look like this:
Collections.sort(arrayList, new Comparator<Stack<Integer>>() {
public int compare(Stack<Integer> list1, Stack<Integer> list2) {
int result = 0;
for (int i = 0; i <= list1.size() - 1 && result == 0; i++) {
if (list2.size()-1 < i)
return 1;
else
result = list1.get(i).compareTo(list2.get(i));
}
return result;
}
});
This code will produce the following result: [[1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 3], [1, 1, 1, 3, 1], [1, 1, 3, 1, 1], [1, 1, 3, 3], [1, 3, 1, 1, 1], [1, 3, 1, 3], [1, 3, 3, 1], [1, 4, 4], [3, 1, 1, 1, 1], [3, 1, 1, 3], [3, 1, 3, 1], [3, 3, 1, 1], [3, 3, 3], [4, 1, 4], [4, 4, 1]], that I understand as lexicographically ordered despite of your expected result.
The if (list2.size()-1 < i) inside the for loop prevents an IndexOutOfBoundsException due to list2 being smaller than list1.
Recently I got assigned an assignment that says this:
Write a program named NumberPermutation.java and implement a recursive method specified below:
public static void permutation(int num)
This method has a positive integer as its parameter and displays all permutations of the odd digits of that length.
Display these values in ascending order. For example, if the length is 3, your program should display:
111
113
115
117
119
131
133
135
...
I'm very new to Java (as in all my previous coding assignments for the past year have been in Python and this is the 3rd Java program I've worked on), so I am absolutely lost on where to even get started. If anyone can lend a hand and tell me how to get started I'd appreciate it, thanks.
Although I don't like questions that smell "help me with my homework" I'll provide an answer this time. Here's my suggestion. Please don't just copy and paste and hand in. Understand first, and use this example to understand some of the basics of Java.
public class RecursionTester {
public static void main(String[] args) {
new RecursionTester().permutation(3);
}
private void permutation(int num) {
permutation(num, "");
}
private void permutation(int num, String buffer) {
if (num == 0) {
System.out.println(buffer);
return;
}
for (int i = 1; i < 10; i += 2) {
permutation(num - 1, buffer + Integer.toString(i));
}
}
}
The fact that the results just go to System.out makes this solution pretty useless, but if the task is to only prove that you understand recursion it should be enough.
The map and reduce approach
You can interpret this task as getting the Cartesian product of the n-th number of 2D arrays of odd digits. If n=3 then you get 53=125 combinations.
The mapToObj method prepares 2D arrays for summation and points to the format of the result:
1: {{1}, {3}, {5}, {7}, {9}}
2: {{1}, {3}, {5}, {7}, {9}}
3: {{1}, {3}, {5}, {7}, {9}}
The reduce method sums pairs of 2D arrays into a single 2D array - two steps of reduction if n=3:
1: {{1}, {3}, {5}, {7}, {9}}
2: {{1}, {3}, {5}, {7}, {9}}
---
sum1: {{1, 1}, {1, 3}, {1, 5}, ...}
3: {{1}, {3}, {5}, {7}, {9}}
---
total: {1, 1, 1}, {1, 1, 3}, ...}
Try it online!
public static int[][] cartesianProduct(int n, int[][] arr) {
return IntStream.range(0, n)
// stream of n-th number of 2D arrays
.mapToObj(i -> arr)
// stream of 2D arrays into a single 2D array
.reduce((arr1, arr2) -> Arrays.stream(arr1)
// combinations of rows of two arrays
.flatMap(row1 -> Arrays.stream(arr2)
// concatenate into a single row
.map(row2 -> Stream.of(row1, row2)
.flatMapToInt(Arrays::stream)
// row of a 2D array
.toArray()))
// 2D array of combinations
.toArray(int[][]::new))
// otherwise an empty array
.orElse(new int[0][]);
}
public static void main(String[] args) {
// exponent
int n = 3;
// 2D array of odd digits
int[][] arr = {{1}, {3}, {5}, {7}, {9}};
// cartesian product
int[][] cp = cartesianProduct(n, arr);
// output
System.out.println("Number of combinations: " + cp.length);
// number of rows
int rows = cp.length / arr.length;
// column-wise output
IntStream.range(0, rows)
.mapToObj(i -> IntStream.range(0, cp.length)
.filter(j -> j % rows == i)
.mapToObj(j -> Arrays.toString(cp[j]))
.collect(Collectors.joining(" ")))
.forEach(System.out::println);
}
Output:
Number of combinations: 125
[1, 1, 1] [3, 1, 1] [5, 1, 1] [7, 1, 1] [9, 1, 1]
[1, 1, 3] [3, 1, 3] [5, 1, 3] [7, 1, 3] [9, 1, 3]
[1, 1, 5] [3, 1, 5] [5, 1, 5] [7, 1, 5] [9, 1, 5]
[1, 1, 7] [3, 1, 7] [5, 1, 7] [7, 1, 7] [9, 1, 7]
[1, 1, 9] [3, 1, 9] [5, 1, 9] [7, 1, 9] [9, 1, 9]
[1, 3, 1] [3, 3, 1] [5, 3, 1] [7, 3, 1] [9, 3, 1]
[1, 3, 3] [3, 3, 3] [5, 3, 3] [7, 3, 3] [9, 3, 3]
[1, 3, 5] [3, 3, 5] [5, 3, 5] [7, 3, 5] [9, 3, 5]
[1, 3, 7] [3, 3, 7] [5, 3, 7] [7, 3, 7] [9, 3, 7]
[1, 3, 9] [3, 3, 9] [5, 3, 9] [7, 3, 9] [9, 3, 9]
[1, 5, 1] [3, 5, 1] [5, 5, 1] [7, 5, 1] [9, 5, 1]
[1, 5, 3] [3, 5, 3] [5, 5, 3] [7, 5, 3] [9, 5, 3]
[1, 5, 5] [3, 5, 5] [5, 5, 5] [7, 5, 5] [9, 5, 5]
[1, 5, 7] [3, 5, 7] [5, 5, 7] [7, 5, 7] [9, 5, 7]
[1, 5, 9] [3, 5, 9] [5, 5, 9] [7, 5, 9] [9, 5, 9]
[1, 7, 1] [3, 7, 1] [5, 7, 1] [7, 7, 1] [9, 7, 1]
[1, 7, 3] [3, 7, 3] [5, 7, 3] [7, 7, 3] [9, 7, 3]
[1, 7, 5] [3, 7, 5] [5, 7, 5] [7, 7, 5] [9, 7, 5]
[1, 7, 7] [3, 7, 7] [5, 7, 7] [7, 7, 7] [9, 7, 7]
[1, 7, 9] [3, 7, 9] [5, 7, 9] [7, 7, 9] [9, 7, 9]
[1, 9, 1] [3, 9, 1] [5, 9, 1] [7, 9, 1] [9, 9, 1]
[1, 9, 3] [3, 9, 3] [5, 9, 3] [7, 9, 3] [9, 9, 3]
[1, 9, 5] [3, 9, 5] [5, 9, 5] [7, 9, 5] [9, 9, 5]
[1, 9, 7] [3, 9, 7] [5, 9, 7] [7, 9, 7] [9, 9, 7]
[1, 9, 9] [3, 9, 9] [5, 9, 9] [7, 9, 9] [9, 9, 9]
See also: How do I generate a Cartesian product in Java?
I have written a method to find all combinations n choose k. When I have it void and simply print out the solutions it works fine. However, I am trying to change it as to return a List<List<Integer>> of all the combinations. I tried returning the solution and returning the recursion call in the if-else respectively but I get an error for unreachable line of code. Below I am trying to carry the list of list through the recursion and return it in the end.
public class Combos {
public static void main(String[] args) {
List<Integer> n = new ArrayList<Integer>();
for (int i = 0; i < 9; i++) {
n.add(i);
}
List<Integer> temp = new ArrayList<Integer>();
List<List<Integer>> combos = new ArrayList<List<Integer>>();
// findCombos(n, temp, 3, combos);
System.out.println(findCombos(n, temp, 3, combos));
}
public static List<List<Integer>> findCombos(List<Integer> n, List<Integer> temp, int k, List<List<Integer>> combos) {
if (k == 0) {
//System.out.print(temp);
combos.add(temp);
}
else {
for (int i = 0; i < n.size(); i++) {
temp.add(n.get(i));
List<Integer> subList = n.subList(i + 1, n.size());
findCombos(subList, temp, k - 1, combos);
temp.remove(temp.size() - 1);
}
}
return combos;
}
}
The working void method is here:
package client;
import java.util.ArrayList;
import java.util.List;
public class Combos {
public static void main(String[] args) {
List<Integer> n = new ArrayList<Integer>();
for (int i = 0; i < 5; i++) {
n.add(i);
}
List<Integer> temp = new ArrayList<Integer>();
findCombos(n, temp, 3);
}
public static void findCombos(List<Integer> n, List<Integer> temp, int k) {
if (k == 0) {
System.out.print(temp);
}
else {
for (int i = 0; i < n.size(); i++) {
temp.add(n.get(i));
List<Integer> subList = n.subList(i + 1, n.size());
findCombos(subList, temp, k - 1);
temp.remove(temp.size() - 1);
}
}
}
}
This has to do with the temp List and how it's always the same object when it gets added to combos.
Changing this line will correct that:
if (k == 0) {
combos.add(new ArrayList<Integer>(temp));
}
You have to make a copy because temp is getting mutated. After that, the output is:
[[0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 1, 5], [0, 1, 6], [0, 1, 7], [0, 1, 8], [0, 2, 3], [0, 2, 4], [0, 2, 5], [0, 2, 6], [0, 2, 7], [0, 2, 8], [0, 3, 4], [0, 3, 5], [0, 3, 6], [0, 3, 7], [0, 3, 8], [0, 4, 5], [0, 4, 6], [0, 4, 7], [0, 4, 8], [0, 5, 6], [0, 5, 7], [0, 5, 8], [0, 6, 7], [0, 6, 8], [0, 7, 8], [1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 2, 6], [1, 2, 7], [1, 2, 8], [1, 3, 4], [1, 3, 5], [1, 3, 6], [1, 3, 7], [1, 3, 8], [1, 4, 5], [1, 4, 6], [1, 4, 7], [1, 4, 8], [1, 5, 6], [1, 5, 7], [1, 5, 8], [1, 6, 7], [1, 6, 8], [1, 7, 8], [2, 3, 4], [2, 3, 5], [2, 3, 6], [2, 3, 7], [2, 3, 8], [2, 4, 5], [2, 4, 6], [2, 4, 7], [2, 4, 8], [2, 5, 6], [2, 5, 7], [2, 5, 8], [2, 6, 7], [2, 6, 8], [2, 7, 8], [3, 4, 5], [3, 4, 6], [3, 4, 7], [3, 4, 8], [3, 5, 6], [3, 5, 7], [3, 5, 8], [3, 6, 7], [3, 6, 8], [3, 7, 8], [4, 5, 6], [4, 5, 7], [4, 5, 8], [4, 6, 7], [4, 6, 8], [4, 7, 8], [5, 6, 7], [5, 6, 8], [5, 7, 8], [6, 7, 8]]
As an example of what is happening, if k is 1, we can follow the logic through for a couple of steps:
// k is 1 so call findCombos with 0
findCombos(subList, temp, k - 1, combos);
// k is 0 so add temp to combos
if (k == 0) {
combos.add(temp);
}
// on return, immediately mutate temp
temp.remove(temp.size() - 1);