I'm trying to solve a leetcode problem https://leetcode.com/problems/combination-sum/
I have to find out all the combinations (A combination is stored in an ArrayList) that add to a specified number. I have to store all the Combinations (ArrayLists) in an ArrayList. So I will have ArrayList of ArrayList (call it "ans").
But I am not able to add any combinations to this ans ArrayList. I am able to print out all the combinations but I have to return it in a 2d ArrayList only. The ans list is returning only empty lists at the end of the code flow.
I am attaching my code below
class Solution {
int[] candidates;
ArrayList<List<Integer>> ans;
void f(int index, int target, ArrayList<Integer> current){
if (target == 0){
System.out.println(current);
this.ans.add(current);
return;
}
if (target < 0) return;
for(int i = index; i < candidates.length; i++){
current.add(candidates[i]);
target -= candidates[i];
f(i, target, current);
target += candidates[i];
current.remove(current.size()-1);
}
}
public List<List<Integer>> combinationSum(int[] candidates, int target) {
this.ans = new ArrayList<List<Integer>>();
this.candidates = candidates;
f(0, target, new ArrayList<>());
return this.ans;
}
}
Input: [2,3,6,7] 7
Output (contents of ans): [[],[]]
StdOut: [2, 2, 3] [7]
#OH GOD SPIDERS, Thanks!;
This is happening because I am not passing a copy of the current combination to the ans List.
I had to alter the basecase to
if (target == 0){
this.ans.add(new ArrayList(current));
return;
}
Related
I have written some code to try to solve this challenge, but its not working, i can't seem to figure out where it went wrong, i can find the answer online but that's not the point i'm trying to see why my code doesn't work.
question:
Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
The same repeated number may be chosen from candidates unlimited number of times.
Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
[7],
[2,2,3]
]
this is what i have came up with:
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
helper(res,new ArrayList<Integer>(), candidates,target,0,0);
return res;
}
//current = current sum, we want it to be target
//start is index we are at and where the for loop starts
public void helper(List<List<Integer>> res, List<Integer> temp, int[] nums, int target, int current, int start){
if(start>=nums.length){
return;
}
if(current>=target){
if(current==target){
res.add(new ArrayList<>(temp));
}
temp.remove(temp.size()-1);
helper(res,temp,nums,target,current-nums[start],start+1);
return;
}
for(int i=start; i<nums.length; i++){
temp.add(nums[i]);
helper(res,temp,nums,target,current+nums[i],start);
}
}
}
explanation of my code:
so i am trying to use recursion backtracking here. i keep for looping an element in the array till the sum is >= target.if its >target i remove the last element since that made it bigger than target and try the other ones. if its = target i add it to result and i remove last element to try find more combinations.
but apparently i am getting error in this line:
temp.remove(temp.size()-1); //saying index out of bounds i am trying to remove when arraylist is empty
so it isnt running how i thought, because if the list is empty current should be 0 and it should even enter that if loop and should never be removed but it is and i am not sure why.
thanks.
The main issue if from trying to roll back the current variable value and call the helper method again from there in the if(current>=target) if statement. You can use the for loop to automatically do that for you and remove the added number after it returns. Then using the functions return to update the start value so that it will continue from where you left off will eliminate duplicates.
And because of the for loop num[i] will never go out of bounds so you dont have to worry about
if(start>=nums.length){
return;
}
This is the working version using your solution method
public static List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
helper(res,new ArrayList<Integer>(), candidates,target,0,0);
return res;
}
public static int helper(List<List<Integer>> res, List<Integer> temp, int[] nums, int target, int current, int start){
if(current>=target){
if(current==target){
res.add(new ArrayList<>(temp));
}
return start + 1;
}
for(int i=start; i<nums.length; i++){
temp.add(nums[i]);
start = helper(res,temp,nums,target,current+nums[i],start);
temp.remove(temp.size()-1);
}
return start;
}
Running the code:
public static void main(String []args){
List<List<Integer>> res = combinationSum(new int[] {2,3,6,7}, 7);
System.out.println(res);
}
Result:
[[2, 2, 3], [7]]
Try this.
static List<List<Integer>> combinationSum(int[] candidates, int target) {
int size = candidates.length;
List<List<Integer>> result = new ArrayList<>();
new Object() {
void search(int index, int sum, List<Integer> selected) {
if (index >= size) {
if (sum == target)
result.add(new ArrayList<>(selected));
} else {
int candidate = candidates[index];
List<Integer> nextSelected = new ArrayList<>(selected);
for (int nextSum = sum; nextSum <= target; nextSum += candidate, nextSelected.add(candidate))
search(index + 1, nextSum, nextSelected);
}
}
}.search(0, 0, new ArrayList<>());
return result;
}
and
int[] candidates = {2, 3, 6, 7};
int target = 7;
List<List<Integer>> result = combinationSum(candidates, target);
System.out.println(result);
result:
[[7], [2, 2, 3]]
What's the time complexity of my code? I ran this through www.leetcode.com and it's optimal. I think its O(n*n!). First I thought it was O(n^2*n!) : The extra n since we make n recursive calls. However, only the first call to permute() is dominant, and kind of dwarfs the rest since n! is >>> (n-1)!
Thanks upfront!
class Solution {
public List<List<Integer>> permute(int[] nums) {
return permute(nums, nums.length - 1);
}
private List<List<Integer>> permute(int[] nums, int n) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if(n < 0) {
List<Integer> permutation = new ArrayList<Integer>();
result.add(permutation);
return result;
}
// below returns (n-1)! results of size n-1 each
List<List<Integer>> prefixes = permute(nums, n-1);
for(List<Integer> prefix : prefixes) {
List<List<Integer>> permutations = insert(nums[n], prefix);
result.addAll(permutations);
}
return result;
}
// O(n^2) worst case when size of list is n-1
private List<List<Integer>> insert(int num, List<Integer> list) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
for(int i = 0; i <= list.size(); i++) {
List<Integer> clone = new ArrayList<Integer>();
clone.addAll(list);
clone.add(i, num);
result.add(clone);
}
return result;
}
}
I think this question might be more suited to https://codereview.stackexchange.com/
How would you solve the following task:
Write a recursive method which gets passed an array, filters all odd numbers and store them into an array. The returned array has to be sorted by each elements order.
You are not allowed to use any provided methods by java classes like Arrays.sort, Lists, etc. Furthermore loops are disallowed and generic well known sort algorithm applied to the result as well.
The part of filtering is easy, but I don't know how to put each element at its right place. At the moment my method only returns an unsorted array with all odd numbers.
public static int[] filterOdd(int[] m){
return filterOdd(m, 0, 0);
}
private static int[] filterOdd(int[] m, int idx, int idxToPlace){
if(idx <= m.length -1){
if(m[idx] % 2 == 0){
return filterOdd(m, idx + 1, idxToPlace);
}else{
int[] buffer = filterOdd(m, idx + 1, idxToPlace + 1);
buffer[idxToPlace] = m[idx];
return buffer;
}
}else{
return new int[numberOfOddIntegers(m)];
}
}
Is there any way to insert the odd number at its right place recursively?
At the place where you do buffer[idxToPlace] = m[idx]; you have to call another method that will return the sorted array with the current processing number added to it.
That new method can be recursive too: you know at that moment that the array you have in your hands is ordered. You just recursively traverse (for example from the end to the begin) and from the moment your element fits in (e.g. is smaller than the previous element) you can insert it and return the sorted array. If there is only 1 element (base case) you can just return it.
That way, at the end of your algorithm, the list will be sorted.
I'm not allowed to use System.arraycopy
This means that you need to figure out how many odd numbers you are going to have, in order to size your result properly:
public static int[] filterOdd(int[] m){
int[] res = new int[countOdd(m, 0)];
filterOdd(m, 0, 0, res);
return res;
}
private static int countOdd(int[] m, int i) {
if (i == m.length) {
return 0;
}
int isOdd = m[i] % 2 != 0 ? 1 : 0;
return isOdd + countOdd(m, i+1);
}
private static void filterOdd(int[] m, int src, int dest, int[] res){
if(src == m.length) {
return;
}
if (m[src] % 2 != 0) {
res[dest++] = m[src];
}
filterOdd(m, src+1, dest, res);
}
I have a 2D array
int[][] lists=new int[][]{{22, 23},{34, 35},{47, 15}};
I have to get all combinations of each elements in every rows, like this:
int [][] result= {{22,34,47},{22,34,15},{22,35,47},{22,35,15},{23,34,47},{23,34,15},{23,35,47},{23,35,15}}
Then for each rows from the newest array I have to calculate average. For this I create a method average(int[]a).
All I need is to get only those combinations with highest average.
Because my initial array can have a large number of rows/columns, I'm trying to generate each combination and check if it's average is higher then memorate it.
Here is my code, but obviously it doesn't work. Can someone help me?
public static int average(int[]a)
{
int sum=0;
for(int i=0;i<a.length;i++)sum+=a[i];
return sum/a.length;
}
public static void cartesian(int[][] lists, int[] values, int n)
{
int sum=0;
List<List<Integer>> result = new ArrayList<List<Integer>>();
if (n == lists.length) {
if(average(values)>sum) {
result.clear();
result.add(Arrays.stream(values).boxed().collect(java.util.stream.Collectors.toList()));
sum=average(values);}
}
else
{
for(int i: lists[n]) {
values[n] = i;
cartesian(lists, values, n+1);
}
}
return result;
}
public static void main(String[] args)
{
List<List<Integer>> result = cartesian(lists, new int[lists.length], 0);
for(List<Integer> i: result) System.out.println(i);
}
I think there are a couple errors of logic in your cartesian code. From what I can tell, that is the function that determines what array has the highest average. First of all, in the statement
int sum=0;
List<List<Integer>> result = new ArrayList<List<Integer>>();
if (n == lists.length) {
if(average(values)>sum) {
The last line is irrelevant - you've defined sum so that if your values aren't negative the if statement will always be true. Also, later in the code,
else
{
for(int i: lists[n]) {
values[n] = i;
cartesian(lists, values, n+1);
}
I think you meant to put cartesian(lists, values, n+1) outside of the for loop. Here is how I would rewrite this code:
public static void cartesian(int[][] lists, int[] values, int n)
{
int sum=0;
List<List<Integer>> result = new ArrayList<List<Integer>>();
int[] totest = lists[n];
if(average(totest) > average(values) || r.equals(null)) {
result.clear();
result.add(Arrays.stream(totest).boxed().collect(java.util.stream.Collectors.toList()));
if(n != lists.length - 1){cartesian(lists, totest, n + 1)};
}
else
{
if(n != lists.length - 1){cartesian(lists, totest, n + 1)};
}
return result;
}
Just practicing some sorting algorithms. I tried to implement a recursive merge sort, but there seems to be a problem with getting a new pivot for each recursive call.
I feel like my code should be working... but I'm new to using ArrayList as a data structure... and only have experience with arrays. I needed a dynamic-sized array, so I'm using an ArrayList.
It just keeps spitting out pivot = 1 until it overflows:
pivot: 1
pivot: 1
pivot: 1
pivot: 1
pivot: 1
...
Exception in thread "main" java.lang.StackOverflowError
code:
import java.util.*;
public class Sorts{
static Sorts run;
List<Integer> initialList = new ArrayList<Integer>();
public Sorts() {
//List<Integer> initialList = new ArrayList<Integer>();
initialList.add(1);
initialList.add(4);
initialList.add(8);
initialList.add(2);
initialList.add(3);
initialList.add(7);
initialList.add(9);
System.out.print("List of values: (");
for (int value: initialList) {
System.out.print(value);
}
System.out.println(")");
//output sorted array
System.out.println("Sorted list: " + mergeSort(initialList));
}
public List<Integer> mergeSort(List<Integer> list) {
if (list.size() <= 1) {
return list;
}
//after each recursion, generate two new sub lists
List<Integer> left = new ArrayList<Integer>();
List<Integer> right = new ArrayList<Integer>();
//generate new pivot for each new list
int middle = list.size()/2;
System.out.println("middle: " + middle);
int i = 0;
for (int x: list) {
if (i < middle) {
left.add(x);
}
else {
right.add(x);
}
i++;
}
//call mergeSort, passing in each new sublist (left, right)
left = mergeSort(left);
right = mergeSort(right);
return mergeLists(left, right);
}
public List<Integer> mergeLists (List<Integer> left, List<Integer> right) {
List<Integer> sortedList = new ArrayList<Integer>();
int i = 0;
while (left.size() > 0 || right.size() > 0) {
if (left.size() > 0 && right.size() > 0) {
if (left.get(i) <= right.get(i)) {
sortedList.add(left.get(i));
}
else {
sortedList.add(right.get(i));
}
}
else if (left.size() > 0) {
sortedList.add(left.get(i));
}
else if (right.size() > 0) {
sortedList.add(right.get(i));
}
}
for (int value : sortedList) {
System.out.println(value);
}
return sortedList;
}
public static void main(String []args){
run = new Sorts();
}
}
Any thoughts? Am I using the ArrayList incorrectly?
Thanks!
The problem is that you're splitting the list in the wrong way:
for (int i: initialList) {
if (i < pivot) {
left.add(i);
}
else {
right.add(i);
}
}
i is the element in initialList, not the index of the element. Change this to:
int i = 0;
for (int x: initialList) {
if (i < pivot) {
left.add(x);
}
else {
right.add(x);
}
i++;
}
For any downvoter: I've tested this and worked :).
Also, there's a problem in your merge algorithm. You should merge both lists while sorting the elements but you're just inserting the values of left and then the values of right (but maybe could be for test purposes).
Based on your edit, now you have a new problem when getting the pivot:
int pivot = list.get(list.size()/2);
This should be as you posted in original code:
int pivot = initialList.size()/2;
Note that people might be telling you some odd advices since pivot is used in QuickSort and you just use middle or mid in MergeSort
Take a look at http://en.wikipedia.org/wiki/Merge_sort
You don't need to compare with pivot, it is not a partition sort you're implementing. Just split the list in two, something like this.
left = list.sublist(0, pivot);
right = list.sublist(pivot, list.length())