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]]
Related
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;
}
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/
I'm trying to implement selection sort using generics. To do that I receive a comparator (Because I wanted to use the method Comparator#naturalOrder() while testing).
The problem is that when calling it with a Double array it does not work, but when calling it with an Integer array instead, it works.
Here is the selection sort implementation I made:
public static<V> void selectionSort(V[] arr, Comparator<V> cmp){
if (arr == null)
throw new IllegalArgumentException("Invalid array, can't be sorted");
int minIndex = -1;
for(int i = 0, j; i<arr.length; i++){
for (j = i; j<arr.length;j++){
if (minIndex == -1 || cmp.compare(arr[minIndex],arr[j])>0){
minIndex = j;
}
}
swap(arr, i, minIndex);
}
}
private static<V> void swap(V[] arr, int i, int j) {
V aux = arr[i];
arr[i]=arr[j];
arr[j]=aux;
}
Here is the test that's failing:
#Test
public void selectionSortDoubleTest(){
arrDouble = new Double[]{5.5,2.5,1.2,8.0};
SelectionSort.selectionSort(arrDouble, Comparator.naturalOrder());
Assert.assertArrayEquals(new Double[]{1.2,2.5,5.5,8.0}, arrDouble);
}
And here is the test that works:
#Test
public void selectionSortIntegerTest(){
arr = new Integer[]{2,5,7,1};
SelectionSort.selectionSort(arr, Comparator.naturalOrder());
Assert.assertArrayEquals(new Integer[]{1, 2, 5, 7},arr);
}
The weird part is that in the first test the arrays differ at position [1], so both start with 1.2, but then arrDouble[1] is 8.0 which doesn't make any sense.
The assertion error message I receive:
Arrays first differed at element [1];
Expected :2.5
Actual :8.0
minIndex must be reset to -1 at each iteration of the outer loop. Otherwise you swap the previously found min element with the new one. Using a debugger makes it quite easy to spot such mistakes.
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;
}
I am trying for too long to figure out this exersies but I am stuck here. I need to write a boolean method that will an array as argument and should return true if numbers in array are in decreasing order. Bu any time that I am trying I am having the same value or errors. Here is my code:
public class Question1c{
public static void main (String[] args){
int[] arr = {1, 9, 3, 4, 5, 6};
boolean product = isDecreasing(arr);
System.out.println(product);
}
public static boolean isDecreasing (int[] numbers){
int first = numbers[0];
for (int i : numbers){
if(first <= i){
first = i;
return true;
}
//else{
// return false;
//}
}return false;
}
}
The problem in your code is that you cannot return true until after you went through the entire array. However, you can return false as soon as you detect an "inversion" - i.e. a situation when the number that follows the one you've seen before is greater than the prior number.
You are reasonably close to a working solution - you need to remove return true, uncomment the else, and change the final return false to return true.
To make your code more readable, rename first to prior. Also consider changing the "foreach" version of the for loop to a regular for loop that skips the initial element of the array. This would let you detect decreasing order, as opposed to non-increasing, which you currently detect.
Not sure I understand, but wouldn't this solve your issue?
public class Question1c{
public static void main (String[] args){
int[] arr = {1, 9, 3, 4, 5, 6};
boolean product = isDecreasing(arr);
System.out.println(product);
}
public static boolean isDecreasing (int[] numbers){
for (int i = 0; i < numbers.Length; i++){
if (i == 0)
continue;
if (numbers[i - 1] >= numbers[i])
return false;
}
return true;
}
}
You're essentially just aiming to check that the previous item in the array isn't greater than or equal to the current item in the array, aren't you?
You initialize first with numbers[0] this causes several problems:
An empty array throws IndexOutOfBoundsException
the first check automatically passes (numbers[0] <= numbers[0])
you best check the length of numbers for 0 and use a "normal" for loop (using an index).
Your return values is also the negation of what it should be.
This might solve your issue.
public class Question{
public static void main (String[] args){
int[] arr = {1, 9, 3, 4, 5, 6};
boolean product = isDecreasing(arr);
System.out.println(product);
}
public static boolean isDecreasing (int[] numbers){
int first = numbers[0];
for (int i = 1; i < numbers.length ; i++) {
if (first <= numbers[i]) {
return false;
}
first = numbers[i];
}
return true;
}
}