Method inefficiency - java

This is from code fights. The method works but is apparently taking too long for large inputs. Can someone please explain what is inefficient about this solution?
Question:
Given an array of integers, write a function that determines whether the array contains any duplicates. Your function should return true if any element appears at least twice in the array, and it should return false if every element is distinct.
Example
For a = [1, 2, 3, 1], the output should be
containsDuplicates(a) = true.
There are two 1s in the given array.
Solution:
static boolean containsDuplicates(int[] a) {
boolean elementRepeat = false;
for (int loop1 = 0; loop1 < a.length; loop1++){
for (int loop2 = 0; loop2 < a.length; loop2++){
if (a[loop1] == a[loop2] && loop1!=loop2){
elementRepeat = true;
return elementRepeat;
}
}
}
return elementRepeat;
}

One way to do this is by storing the array in Set and then comparing the length of the array and set. Here is how:
static boolean containsDuplicates(int[] array) {
HashSet<Integer> integers = new HashSet<>();
Arrays.stream(array).forEach(integers::add);
array.length == integers.size();
}

I think that #Henry did a very good sugestion.
This is an example:
import java.util.HashSet;
import java.util.Set;
public class Test4 {
public static void main(String[] args) {
Integer[] arrayInt = {1, 2, 3, 1};
Set<Integer> integers = new HashSet<Integer>();
boolean hasDuplicates = false;
for (Integer integerNumber : arrayInt) {
if (!integers.add(integerNumber)) {
hasDuplicates = true;
break;
}
}
System.out.println("Contains duplicates? " + hasDuplicates);
}
}
And it will print:
Contains duplicates? true

Related

Find sum of subsequent 3 elements of an array

I need to sum the three consecutive elements of an array when appending numbers to the same array dynamically and return true if the sum is equal to the argument value. I have already written the code below and it all return required output but it fails for some test cases( I don't have the the exact test cases), Can anybody tell me what exact scenario which my programme can be failed?
import java.util.LinkedList;
import java.util.List;
public class Test {
List<Integer> mergeList = new LinkedList<Integer>();
List<List<Integer>> allList = new LinkedList<List<Integer>>();
List<Integer> tail;
int from = 0;
int to = 0;
public void addLast(int[] list) {
allList.removeAll(allList);
for(int i : list) {
mergeList.add(i);
}
if (mergeList.size() > 0) {
int j = 0;
while(to < mergeList.size()){
from = j;
to = j + 3;
tail = mergeList.subList(from, to);
j++;
allList.add(tail);
}
}
}
public boolean containsSum3(int sum) {
boolean retVal = false;
for (List<Integer> sum3List : allList) {
if (sum3List.stream().mapToInt(Integer::intValue).sum() == sum) {
retVal = true;
}
}
return retVal;
}
public static void main(String[] args) {
Test s = new Test();
s.addLast(new int[] { 1, 2, 3 });
System.out.println(s.containsSum3(6));
System.out.println(s.containsSum3(9));
s.addLast(new int[] { 4 });
System.out.println(s.containsSum3(9));
s.addLast(new int[] { 5, 2});
System.out.println(s.containsSum3(11));
s.addLast(new int[] { 0, -1 });
System.out.println(s.containsSum3(7));
System.out.println(s.containsSum3(2));
}
}
Output:
true
false
true
true
true
false
I generated large random collections of integers and couldn't find any obvious cases your code fails for beyond the insufficient elements. Incidentally, the function I wrote to check if a list has any consecutive n elements that sum to a given value was:
public static boolean containsSum(List<Integer> list, int sum, int n) {
return IntStream.range(0, list.size() - n + 1)
.anyMatch(i -> list.subList(i, i + n).stream()
.reduce(0, Integer::sum) == sum);
}
I can't see any reason for your code that keeps all the list of lists: the space / time tradeoff doesn't make a lot of sense. I suggest you could simplify addLast to just add the elements to mergeList. There are a bunch of stylistic issues with your code but I'm sure you'll work those out in your own time.

Boolean assignment not catching, need to understand more

public class MyClass {
public static void main(String args[]) {
int[] nums = {1, 2, 9, 3, 4};
boolean results = false;
int end = nums.length;
if (end>4)end=4;
for (int x=0;x<end;x++)
{
System.out.println(nums[x]);
results = (nums[x] == 9);
}
System.out.println(results);
}
}
The following code checks to see if a 9 is present in the first 4 elements of an array, yet using the boolean operator in this fashion seems to always fail if there are not more than 1 "9" in the first 4 elements of the array.
Why is this? Logically it seems that this should work, and it really helps me to understand better when I understand why something doesn't work.
The reason is that you have itetate all the elements,the result will be the result of the last element,
So you need to stop for when you find the match result
for (int x=0;x<end;x++)
{
System.out.println(nums[x]);
if(nums[x] == 9){
result = true;
break;
}
}
You overwrite results every time. As written, this'll tell you whether the last item in the array equals 9 (which it doesn't), not whether any item in the array equals 9.
You should assign true to result if num[x] == 9; otherwise, don't assign anything.
#lucumt's answer shows an example of how to do that. One other example, just replace
results = (nums[x] == 9);
with
results |= (nums[x] == 9);
where the |= assignment is equivalent to results = results || (num[x] == 9); - in other words, if any value is true, the entire expression will be true. (Note that #lucumt's answer is slightly more efficient because it's O(n) whereas this is Theta(n) - i.e. this will always run exactly n times, where n is the length of the list, but #lucumt's can end the loop early if it finds any 9).
In your for loop you are over writing the value each time. This means you are testing if the 4th value is equal to 9.
you can solve your problem like so:
boolean results = false;
for (int x = 0; x < end; x++) {
System.out.println(nums[x]);
if(nums[x] == 9) {
results = true;
break;
}
}
Try this:
boolean isPresent(int[] nums, int val)
{
for (int x : nums )
{
if (nums[x] == val)
return true;
}
return false;
}
Otherwise you rewrite a value every time you're checking
I wrote you a class. The method nignPresentInFirst4Elements(int[] arr) returns true if the given array contains a 9 in one or more of it's first 4 elements:
public class Test {
private static boolean nignPresentInFirst4Elements(int[] arr) {
if(arr == null)
return false;
for(int i = 0; i < Math.min(arr.length, 4); i++) {
if(arr[i] == 9)
return true;
}
return false;
}
public static void main(String[] args) {
int[][] arrs = new int[][] {
{5, 8, 9, 3},
{5, 8, 9, 3, 8, 26},
{5, 8, 9, 9},
{5, 8, 23, 0}
};
for(int i = 0; i < arrs.length; i++) {
System.out.println(toString(arrs[i]) + " | " + nignPresentInFirst4Elements(arrs[i]));
}
}
private static String toString(int[] arr) {
if(arr == null)
return "null";
String s = "[";
if(arr.length > 0)
s += arr[0];
for(int i = 1; i < arr.length; i++) {
s += ", " + arr[i];
}
s += "]";
return s;
}
}

Sieve of erastothenes primality issue

Set up to print out all false values which are prime numbers however out of 25 it prints. 3, 5, 7, 8, 9, 11, 13, 14, 15, 17, 19, 20, 21, 23, 24, not sure why some of them slip by. Any insight into the matter would be nice.
Or simply pointing me in the write direction.
Why are the non-prime numbers such as 8 being printed?
import java.util.Arrays;
import java.util.Scanner;
class Sieve {
public static void main(String args[]) {
Scanner inputScanner;
inputScanner = new Scanner(System.in);
//determine max value
System.out.println("I will determine all the primality of a set of numbers, enter the max");
int n = Integer.parseInt (inputScanner.nextLine());
boolean[] truedBooleanArray = calcBooleanMax (n);
//call upon function to check primality
boolean [] primeNumbers = calcPrimality (truedBooleanArray);
// call upon function to print out prime numbers
printPrimes(primeNumbers);
}
public static boolean[] calcBooleanMax(int maxNumber) {
boolean [] maxNumberArray = new boolean [maxNumber];
maxNumberArray[0] = false;
maxNumberArray[1] = false;
//asigns 1, 0 to false
//change all boleans within array from false to true!
for(int i=1; i < maxNumber; i++) {
maxNumberArray [i] = true;
}
return maxNumberArray;
}
public static boolean[] calcPrimality(boolean [] truedBooleans) {
for(int i = 2; i <=truedBooleans.length; i++) {
//check every number greater than 1 for primality.
if (truedBooleans[i-1]) {
}
//finds multiples and makes sure they arent stored
for(int j = 2*i; j <= truedBooleans.length; j+= i) {
truedBooleans[j-1] = false;
}
}
return truedBooleans;
}
public static void printPrimes(boolean [] thePrimeNumbers){
System.out.println("The prime numbers are [");
for(int i = 2; i<thePrimeNumbers.length; i++) {
if(thePrimeNumbers[i] == false ) {
System.out.print(i + ", ");
}
}
}
}
You have a few errors.
The array must be one larger than the given max
You are accidentally adding one back to the sieve when initializing
When removing multiples from the sieve, you must first make sure the initial number "i" is still in the sieve
You want to print the items that are still in the sieve, so print when true rather than false
Here is the fixed code
public static boolean[] calcBooleanMax(int maxNumber) {
boolean [] maxNumberArray = new boolean [maxNumber+1];
maxNumberArray[0] = false;
maxNumberArray[1] = false;
//asigns 1, 0 to false
//change all boleans within array from false to true!
for(int i=2;i < maxNumber+1; i++) {
maxNumberArray [i] = true;
}
return maxNumberArray;
}
public static boolean[] calcPrimality(boolean [] truedBooleans){
for(int i = 2; i <truedBooleans.length; i++) {
if(truedBooleans[i]) {
//finds multiples and makes sure they arent stored
for(int j = 2*i; j < truedBooleans.length; j+= i) {
truedBooleans[j] = false;
}
}
}
return truedBooleans;
}
public static void printPrimes(boolean [] thePrimeNumbers){
System.out.println("The prime numbers are [");
for(int i = 2;i<thePrimeNumbers.length;i++) {
if(thePrimeNumbers[i] ) {
System.out.print(i + ", ");
}
}
}
A simpler solution is a less literal interpretation of the algorithm. Rather than keeping a literal list of booleans, you can keep a list of the current primes. This makes the code simpler and easier to read.
Here is an example of a solution (that relies on Java 8 streams):
class Sieve {
private long current = 2;
private final List<Long> primes = new ArrayList<>();
public long nextPrime() {
while (primes.stream().anyMatch(p -> current % p == 0))
current++;
primes.add(current);
return current;
}
}

Count different values in array in Java

I'm writing a code where I have an int[a] and the method should return the number of unique values. Example: {1} = 0 different values, {3,3,3} = 0 different values, {1,2} = 2 different values, {1,2,3,4} = 4 different values etc. I am not allowed to sort the array.
The thing is that my method doesn't work probably. There is something wrong with my for statement and I can't figure it out.
public class Program
{
public static void main(String[] args)
{
int[] a = {1, 2, 3, 1};
System.out.println(differentValuesUnsorted(a));
//run: 4 //should be 3
}
public static int differentValuesUnsorted(int[] a)
{
int values; //values of different numbers
if (a.length < 2)
{
return values = 0;
}else if (a[0] == a[1])
{
return values = 0;
}else
{
values = 2;
}
int numberValue = a[0];
for (int i = a[1]; i < a.length; i++)
{
if (a[i] != numberValue)
{
numberValue++;
values++;
}
}
return values;
}
}
Can anybody help?
This is actually much simpler than most people have made it out to be, this method works perfectly fine:
public static int diffValues(int[] numArray){
int numOfDifferentVals = 0;
ArrayList<Integer> diffNum = new ArrayList<>();
for(int i=0; i<numArray.length; i++){
if(!diffNum.contains(numArray[i])){
diffNum.add(numArray[i]);
}
}
if(diffNum.size()==1){
numOfDifferentVals = 0;
}
else{
numOfDifferentVals = diffNum.size();
}
return numOfDifferentVals;
}
Let me walk you through it:
1) Provide an int array as a parameter.
2) Create an ArrayList which will hold integers:
If that arrayList DOES NOT contain the integer with in the array
provided as a parameter, then add that element in the array parameter
to the array list
If that arrayList DOES contain that element from the int array parameter, then do nothing. (DO NOT ADD THAT VALUE TO THE ARRAY LIST)
N.B: This means that the ArrayList contains all the numbers in the int[], and removes the repeated numbers.
3) The size of the ArrayList (which is analogous to the length property of an array) will be the number of different values in the array provided.
Trial
Input:
int[] numbers = {3,1,2,2,2,5,2,1,9,7};
Output: 6
First create distinct value array, It can simply create using HashSet.
Then alreadyPresent.size() will provide number of different values. But for the case such as -{3,3,3} = 0 (array contains same elements); output of alreadyPresent.size() is 1. For that use this simple filter
if(alreadyPresent.size() == 1)){
return 0;
}
Following code will give the count of different values.
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class Demo {
public static void main(String[] args)
{
int array[] = {9,9,5,2,3};
System.out.println(differentValuesUnsorted(array));
}
public static int differentValuesUnsorted(int[] array)
{
Set<Integer> alreadyPresent = new HashSet<Integer>();
for (int nextElem : array) {
alreadyPresent.add(nextElem);
}
if(alreadyPresent.size() == 1){
return 0;
}
return alreadyPresent.size();
}
}
You can use a HashSet, which can only contain unique elements. The HashSet will remove the duplicated items and you can then get the size of the set.
public static int differentValuesUnsorted(int[] a) {
Set<Integer> unique = new HashSet<Integer>();
for (int val : a) {
unique.add(val); // will only be added if a is not in unique
}
if (unique.size() < 2) { // if there are no different values
return 0;
}
return unique.size();
}
For small arrays, this is a fast concise method that does not require the allocation of any additional temporary objects:
public static int uniqueValues(int[] ids) {
int uniques = 0;
top:
for (int i = 0; i < ids.length; i++) {
final int id = ids[i];
for (int j = i + 1; j < ids.length; j++) {
if (id == ids[j]) continue top;
}
uniques++;
}
return uniques;
}
Try this:
import java.util.ArrayList;
public class DifferentValues {
public static void main(String[] args)
{
int[] a ={1, 2, 3, 1};
System.out.println(differentValuesUnsorted(a));
}
public static int differentValuesUnsorted(int[] a)
{
ArrayList<Integer> ArrUnique = new ArrayList<Integer>();
int values=0; //values of different numbers
for (int num : a) {
if (!ArrUnique.contains(num)) ArrUnique.add(num);
}
values = ArrUnique.size();
if (values == 1) values = 0;
return values;
}
}
input:{1,1,1,1,1} - output: 0
input:{1,2,3,1} - output: 3
Try this... its pretty simple using ArrayList. You don't even need two loop. Go on
import java.util.*;
public class distinctNumbers{
public static void main(String []args){
int [] numbers = {2, 7, 3, 2, 3, 7, 7};
ArrayList<Integer> list=new ArrayList<Integer>();
for(int i=0;i<numbers.length;i++)
{
if(!list.contains(numbers[i])) //checking if the number is present in the list
{
list.add(numbers[i]); //if not present then add the number to the list i.e adding the distinct number
}
}
System.out.println(list.size());
}
}
Try this simple code snippet.
public static int differentValuesUnsorted(int[] a)
{
ArrayList<Integer> list=new ArrayList<Integer>(); //import java.util.*;
for(int i:numbers) //Iterate through all the elements
if(!list.contains(i)) //checking for duplicate element
list.add(i); //Add to list if unique
return list.size();
}
What about this?
private <T> int arrayDistinctCount(T[] array) {
return Arrays.stream(array).collect(Collectors.toSet()).size();
}
Use a set to remove duplicates
public static int differentValuesUnsorted(int[] a) {
if (a.length < 2) {
return 0;
}
Set<Integer> uniques = new HashSet<>(a);
return singleUnique.size();
}

Get all subsets of a set

import java.util.ArrayList;
public class Subset { //Generate all subsets by generating all binary numbers
public static ArrayList<ArrayList<Integer>> getSubsets2(ArrayList<Integer> set) {
ArrayList<ArrayList<Integer>> allsubsets =
new ArrayList<ArrayList<Integer>>();
int max = 1 << set.size(); //there are 2 power n
for (int i = 0; i < max; i++) {
ArrayList<Integer> subset = new ArrayList<Integer>();
int index = 0;
while (i > 0) {
if ((i & 1) > 0) {
subset.add(set.get(index)); //Add elements to a new ArrayList
}
i >>= 1;
index++;
}
allsubsets.add(subset);
}
return allsubsets;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<Integer> set = new ArrayList<Integer>(); //Create an ArrayList
set.add(1);
set.add(2);
System.out.println(getSubsets2(set));
}
}
The result should be [[],[1],[2],[1,2]]
But I can't get the result, the exception is as follows:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Your while loop is incorrect.
Made slightly more succinct with a for-loop:
import java.util.ArrayList;
public class Subset { //Generate all subsets by generating all binary numbers
public static ArrayList<ArrayList<Integer>> getSubsets2(ArrayList<Integer> set) {
ArrayList<ArrayList<Integer>> allsubsets =
new ArrayList<ArrayList<Integer>>();
int max = 1 << set.size(); //there are 2 power n different subsets
for (int i = 0; i < max; i++) {
ArrayList<Integer> subset = new ArrayList<Integer>();
for (int j = 0; j < set.size(); j++) {
if (((i >> j) & 1) == 1) {
subset.add(set.get(j));
}
}
allsubsets.add(subset);
}
return allsubsets;
}
public static void main(String[] args) {
ArrayList<Integer> set = new ArrayList<Integer>(); //Create an ArrayList
set.add(1);
set.add(2);
System.out.println(getSubsets2(set));
}
}
Bear in mind that the subset operation is exponential, so you'll get a very large number of elements. The implementation above will only work with about 32 input elements, as that yields 2^32 output subsets, which will very easily run you over the limit of an array...
Your problem appears to be in your loop. If you look at it:
for (int i = 0; i < max; i++) {
ArrayList<Integer> subset = new ArrayList<Integer>();
int index = 0;
while (i > 0) {
if ((i & 1) > 0) {
subset.add(set.get(index)); //Add elements to a new ArrayList
}
i >>= 1;
index++;
}
allsubsets.add(subset);
}
You'll notice that the outside for-loop is trying to count i upwards from zero, and the inner while loop counts it back to zero every iteration, so the outer loop runs forever.
Here is a Java 8 solution for this question:
public Set<Set<Integer>> getSubsets(Set<Integer> set) {
if (set.isEmpty()) {
return Collections.singleton(Collections.emptySet());
}
Set<Set<Integer>> subSets = set.stream().map(item -> {
Set<Integer> clone = new HashSet<>(set);
clone.remove(item);
return clone;
}).map(group -> getSubsets(group))
.reduce(new HashSet<>(), (x, y) -> {
x.addAll(y);
return x;
});
subSets.add(set);
return subSets;
}
Program runs forever. Below statement execute continuesly and getting outOfMemory. Variable i value is never bigger than max value, check it.
`subset.add(set.get(index));`
In a nutshell, your inner while-loop is changing the outer for-loop's loop variable (i). This is disrupting the outer loop iteration. At the end of the inner loop the value of i is going to be zero ... which means that the outer loop will never terminate.
Given what you are doing, the fix is to use a different variable (say j) for the inner loop, and initialize it from i.
This illustrates why it is a bad idea to change a for-loop variable inside the loop.
how about a recursive solution?
vector<vector<int> > getSubsets(vector<int> a){
//base case
//if there is just one item then its subsets are that item and empty item
//for example all subsets of {1} are {1}, {}
if(a.size() == 1){
vector<vector<int> > temp;
temp.push_back(a);
vector<int> b;
temp.push_back(b);
return temp;
}
else
{
//here is what i am doing
// getSubsets({1, 2, 3})
//without = getSubsets({1, 2})
//without = {1}, {2}, {}, {1, 2}
//with = {1, 3}, {2, 3}, {3}, {1, 2, 3}
//total = {{1}, {2}, {}, {1, 2}, {1, 3}, {2, 3}, {3}, {1, 2, 3}}
//return total
int last = a[a.size() - 1];
a.pop_back();
vector<vector<int> > without = getSubsets(a);
vector<vector<int> > with = without;
for(int i=0;i<without.size();i++){
with[i].push_back(last);
}
vector<vector<int> > total;
for(int j=0;j<without.size();j++){
total.push_back(without[j]);
}
for(int k=0;k<with.size();k++){
total.push_back(with[k]);
}
return total;
}
}

Categories