Java, First Duplicate value from an array in O(n) time complexity - java

int firstDuplicate(int[] a) {
Set<Integer> result = new HashSet();
for(int i=0; i<a.length; i++) {
if(result.contains(a[i])) {
return a[i];
} else {
result.add(a[i]);
}
}
return -1;
}
The complexity of the above code is O(n2) because of contains check inside the for loop.
How to achieve this with a complexity of O(n) in java.
Implementation of .contains for ArrayList
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}

The implementation you're providing corresponds to the contains(Object) method in the ArrayList class. The method you're using is actually HashSet.contains(Object).
The complexity of HashSet.contains(Object) is O(1). To achieve this, it uses a hash of the value stored to find the element searched for.
In the unlikely event that two objects share the same hash, both elements will be stored under the same hash in a list. This might be the reason that is misleading you to believe that the cost for HashSet.contains(Object) is O(n). Although there is a list, elements are nearly evenly distributed, and thus the list size tends to 1, transforming O(n) to O(1).

As already explained in this answer your algorithm has already O(n) time complexity as HashSet’s lookup methods (includes both contains and add) have O(1) time complexity.
Still, you can improve your method, as there as no reason to perform two lookups for each element:
static int firstDuplicate(int[] a) {
Set<Integer> result = new HashSet<>();
for(int i: a) if(!result.add(i)) return i;
return -1;
}
The contract of Set.add is to only add a value (and return true) if the value is not already contained in the set and return false if it is already contained in the set.
Using this you may end up with half the execution time (it’s still the same time complexity) and have simpler code…

void printRepeating(int a[], int asize){
int i;
System.out.println("The repeating elements are : ");
for (i = 0; i < asize; i++)
{
if (a[Math.abs(a[i])] >= 0){
a[Math.abs(a[i])] = -a[Math.abs(a[i])];
}
else{
System.out.print(Math.abs(a[i]) + " ");
break;
}
}
}

Related

Why hashset solution is accepted whereas using hashmap getting timeout error-Finding pairs in array with difference K?

I was going through a question where the problem was to find the number of pairs which makes a difference K.Below is the code for the same.In the below code I have used hashmap however it gave correct answer but for few of the scenario's I got timeout where as using HashSet all the test cases were passed.Can anyone help why using hashmap I am getting timeout error whereas in actual scenario hashmap computation is fast as compared to hashset.
static int pairs(int k, int[] arr) {
HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
for(int i=0;i<arr.length;i++)
map.put(i,arr[i]);
int count=0;
for(int j=0;j<arr.length;j++)
{
if(map.containsValue(arr[j]-k))
count++;
}
return count;
}
Correct me if my understanding is wrong.Thanks in advance for the same.
Looking up a key in a HashMap is O(1)*, but looking up a value is O(n) -- it has to loop over every entry, one at a time, until it finds a matching value.
If you wanted analogous behavior to HashSet, you would need to put the things you've looking up into the keys, not the values. You would then use containsKey, and never actually care what there values are. Under the hood, that is in fact the implementation of HashSet that OpenJDK uses.
* it's actually a tad more complicated than that, but you can think of it as O(1) most of the time
Probably, you can write the code this way & check:-
import java.util.*;
class GFG {
/* Returns count of pairs with
difference k in arr[] of size n. */
static int countPairsWithDiffK(int arr[], int n,
int k)
{
int count = 0;
Arrays.sort(arr); // Sort array elements
int l = 0;
int r = 0;
while(r < n)
{
if(arr[r] - arr[l] == k)
{
count++;
l++;
r++;
}
else if(arr[r] - arr[l] > k)
l++;
else // arr[r] - arr[l] < sum
r++;
}
return count;
}
public static void main(String[] args)
{
int arr[] = {1, 5, 3, 4, 2};
int n = arr.length;
int k = 3;
System.out.println("Count of pairs with given diff is " +
countPairsWithDiffK(arr, n, k));
}
}
Time Complexity: O(nlogn)

How do I count how many negative elements are in a circular doubly linked list?

I would like to use list.negativeNumbers(); to call out the part of a code, which counts how many negative numbers are in a list.
public void negativeNumbers(){
int negative = 0;
for (int i = 0; i <= size; i++){
if (i < 0) {
negative = negative + 1;
}
System.out.println("There are "+ negative +" negative elements in the list!");
}
}
Can you help me in creating a method, that could count negative numbers in the list the correct way?
public void negativeNumbers(){
int negative = 0;
for (int i = 0; i <= size; i++){
if (i < 0) {
negative = negative + 1;
}
System.out.println("There are "+ negative +" negative elements in the list!");
}
}
You will learn better by working out the solution for yourself.
Your code as presented is a good start but lacks:
a defined list of values to test.
a definition of the size of the list (use list.size()).
proper indexing of the list to access values to test (use list.get(i) or list[i]).
a test of each element in the list to determine its negativity. Your code tests whether the list increment variable is < 0.
negative = negative + 1 is ok, but simpler to write ++negative.
Here's a simple example:
import java.util.ArrayList;
public class negnum {
public static void main(String [] args) {
ArrayList<Integer> nums = new ArrayList();
nums.add(0);
nums.add(10);
nums.add(-10);
nums.add(20);
nums.add(-20);
nums.add(30);
nums.add(-30);
nums.add(40);
nums.add(-40);
nums.add(50);
int negs = 0;
for (int i = 0; i < nums.size(); i++){
int n = nums.get(i);
if (n < 0) {
++negs;
System.out.println(n);
}
}
System.out.println(negs +" negatives");
}
}
c:\dev>java negnum
-10
-20
-30
-40
4 negatives
If it is a list of integers you should not be doing "i < 0" but rather the number at index of i. If you were to do that, you would also want to do "< size" rather than "<= size" or else you would run into an IndexArrayOutOfBounds.
It depends on how your double linked list is implemented, but if it extends the normal List<Integer> interface it would look like:
final Integer ZERO = Integer.valueOf(0);
int countNegativeElements() {
return stream().filter(MyList::isNegative).count();
}
static boolean isNegative(Integer i) {
return i.compareTo(ZERO) < 0;
}
with streams. More traditionally with an collection for-each (or an iterator for-each):
int countNegativeElements() {
int count = 0;
for(Integer i : this) { // or iterator()
if (isNegative(i)) count++;
}
return count;
}
This does not expect concurrent modifications and is optimized for collections where iterating is the fastest access. If you have a simple type list then you can replace isNegative with a simple < 0.
This article here talks about different ways to iterate a collection.
In my code I assumed you will add the method directly to your list implementation class. Replace this or this.iterator() or this.stream() with your actual list instance if it is external.
Update:
I just saw your link to the actual linked list you are using, this would look like this (hand made iteration):
int countNegativeElements() {
Node n = start;
int count = 0;
while(n != null) {
if (n.getData() < 0) count++;
n = n.getLinkNext();
}
return count;
}
Using null since there is no hasLinkNext() which would be typical for homework :)
I don't think it is a particular good idea to work with implementations which do not fit in the Collections framework, but maybe it is required to keep the lessons simple.

Sorting an Array with duplicates using Insertion sort

package com.sort;
public class ArraySel {
private Long[] a;
private int nElems;
public ArraySel(int max)
{
a = new Long[max];
nElems = 0;
}
public void insert(long max)
{
a[nElems] = max;
nElems++;
}
public void display()
{
for(int j = 0; j < nElems; j++)
{
System.out.print(a[j]+ " ");
}
System.out.println();
}
public void insertionSort()
{
int in , out, flag = 0;
long temp;
for(out = 1; out < nElems; out++)
{
temp = a[out];
in = out;
while(in > 0 && a[in - 1] >= temp )
{
if(a[in] == a[in - 1 ])
{
flag++;
in--;
}
else
{
a[in] = a[in-1];
in--;
}
}
a[in] = temp;
}
}
}
This code takes an unsorted array and sorts it using Insertion Sort.
When duplicates are arranged together in unsorted array then due to multiple shifting complexity raises to O(N^2) , which i tried to make it O(N) by making sure no item moved more than once in case of duplicates arranged together.
But when duplicates are not arranged together complexity remains O(N^2).
Can we make the complexiy O(N) in this case too ?
Complexity isn't given by the number of moves but by the number of operations overall, in this case comparisons as well.
Insertion sort is O(n^2) average complexity, you can't make it faster than that. In works in O(n) only in best case scenario, when the input string is already sorted (http://en.wikipedia.org/wiki/Insertion_sort).
Without further information about the underlying data, the best time complexity you can achieve with sorting algorithms is O(n log n) (n being the number of elements).
Sorting algorithms like insertion sort, bubble sort, selection sort, etc., all have a time complexity of O(n²) due to their double loops. In fact they sometimes tend to work better, when getting an already sorted list of elements. Insertion sort for example has a time complexity of O(n) for a completely sorted list.
There is nothing you can do to change the inherent time complexity of those algorithms. The only thing you can do is short-cutting the algorithm when finding pre-sorted regions in the incoming list.

Building a bag class in Java

I'm in dire need of help with this project. I'm trying to implement a Bag class for a programming assignment, and I'm getting hung up on the addAll(), Union(), and equals(), methods.
Edit: According to the assignment, addAll() is supposed to add all of the the objects from the second array into the first. I'm no longer getting an error when I run it, but for some reason it will not add all of the elements from the second array, it will only add the first 2. Thanks guys, this one is working perfectly now!
Edit: For Union(), I'm supposed to create a third bag that will contain all the contents of the first 2 bags. I was getting an ArrayIndexOutOfBoundsException when running this method. I've updated the code following biddulph.r and it's also working great. Thanks again!
Edit: "First attempt" And for equals(), it's supposed to check the size of the bags to make sure they are equal in size, then check to see if they contain the same numbers. So as it's written now, my equals() method will compare sizes and return the boolean value for that, but I'm unsure of how to make it compare the actual values.
import java.util.Arrays;
import javax.swing.*;
public class bag {
int maxSize = 10; //Size of the arrays
int count = 0; //Number of items stored in the array
int[] a;
int[] b;
bag c;
bag d;
public bag() {
//for(int i = 0; i < maxSize; i++){
//a[i] = (int)(1+Math.random()*100);
//}
a = new int[maxSize];
}
public String bagString() {
return Arrays.toString(a);
}
public void add(int b) {
try {
a[count] = b;
count++;
} catch (ArrayIndexOutOfBoundsException n) {
JOptionPane.showMessageDialog(null, "Array is full, element will not be added");
}
}
public void removeRandom() {
int i = (int)(1 + Math.random() * (count - 1));
a[i] = a[count - 1];
a[count - 1] = 0;
count--;
}
public void remove(int b) {
for (int i = 0; i < maxSize; i++) {
if (contains(b)) {
a[i] = a[count - 1];
}
}
}
public boolean isEmpty() {
if (count == 0) return true;
else return false;
}
public boolean contains(int b) {
int tf = 0;
for (int i = 0; i < maxSize; i++) {
if (a[i] == b) tf = 1;
}
if (tf == 1) return true;
else return false;
}
public int size() {
return count;
}
public void addAll(bag c, bag d) {
if (a.length >= c.size() + d.size()) {
for (int i = 0; c.size() <= d.size(); i++) {
c.add(d.a[i]);
}
}
}
public void union(bag c, bag d) {
bag bigger = new bag();
for (int i = 0; i < c.size(); i++) {
bigger.add(c.a[i]);
}
for (int i = 0; count < d.size() - 1; i++) {
bigger.add(d.a[i]);
}
System.out.println(bigger.bagString());
}
public boolean equals(bag c, bag d){
if(c.size() != d.size()){
return false;
}else{
for(int i = 0; i < c.union(c, d).size(); i++){
if(c.union(c, d).contains(c.a[i]) && c.union(c, d).contains(d.a[i])){
return true;
}
}
return false;
}
}
}
I really appreciate any help you guys can give me, thanks.
EDIT: Thanks to everyone for your help, you guys are life savers.
Your problem for addAll() is here
if (a.length >= c.size() + d.size()) {
for (int i = 0; c.size() <= d.size(); i++) {
c.add(d.a[i]);
}
}
You shouldn't be adding elements until your c bag becomes bigger than d, you should be adding all of d's elements to c.
for (int i = 0; i < d.size(); i++) {
c.add(d.a[i]);
}
So the part of the assignment you are having issue with is:
public void addAll(bag c, bag d){
if (a.length >= c.size() + d.size()) {
for (int i = 0; c.size() <= d.size(); i++) {
c.add(d.a[i]);
}
}
}
which you say is supposed to add all of the the objects from the second array into the first.
If you break that down and apply it to your addAll() method, it sounds like you are supposed to be adding all of the items in bag "d" into bag "c".
Your for loop is saying start i at 0, and add 1 to it until the size of c is less than or equal to d.
What it should be saying is start i at 0, and add 1 to it until you have gone through every item in d.
That would look like this:
for (int i = 0; i < d.size(); i++){
c.add(d.a[i]);
}
i is increased every time you go through the for loop, and i will stop increasing when you have got to the size of d (the second condition). At this point you will exit the for loop. You don't have to worry about the size of c.
In fact you can probably get rid of the if (a.length >= c.size() + d.size()) line as well.
I hope my explanation helps you understand why the changes have been made to the method.
I think you have a lot of problems with the design of the class that you should address first. If you are representing the bag as a static or dynamic array then you only need one array, not 2. You also don't need two bags inside each bag as attributes, that doesn't make any sense; all you should have left is the size of the bag or count and the array to hold all the elements (which are integers in your case). Also, avoid naming parameters for functions and attributes for the class the same way. Not doing so might confuse the compiler and will require code like self.attributeName to use attributes; otherwise, the compiler assumes you're talking about the parameter.
If you make these changes, the rest should be straight-forward from here. Since it's an assignment, you should make these changes and try again because you won't learn if we provide the answers for you; you'll see it will be much easier once you structure it correctly.
P.S. it's a convention to start a class name with a capital letter. Bag and not bag
addAll
There's a couple of problems with this function as written. First is that it's confusing to the caller. The code using this method would be something like this:
Bag bag1 = ...
Bag bag2 = ...
Bag bag3 = ...
bag1.addAll(bag2, bag3)
...or perhaps bag2.addAll(bag2, bag3). The function is intended to add elements from one bag in to another bag, so why does the caller have to specify three different bags? There's only two involved. You should either make the function static, so it can be called like Bag.addAll(bag1, bag2) or (better) make it totally clear who's getting elements added by making it take a single argument bag1.addAll(bag2).
Second problem is that the function isn't implemented correctly, but I think that's because you're getting confused because you've got three bags involved instead of two. To sketch out how it should be fixed:
Bag target = ...
Bag source = ...
if (target.a.length >= target.size() + source.size()) {
for (int i = 0; i < source.a.length; i++) {
target.add(source.a[i]);
}
}
Good variable naming is your friend.
union
You haven't specified what problem you're having with your implementation, so I'm not going to simply rewrite it for you. Edit your question with the problem, and I'll help.
However, this is an excellent example of a method that should be static (a Factory method, in fact). It should be able ot be called like: Bag biggerBag = Bag.union(bag1, bag2).
EDIT after his comment regarding the .union problem
The problem with .union is that you're looping through each bag using some else's size. It boils down to, if you want add each element from source in to target, you should be only counting elements from source, as so:
bag bigger = new bag();
for (int i = 0; i <= c.size(); i++) {
bigger.add(c.a[i]);
}
note that your method does not protect against the bigger bag not being big enough. You should have a check to make sure that it is BEFORE the loops, or even better just create a big enough bag.
equals
Again, you need to show that you've tried to write it, and then ask a question specifying what you need help with. Update your question and I'll help.
Your method:
public void addAll(bag c, bag d) {
if (a.length >= c.size() + d.size()) {
for (int i = 0; c.size() <= d.size(); i++) {
c.add(d.a[i]);
}
}
}
betrays your lack of understanding of Object Oriented programming.
Remember that the method addAll() is already acting on a bag, and so you should not need to specify 2 bags in the arguments.
Calling example:
mybag.addAll(yourBag);
would demonstrate a possible usage - it would add all contents of yourBag into myBag.
I'll give you this method for free (assuming that the array 'a' contains the contents of the bag - something I'm not sure about because your variable names aren't clear):
public void addAll(Bag otherBag) {
for (int i : otherBag.a) {
add(i);
}
}
The above method will copy all contents of otherBag into this bag.
Another thing I noticed - you also have a b[] instance variable - what's that for?
You also have 2 other bag instance variables. Not sure why.

why does AbstractList.removeRange require quadratic time?

I can see in the documentation for:
java.util.AbstractList#removeRange
That it requires quadratic time:
This implementation gets a list iterator positioned before fromIndex,
and repeatedly calls ListIterator.next followed by ListIterator.remove
until the entire range has been removed. Note: if ListIterator.remove
requires linear time, this implementation requires quadratic time.
But why?? The code:
protected void removeRange(int fromIndex, int toIndex) {
ListIterator<E> it = listIterator(fromIndex);
for (int i=0, n=toIndex-fromIndex; i<n; i++) {
it.next();
it.remove();
}
}
Seems for me to be linear... But I have to be wrong as I'm a newbie in this kind of algorithmic stuff. Please help me to understand it.
The important part is "Note: if ListIterator.remove requires linear time, this implementation requires quadratic time." The for loop requires linear time, you're right. But, if you do a linear time step on each iteration, you get n * n = n^2.
The reason is in :
it.remove();
that can be an O(n) operation on a list, which you call within an O(n) loop.
In other words, your real loop would look like this if it is the case (I made it up but you get the idea):
protected void removeRange(int fromIndex, int toIndex) {
ListIterator<E> it = listIterator(fromIndex);
for (int i = 0, n = toIndex - fromIndex; i < n; i++) {
E item = it.next();
//it.remove();
for (int j = ; j < n; j++) {
if (list.get(j).equals(e)) {
list.remove(e);
break;
}
}
}
}

Categories

Resources