I am trying to add the squared elements for back into the original arraylist. For example [1,2,3] should become [1, 1, 2, 4, 3, 9]. My issue is I am not sure if my machine is just bad because I am getting an out of memory error. Here is my attempt. The recursive call is just to get the sum of the arraylist.
public static int sumOfSquares(List<Integer> num) {
if (num.isEmpty()) {
return 0;
}
for(int i=0; i<num.size();i++){
int hold= num.get(i)*num.get(i);
num.add(hold);
}
return num.get(0) + sumOfSquares(num.subList(1, num.size()));
}
The problem with your implementation is that it does not distinguish original numbers from the squares that you have previously added.
First, since you are doing this recursively, you don't need a for loop. Each invocation needs to take care of the initial value of the list alone.
Next, add(n) adds the number at the end, while your example shows adding numbers immediately after the original value. Therefore, you should use num.add(1, hold), and skip two initial numbers when making a recursive call.
Here is how the fixed method should look:
public static int sumOfSquares(List<Integer> num) {
if (num.isEmpty()) {
return 0;
}
// Deal with only the initial element
int hold= num.get(0)*num.get(0);
// Insert at position 1, right after the squared number
num.add(1, hold);
// Truncate two initial numbers, the value and its square:
return num.get(1) + sumOfSquares(num.subList(2, num.size()));
}
Demo.
There are two ways to safely add (or remove) elements to a list while iterating it:
Iterate backwards over the list, so that the indexes of the upcoming elements don't shift.
Use an Iterator or ListIterator.
You can fix your code using either strategy, but I recommend a ListIterator for readable code.
import java.util.ListIterator;
public static void insertSquares(List<Integer> num) {
ListIterator<Integer> iter = num.listIterator();
while (iter.hasNext()) {
int value = iter.next();
iter.add(value * value);
}
}
Then, move the summing code into a separate method so that the recursion doesn't interfere with the inserting of squares into the list. Your recursive solution will work, but an iterative solution would be more efficient for Java.
Related
I was trying this problem where we need to find the permutations of the elements in the array.
This is the leetcode problem no 46. The issue I've faced is that I'm not able to output the ans it just keeps returning a blank ArrayLists:
Code:
public List<List<Integer>> permute(int[] nums)
{
List<List<Integer>> fans = new ArrayList<>();
HashMap<Integer, Integer> fmap = new HashMap<>();
for(int i: nums){
fmap.put(i, fmap.getOrDefault(i, 0) + 1);
}
int n=nums.length;
List<Integer> ans=new ArrayList<>(n);
dfs(1, n, fmap, ans, fans);
return fans;
}
public void dfs(int cs, int ts, HashMap<Integer, Integer> fmap,List<Integer> ans, List<List<Integer>> fans)
{
if (cs > ts)
{
fans.add(ans);
return;
}
for(Integer val: fmap.keySet())
{
if (fmap.get(val) > 0)
{
fmap.put(val, fmap.get(val) - 1);
ans.add(val);
dfs(cs + 1, ts, fmap, ans, fans);
ans.remove(ans.size() - 1);
fmap.put(val, fmap.get(val) + 1);
}
}
}
Output for the test case [0,1]:
[[],[]]
The actual output should be:
[[0,1],[1,0]]
When I'm checking the "potential answer" inside the recursive method, I am able to see the correct answer. I mean, if I print the output in the dfs method, it shows the correct answer:
Change in the code:
if (cs > ts)
{
fans.add(ans);
System.out.println(fans);
return;
}
Now it's printing the value of fans:
[[0, 1]]
[[1, 0], [1, 0]]
But these values are not being updated in the fans and the returned value comes up blank.
I read someone mention this same issue, but it was for Python, and the solution in that case was to do a deep copy of the list.
I'm not sure how to do that in Java.
What I'm doing wrong?
In order to generate a list of permutations, you don't need a Map. You've only introduced redundant actions, which are not useful anyhow. If you doubt, add a couple of print-statements to visualize the map state it will always contain the same key with the value 1 (all numbers in the input are guaranteed to be unique) and it has no impact on the result.
Source of data for generating the Permutations
Besides the fact that attempt to utilize the HashMap as the source of data for generating permutations isn't working because of the bugs, it's also not a good idea because the order iteration over the keySet of HashMap is not guaranteed to be consistent.
As the uniform mean for storing the numbers that haven't yet been applied in current permutation, we can use an ArrayList. In this case because there will be no duplicates in the input (see the quote from the leetcode below), we can use a LinkedHashSet instead to improve performance. As explained below, a removal of elements will happen at before making every recursive a call, and removal from an ArrayList has a cost of O(n), meanwhile with LinkedHashSet it would be reduced to O(1).
Constraints:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
All the integers of nums are unique.
Generating the Permutations
Each generated permutation should be contained in its own list. In your code, you've created one single list which is being passed around during recursive calls and eventually every recursive branch adds the same list to the resulting list. Which obviously should not happen.
You see, the result is being printed as [[],[]]. It seems like a list containing two lists, but in fact they refer to the same empty list.
And this list is empty because every element that was added to it, is being removed after performing a recursive call:
ans.add(val);
... <- rursive call in between
ans.remove(ans.size() - 1); // removes the last element
if I print the output in the dfs method, it shows the correct answer:
Actually, it's not correct. If you take a careful look at the results, you'll see the nested lists are the same [[1, 0], [1, 0]].
The final result is blank because all recursive calls are happening between each value being added and removed (see the code snippet above). I.e. removal will be performed in revered order. That would be the last lines to be executed, not the return statements. To understand it better, I suggest you to walk through the code line by line and draw on paper all the changes done to the ans list for a simple input like [0, 1].
Instead, you should create a copy of the list containing not fully generated permutation (answer) and then add an element into the copy. So that the initial permutation (answer) remains unaffected and can be used as a template in all subsequent iterations.
List<Integer> updatedAnswer = new ArrayList<>(answer);
updatedAnswer.add(next);
And you also need to create a copy of the source of data and remove the element added to the newly created permutation (answer) in order to avoid repeating this element:
Set<Integer> updatedSource = new LinkedHashSet<>(source);
updatedSource.remove(next);
Sidenote: it's a good practice to give meaningful names to methods and variables. For instance, names cs and ts aren't informative (it's not clear what they are meant to store without looking at the code), method-name dfs is confusing, DFS is a well-known algorithm, which is used for traversing tree or graph data structures, but it's not related to this problem.
Building a recursive solution
It makes sense to keep the recursive method to be void to avoid wrapping the result with an additional list that would be thrown away afterwards, but in general it's more handy to return the result rather than accumulating it in the parameter. For performance reasons, I'll keep the method to be void.
Every recursive implementation should contain two parts:
Base case - that represents a simple edge-case (or a set of edge-cases) for which the outcome is known in advance. For this problem the base case would represent a situation when the given permutation has reached the size of the initial array, i.e. the source will contain no element, and we need to check whether it's empty or not. Parameters cs and ts that were used for this check in the solution provided in the question are redundant.
Recursive case - a part of a solution where recursive calls a made and when the main logic resides. In the recursive case, we need to replicate the given answer and source as explained above and use the updated copies as the arguments for each recursive call.
That's how it might be implemented:
public static List<List<Integer>> permute(int[] nums) {
Set<Integer> source = new LinkedHashSet<>();
for (int next: nums) source.add(next);
List<List<Integer>> result = new ArrayList<>();
permute(source, new ArrayList<>(), result);
return result;
}
public static void permute(Set<Integer> source, List<Integer> answer,
List<List<Integer>> result) {
if (source.isEmpty()) {
result.add(answer);
return;
}
for (Integer next: source) {
List<Integer> updatedAnswer = new ArrayList<>(answer);
updatedAnswer.add(next);
Set<Integer> updatedSource = new LinkedHashSet<>(source);
updatedSource.remove(next);
permute(updatedSource, updatedAnswer, result);
}
}
main()
public static void main(String[] args) {
int[] source = {1, 2, 3};
List<List<Integer>> permutations = permute(source);
for (List<Integer> permutation: permutations) {
System.out.println(permutation);
}
}
Output:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
A link to Online Demo
I am having trouble solving this recursion problem. Recursion is quite difficult to understand and be able to code as I am new to coding. The problem is to write a recursive method to find every possible sub-list of a given list. Your method should accept a list of strings as a parameter and print every sub-list that could be created from elements of that list, one per line. Assume there is no duplicates and the list is not null. Do not use any loops.
The only possible way I can think of doing this is with a for loop or use more parameters but I can't per instructions. This is what I have so far. I checked the list api it says there is a subList method you can use. I was able to print the first 5 possible sublists just by substracting -1 from the list size every recursion and then I get an index error. This is very frustrating so if anyone has any tips or pointers that would greatly be appreciated.
If you can possibly solve it with loops, I'd love to see how you would solve it.
public static void main(String[]args){
ArrayList<String> list = new ArrayList<>(List.of("Janet", "Robert", "Morgan", "Char"));
subsets(list);
}
public static void subsets(List<String> list) {
int n = list.size();
if(list.isEmpty()){
System.out.println(list);
}
if(n > 0){
System.out.println(list.subList(0 , n));
}
subsets(list.subList(0,n -1));
}
Results of my code
The best solution I came up with is based on randomness, I'll post in even though it is not what is expected by the Java Programming textbook.
You can calculate how many distinct k-combinations of K elements exists in a list of N elements.
For example:
One combination of 4 elements exists in a list of 4
4 combinations of 3 elements exist in a list of 4.
The idea is to have as args of the recursive method:
The initial list you want to extract sublists
A list of every sublist already printed
The number K of elements of the wanted sublist size
You should then have the following method signature:
public static void subsets(List<String> list, ArrayList<List<String>> alreadyPrinted, int nbOfElementsInTheSubList);
and the call in your main method will be
subsets(list, new ArrayList<>(), list.size());
Now in the body of the recursive method, process as follow (pseudo-code)
Pick a sublist of nbOfElementsInTheSubList random elements from list that is not in alreadyPrinted, print it, and add it to alreadyPrinted
compute combinationNumber = list.size() choose nbOfElementsInTheSubList (ie: the number of nbOfElementsInTheSubList-combination in list)
compare it to alreadyThere, the number of combination of nbOfElementsInTheSubList elements presents in alreadyPrinted
if alreadyThere = combinationNumber : You have all the nbOfElementsInTheSubList-Combination available in list, you can call recursively your method using (nbOfElementsInTheSubList - 1) as the last arg
else : You are missing at least one of the nbOfElementsInTheSubList-Combination available in list. Call subset again using the same nbOfElementsInTheSubList but with the updated alreadyPrinted
I doubt this is an optimal solution, so I bookmarked your topic since I am sincerely curious about the expected code.
If we want to permutate all the value in the list then we can use this code->
public static void main(String[] args) {
List<String> list = Arrays.asList("Janet", "Robert", "Morgan", "Char");
recursiveprint(list, new boolean[list.size()], "");
}
private static void recursiveprint(List<String> list, boolean b[], String s) {
System.out.println(s);
for (int j = 0; j < list.size(); j++) {
if (b[j] == false) {
b[j] = true;
recursiveprint(list, b, s + list.get(j)+" ");
b[j] = false;
}
}
}
Is there a better way to remove dups from the array list compared to the below code which does the work in O(n) when encountered with larger input. Any suggestions would be appreciated. Thank you.
Note :- Can't use any extra space and should be solved in place.
Input :- It will be a sorted array with dups.
Code :-
public int removeDuplicates(ArrayList<Integer> a) {
if(a.size()>1){
for( int i=0;i<a.size()-1;i++ ) {
if(a.get(i).intValue() == a.get(i+1).intValue() ) {
a.remove(i);
i--;
}
}
}
return a.size();
}
Please test the code here at coder pad link.
https://coderpad.io/MXNFGTJC
If this code is for removing elements of an unsorted list, then:
The algorithm is incorrect.
The Question is a duplicate of How do I remove repeated elements from ArrayList? (for example ...)
If the list is sorted, then:
The algorithm is correct.
The algorithm is NOT O(N). It is actually O(ND) on average where N is the list length and D is the number of duplicates.
Why? Because ArrayList::remove(int) is an on average O(N) operation!
There are two efficient ways to remove a large number of elements from a list:
Create a new list, iterate the old list and add the elements that you want to retain to the new list. Then either discard the old list or clear it and copy the new list to the old one.
This works efficiently (O(N)) for all standard kinds of list.
Perform a sliding window removal. The algorithm with arrays is like this:
int i = 0;
for (int j = 0; j < array.length; j++) {
if (should remove array[j]) {
// do nothing
} else {
array[i++] = array[j];
}
}
// trim array to length i, or assign nulls or something.
As you can see, this performs one pass through the array, and is O(N). It also avoids allocating any temporary space.
You can implement the sliding window removal using ArrayList::get(int) and ArrayList::set(int, <E>) ... followed by repeated removal of the last element to trim the list.
Here are some ideas to improve performance:
Removing elements one by one from an ArrayList can be expensive since you must shift the all contents after that element. Instead of ArrayList you might consider a different list implementation which allows O(1) removal. Alternatively, if you must use ArrayList and are not allowed any temporary data structures, you can rebuild the array by chaining together recursive calls that use set() instead of remove().
For lists with millions of elements, consider a parallel processing solution to leverage the power of multiple processes. Java streams are a simple way to achieve this.
List<Integer> l = new ArrayList<Integer>();
//add some elements to l
System.out.println(l.stream().distinct().collect(Collectors.toList()));
Is there a way i could return in an array the common elements of 2 or more arrays? I know having some of the methods under lists could do it but is there a way to do it by only using arrays? I made my own get and length btw since i am creating a an array called OrderedIntList.
Example would be:
1,3,5
1,6,7,9,3
1,3,10,11
Result: 1,3
I tried this and it outputs the common elements between two arrays and not all.
I know there's something wrong but i do not how to make it work like it suppose to work :(
//returns the common elements of inputted arrays
public static OrderedIntList common(OrderedIntList ... lists){
int[] list = new int[10];
for(int x = 1; x <= lists.length -1; x++){
for(int q = 0; q < lists[0].length()-1; q++) {
for(int z = 0; z < lists[x].length(); z++) {
if (lists[0].get(q)==lists[x].get(z)){
list[q] = lists[0].get(q);
}
}
}
}
OrderedIntList newlist = new OrderedIntList(list);
return newlist;
}
This can be an easy algorithm to solve it...
1) Instantiate an instance variable of type array called
"commonElements" pointing to the elements of the first Array. At the
beginning these are your common elements.
2) Create a method call getCommonElements(int[] commonElements,
int[] newList). This method manipulates the commonElements array to leave
it with only the common elements between the two. (p.s Use a temporary
array to achieve this if you find it easier)
3) Iterate over all the arrays present in "lists" starting from the
second array.
4) call the method at point 2 for each array .
All the difficult part for you it's to implement a method that given 2 arrays finds the common elements!
You can use
org.apache.commons.collections.CollectionUtils.intersection(java.util.Collection a, java.util.Collection b)
to get the intersection of two lists (elements presents in both lists)
And to pass your array as a Collection: java.util.Arrays.asList(Object[] a);
But working on arrays is tedious, at best. You should consider why you don't want to use a Collection...
As a partial answer, you're probably doing too much work by fully reimplementing an OrderedIntList the way you're doing, since ArrayList and friends already come with sorting baked in via the Collections class.
import java.util.Collections;
public class OrderedIntList extends ArrayList<Integer> {
#override // to effect sorted inserts
public void add(Integer i) {
this.add(i);
Collections.sort(this);
// done.
}
}
Wanting to do this for pure arrays is a nice exercise, but then you'll be better of implementing sorting properly with a quick sort (you can't websearch for a java implementation of that without getting a million results) or an insert sort (equally websearchable), and follow the same recipe.
any time you push a number into the array:
guess where the number goes (although that's optional),
insert the number,
resort your array if you know your guess wasn't perfect.
I have a method that returns an integer value or integer range (initial..final) and I want to know if values are all disjoint.
Is there a more efficient solution than the following one:
ArrayList<Integer> list = new ArrayList<Integer>();
// For single value
int value;
if(!list.contains(value))
list.add(value);
else
error("",null);
// Range
int initialValue,finalValue;
for(int i = initialValue; i <= finalValue; i++){
if(!list.contains(i))
list.add(i);
else
error("",null);
}
Finding a value (contains) in HashSet is a constant-time operation (O(1)) on average, which is better than a List, where contains is linear (O(n)). So, if your lists are large enough, it may be worthwhile to replace your first line with:
HashSet<Integer> list = new HashSet<Integer>();
The reason for this is that to find a value in an (unsorted) list, you need to check every index in the list until you find the one you want or run out of indexes to check. On average you'll check half the list before finding a value if the value is in the list, or the whole list if it's not. For a hash table, you generate an index from the value you want to find, then you check that one index (it's possible you need to check more than one, but it should be uncommon in a well-designed hash table).
Also, if you use a Set, you get a guarantee that each value is unique, so if you try to add a value that already exists, add will return false. You can use that to slightly simplify the code (note: This will not work if you use a List, because add always returns true on a List):
HashSet<Integer> list = new HashSet<Integer>();
int value;
if(!list.add(value))
error("",null);
Problems involving ranges often lend themselves to the use of a tree. Here's a way to do that using TreeSet:
public class DisjointChecker {
private final NavigableSet<Integer> integers = new TreeSet<Integer>();
public boolean check(int value) {
return integers.add(value);
}
public boolean check(int from, int to) {
NavigableSet<Integer> range = integers.subSet(from, true, to, true);
if (range.isEmpty()) {
addRange(from, to);
return true;
}
else {
return false;
}
}
private void addRange(int from, int to) {
for (int i = from; i <= to; ++i) {
integers.add(i);
}
}
}
Here, rather than calling an error handler, the check methods return a boolean indicating whether the arguments were disjoint from all previous arguments. The semantics of the range version are different to in the original code; if the range is not disjoint, none of the elements are added, whereas in the original, any below the first non-disjoint element are added.
A few points may deserve elaboration:
Set::add returns a boolean indicating whether the addition modified the set; we can use that as the return value from the method.
NavigableSet is an obscure but standard subinterface of SortedSet which is sadly neglected. Although you could actually use a plain SortedSet here with only minor modifications.
The NavigableSet::subSet method (like SortedSet::subSet) returns a lightweight view on the underlying set which is restricted to a given range. This provides a very efficient way to query the tree for any overlap with the whole range in one operation.
The addRange method here is very simple, and runs in O(m log n) when adding m items to a checker which has seen n items previously. It would be possible to make a version which ran in O(m) by writing an implementation of SortedSet which described a range of integers and then using Set::addAll, because TreeSet's implementation of this contains a special case for adding other SortedSets in linear time. The code for that special set implementation is very simple, but involves a lot of boilerplate, so i leave it as an exercise for the reader!