I'm trying to generalize the code to find all subsets of a given string(elements that are repeated will be treated as distinct) into one that would work for any list.
public class Subsets{
private static <T> void RecursiveSubsets(List<List<T>> list, ArrayList<T> soFar, List<T> rest)
{
if(rest.isEmpty())
{
list.add(soFar);
}
else
{
List<T> remaining;
if(rest.size() == 1)
{
remaining = new ArrayList<T>();
}
else
{
remaining = rest.subList(1, rest.size() - 1);
}
//include the element
ArrayList<T> includeFirst = new ArrayList<T>(soFar);
includeFirst.add(rest.get(0));
RecursiveSubsets(list, includeFirst, remaining);
//exclude the element
RecursiveSubsets(list, soFar, remaining);
}
}
public static <T> List<List<T>> getAllSubsets(List<T> set)
{
List<List<T>> subsets = new ArrayList<List<T>>();
RecursiveSubsets(subsets,new ArrayList<T>(),set);
return subsets;
}
public static void main(String [] args)
{
List<Integer> ints = new ArrayList<Integer>(){
{
add(0);add(1);add(2);add(3);
}
};
List<List<Integer>> allSubsets = getAllSubsets(ints);
System.out.println("Total Subsets returned : " + allSubsets.size());
for(int i=0; i<allSubsets.size(); ++i)
{
for(int j=0; j<allSubsets.get(i).size(); ++j)
{
System.out.print(allSubsets.get(i).get(j) + " ");
}
System.out.println();
}
}
}
After a few attempts I was able to get this to compile but this is what I get as output.
Even if I have more integers, it still returns this. I'm not able to figure out what I have missed and need help finding it.
$ java Subsets
Total Subsets returned : 4
0 1
0
1
Your program is actually almost correct, and you just have the sublist logic a bit wrong.
The javadoc for List.sublist says
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.
The word "exclusive" here is critical.
If you just change
remaining = rest.subList(1, rest.size() - 1);
to
remaining = rest.subList(1, rest.size());
your code works.
The logic of this (in pseudocode) is typically:
List<List<T>> subsets( List<T> list ){
if( list is empty ) return a list containing the empty list;
// else:
subsetsWithout = subsets( list w/o 0th element );
result.addAll(subsetsWithout);
for( subset in subsetsWithout )
result.add( subset + list[0] )
return result;
}
It looks like what you're doing is different, and the fact that you're trying to return things through the function parameters is making it more confusing.
Related
new to java,I read the answer in the leecode ,and it ask for a array like [1,2,3]and return its permutation [1,3,2],[2,1,3].....and feel confused especially this code
Collections.swap(output, first, i);
backtrack(n, output, res, first + 1);
I do not know why the use Collections.swap(output,first,i) I think in first loop ,the first and i is equal to 0,so why use swap here. they are same vaule. what this recursion actually do,I debug it and can not figure out.code is below:
package com.company;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class Main {
public static void main(String[] args) {
int[]arr=new int[]{1,2,3};
Main main1=new Main();
List<List<Integer>> lists = main1.permute(arr);
System.out.println(lists);
}
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
List<Integer> output = new ArrayList<Integer>();
for (int num : nums) {
output.add(num);
}
int n = nums.length;
backtrack(n, output, res, 0);
return res;
}
public void backtrack(int n, List<Integer> output, List<List<Integer>> res, int first) {
if (first == n) {
res.add(new ArrayList<Integer>(output));
}
for (int i = first; i < n; i++) {
Collections.swap(output, first, i);
backtrack(n, output, res, first + 1);
Collections.swap(output, first, i);
}
}
}
According to the documentation, the swap() method of java.util.Collections class is used to swap the elements at the specified positions in the specified list. If the specified positions are equal, invoking this method leaves the list unchanged.
So in a recursive technique, it is ok to have that call even though it does nothing in that particular condition, just to make the logic easier to implement and understand. If you want to avoid that, you will un-necessarily need to bring conditional statements into the logic, which is really not required.
Here is a somewhat simplified and commented version that may help follow what the code does:
import java.util.*;
public class Main {
public static void main(String[] args) {
int[]arr=new int[]{1,2,3};
List<List<Integer>> permutations = new Main().permute(arr);
System.out.println(permutations);
}
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
List<Integer> input = new ArrayList<>();
for (int num : nums) {
input.add(num);
}
backtrack(input, result, 0);
return result;
}
public void backtrack(List<Integer> input, List<List<Integer>> result, int currentIndex) {
if (currentIndex == input.size() ) { //index passed the end of the collection
result.add(new ArrayList<>(input)); //add the permutation to the returned result
//the method return here because when currentIndex == input.size()
//next for loop will not be executed
//you may add a return here. It may improve the readability of the code
}
//iterate over each element of the array form currentIndex to the end
for (int i = currentIndex; i < input.size(); i++) {
Collections.swap(input, currentIndex, i);//create a permutation by swapping
backtrack(input, result, currentIndex + 1); //increment currentIndex and process new permutation
Collections.swap(input, currentIndex, i);//undo permutation before next loop
}
}
}
looking for a hand with some recursion, I know it's a simple issue somewhere exiting but not sure how/where!
Here's my recursive method:
public static int getNumAppearances(myList<String> l, String word)
{
int index = 0;
int count = 0;
String search = word;
if(index > l.my_get_length()-1)
{
return 0;
}
else if(l.my_get_element(index).equals(search))
{
count++;
index++;
}
return count + getNumAppearances(l, word);
}
Cheers!
Edit, myList Class:
public interface myList<T> {
//-------------------------------------------------------------------
// Create an empty MyList: create_empty
//-------------------------------------------------------------------
//public myList create_empty(); --> Java does not support constructors in interfaces
//-------------------------------------------------------------------
// Basic Operation --> Get number of elements in MyList: my_get_length
//-------------------------------------------------------------------
public int my_get_length();
//-------------------------------------------------------------------
// Basic Operation --> Get element at of MyList at a concrete position: my_get_element
//-------------------------------------------------------------------
public T my_get_element(int index) throws myException;
//-------------------------------------------------------------------
// Basic Operation --> Add element to MyList at a concrete position: my_add_element
//-------------------------------------------------------------------
public void my_add_element(int index, T element) throws myException;
//-------------------------------------------------------------------
// Basic Operation --> Remove element of MyList at a concrete position: my_remove_element
//-------------------------------------------------------------------
public void my_remove_element(int index) throws myException;
}
I've realised you ideally need an index being passed to the method but unfortunately that's not the way he has it set up!
You can count in your function by modifying the list as such:
public class RecursiveListWordCount {
public static void main(String[] args) {
System.out.println(count(Arrays.asList("a", "b", "a", "b", "c"), "d"));
}
public static final int count(List<String> list, String word) {
if(list.isEmpty()) {
return 0;
}
if(list.get(0).equals(word)) {
return 1 + count(list.subList(1, list.size()), word);
} else {
return 0 + count(list.subList(1, list.size()), word);
}
}
}
On each call, I check if the list is empty, if true I will return 0 (as an empty list surely has no word in it that may be equal).
The next call then would add a sublist, removing the word I just checked.
Hope that helps,
Artur
It seems that you're utilising the index variable incorrectly because you're always checking the same index each time the method calls itself, I would recommend using the index as a parameter to the method. Also instead of keeping a count variable, we can just add 1 to the result each time we find a match.
public static int getNumAppearances(List<String> list, String word, int index)
{ if(list == null || list.size() == 0 || index < 0) return -1; // you can throw an exception instead if you deem it necessary.
if(index > list.size() - 1) return 0;
else if(list.get(index).equals(word)) return 1 + getNumAppearances(list, word, index + 1);
return getNumAppearances(list, word, index + 1);
}
note - when calling the method, make sure you pass 0 as the argument to the index parameter, as this approach examines the list from the start to the end.
public class MyArrayList<T> implements MyList<T>{
int num; //number of things in the list
T[] vals; //to store the contents
#SuppressWarnings("unchecked")
public MyArrayList() {
num = 0;
vals = (T[]) new Object[3];
}
public T getUnique(){
T distinct = null;
int count = 0;
for (int i=0; i<vals.length; i++){
distinct = vals[i];
for (int j = 0; j<vals.length; j++){
if (vals[j] == vals[i]){
count++;
}
if (count == 1){
return distinct;
}
}
}
if (distinct == null){
throw new IllegalArgumentException();
}
return distinct;
}
I am trying to work on a get Unique Method. A method getUnique that takes no arguments and returns the first value in the list that appears only once. (For example, calling the method on the list [1,2,3,1,2,4] would return 3 since 1 and
2 both appear more than once.) If the list is empty or all its values appear more than once, the method throws a NoSuchElementException
I have added some FIXME's to your code:
public T getUnique(){
T distinct = null;
int count = 0; // FIXME: move this initialization inside the i loop
for (int i=0; i<vals.length; i++){
distinct = vals[i];
for (int j = 0; j<vals.length; j++){
if (vals[j] == vals[i]){ // FIXME: use .equals() not ==
count++;
}
if (count == 1){ // FIXME: move this check outside the j loop
return distinct;
}
}
}
if (distinct == null){ //FIXME: no check needed, just throw it
throw new IllegalArgumentException();
}
return distinct; //FIXME: no valid return can reach this point
}
Patrick Parker's advice will fix your code, but I wanted to provide a cleaner and faster solution to the problem of finding a unique element in a list. This algorithm runs in time O(n) instead of O(n^2).
public static <T> Optional<T> getUnique(List<T> ls) {
// Create a map whose keys are elements of the list and whose values are
// lists of their occurences. E.g. [1,2,3,1,2,4] becomes {1->[1, 1],
// 2->[2, 2], 3->[3], 4->[4]}. Then elements.get(x).size() tells us how
// many times x occured in ls.
Map<T, List<T>> elements = ls.stream()
.collect(Collectors.groupingBy(x -> x));
// Find the first element that occurs exactly one time in ls.
return ls.stream().filter(x -> elements.get(x).size() == 1)
.findFirst();
}
You might call it like this:
Integer[] vals = {1,2,3,1,2,4};
System.out.println(getUnique(Arrays.asList(vals))
.orElseThrow(NoSuchElementException::new));
This code uses Java 8 streams and Optional. Below is another implementation of the same algorithm that doesn't use Java 8 language features; if you've never encountered streams, you may find it more understandable.
private static <T> T getUnique(List<T> arr) {
Map<T, Integer> numOccurrences = new HashMap<>();
for (T item : arr) {
numOccurrences.put(item, 1 + numOccurrences.getOrDefault(item, 0));
}
for (T item : arr) {
if (numOccurrences.get(item) == 1) {
return item;
}
}
throw new NoSuchElementException();
}
I'm trying to iterate over an ArrayList of ArrayLists - but somehow everything fails on me and I don't understand the error message.
The error is:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.util.ArrayList
I've tried using a regular for(int i; i < lists.length; i++) but get the same error. All I want to do is check if any of the ArrayLists in "lists" contains the integer "v".
public static boolean listsContains(ArrayList<ArrayList<Integer>> lists, int v) {
boolean b = false;
for (ArrayList<Integer> list : lists) {
if (list.contains(v)) {
b = true;
} else {
b = false;
}
}
return b;
}
The actual line that causes the error is the "for (ArrayList list"...
Edited: For clarity I edited in the code with more declarative generics (which works just as little as the first code I posted unfortunately).
Edit2: Ok so it's somehow not the method itself that causes the problem so upon request here's the rest of the code that populates these lists. The code is not done but I got caught with this problem while finishing it.
public static void main(String[] args) {
Graph g = DataSource.load();
ArrayList<ArrayList<Integer>> lists = new ArrayList<ArrayList<Integer>>();
for(int i = 0; i < g.numberOfVertices(); i++) {
if(!(listsContains(lists, i))) { // add list if node is unlisted (since after first iteration one entire network is found)
listsCreate(lists, i);
}
Iterator it = g.adj(i).iterator(); // create iterator for current node's edges
if (!(it.hasNext())) { // node has no edges
listsCreate(lists, i);
} else { // node has edges, iterate through them
while(it.hasNext()) {
Edge current = (Edge) it.next();
if(!(listsContains(lists, current.to))) { // unlisted node
int index = listsIndexOf(lists, current.from);
findNetwork(g, lists.get(index), current.to);
} else {
continue; // node already listed
}
}
}
}
System.out.println("Number of connected graphs: " + lists.size());
} // Main
You did not specify the inner ArrayList's components' type. And from your log I can tell that it contains Integers:
public static boolean listsContains(ArrayList<ArrayList<Integer>> lists, int v) {
for (ArrayList<Integer> list : lists) {
if (list.contains(v))
return true;
}
return false; // No inner arrayList contains 'v'
}
EDIT:
or using Java 8 :
public static boolean listsContains(ArrayList<ArrayList<Integer>> lists, int v) {
return lists.stream().anyMatch(list -> list.contains(v));
}
Because you test:
list.contains(v)
list is of type ArrayList without inside type
v is int
replace your ArrayList by ArrayList< Integer >
I have to iterate through an arraylist in this manner.
ArrayList<Integer> li = new ArrayList<Integer>();
li.add(20);
li.add(30);
li.add(40);
li.add(50);
li.add(70);
for (int i = 0; i < li.size() - 1; i++)
System.out.println(li.get(i) + " " + li.get(i + 1));
Output:
20 30
30 40
40 50
50 70
How to do the same using an iterator?
Use two iterators. I tested this and it worked for me.
Iterator<Integer> first = li.listIterator();
// Will raise IndexOutOfBoundsException if list is empty.
Iterator<Integer> second = li.listIterator(1);
while (second.hasNext()) {
System.out.println(first.next() + " " + second.next());
}
Edit: No need for inner if. Silly me.
Explanation: the listIterator(index) method returns an iterator that starts at the specified position in the list where as listIterator() returns an iterator that starts at position zero.
The first iterator therefore starts at 0 and the second starts at 1. Then it is merely a question of printing the next() on both. This will work irrespective of whether the number of elements in the list is odd or even.
Edit 2
My logic fu is very weak today. Thanks #barjak for pointing out the case about the empty list and the unnecessary first.hasNext().
It's a bit more complicated:
Iterator<Integer> iter = li.iterator();
if (iter.hasNext()) {
for (int y = iter.next(), x; iter.hasNext(); y = x) {
x = iter.next();
System.out.println(y + " " + x);
}
}
or:
if (iter.hasNext()) {
for (int x = iter.next(); iter.hasNext();) {
System.out.println(x + " " + (x = iter.next()));
}
}
Slightly Modified Sagar V's solution to make it work. One iterator is enough to achieve this.
Iterator iter = li.iterator();
Integer int1 = null;
while (iter.hasNext()) {
if (int1 == null) {
int1 = (Integer) iter.next();
}
System.out.print(int1 + " ");
if (iter.hasNext()) {
Integer int2 = (Integer) iter.next();
System.out.println(int2);
int1 = int2;
} else {
break;
}
}
}
There are many solutions, that can be appropriate depending on your needs.
Solution 1 : fixed-size view
The classical way to iterate on a subset of a list is to create a narrower view of the original list, and to iterate on this whole view. The subList method is used to create such a view.
List<Integer> l = // initialization code
int limitIndex = Math.max(l.size()-1, 0); // needed for empty list
for (int v : l.subList(0, limitIndex)) {
// your code
}
Note that I used a 'foreach' loop, which is a convenient way to use iterators. This is strictly equivalent to this code :
Iterator<Integer> it = l.subList(0, limitIndex).iterator();
while(it.hasNext()) {
int v = it.next();
// your code
}
Also, note that the subList method does not create a new list : it only creates a 'view' on the original list. The content of the original list is not copied, and all changes made to the original list are visible from the list created by subList.
Solution 2 : a custom Iterator/Iterable
If all you need is an iterator that always iterates from 0 to n-1, you can define a new Iterable tailored to that particular need.
public class NoLastIterable<T> implements Iterable<T> {
private final List<T> backend;
public NoLastIterable(List<T> backend) {
this.backend = backend;
}
public Iterator<T> iterator() {
return new Iterator<T>() {
private int nextIndex;
public boolean hasNext() {
return nextIndex < backend.size() -1;
}
public T next() {
return backend.get(nextIndex++);
}
public void remove() {
throw new UnsupportedOperationException("not implemented");
}
};
}
}
This class is used like this :
for (int v : new NoLastIterable<Integer>(l)) {
// your code
}
Solution 3
You can even create your custom view of a List, just like subList does, but with more flexibility.
public class NoLastList<T> extends AbstractList<T> {
private final List<T> backend;
public NoLastList(List<T> backend) {
this.backend = backend;
}
#Override
public T get(int index) {
if (index >= size()) {
throw new IndexOutOfBoundsException();
}
return backend.get(index);
}
#Override
public int size() {
return Math.max(0, backend.size()-1);
}
}
Same usage as the other solutions :
for (int v : new NoLastList<Integer>(l)) {
// your code
}
The benefits of this solution can be seen in the following situation :
the original list is created and initialized
the NoLastList instance is created (as a view of the original List)
some elements are added to the original list
In this situation, iterating over NoLastList will take into account the elements that were added lately. NoLastList always represents a view of the elements from 0 to n-1, even if n (the size) changes.