Leetcode: Why this algorithm is slow? - java

So I am trying to solve this problem: http://oj.leetcode.com/problems/merge-intervals/
My solution is:
public class Solution {
public ArrayList<Interval> merge(ArrayList<Interval> intervals) {
// Start typing your Java solution below
// DO NOT write main() function
// ArrayList<Interval> result = new ArrayList<Interval>();
//First sort the intervals
Collections.sort(intervals,new Comparator<Interval>(){
public int compare(Interval interval1, Interval interval2) {
if(interval1.start > interval2.start) return 1;
if(interval1.start == interval2.start) return 0;
if(interval1.start < interval2.start) return -1;
return 42;
}
});
for(int i = 0; i < intervals.size() - 1; i++){
Interval currentInterval = intervals.get(i);
Interval nextInterval = intervals.get(i+1);
if(currentInterval.end >= nextInterval.start){
intervals.set(i,new Interval(currentInterval.start,nextInterval.end));
intervals.remove(i+1);
i--;
}
}
return intervals;
}
}
I have seen some blogs using exactly the same solution but get accepted but mine is rejected because it takes too long. Can you enlighten me why it takes longer than expected?
Cheers
EDIT: solved, remove is too costly, using a new arraylist to store the result is faster

Initially you are sorting all your intervals - due to javadocs, this operation has complexity O(N*log(N))
But, after that, as I have noticed - you are iterating over ArrayList, and sometimes removing elements from it.
But removing some element from ArrayList has complexity O(N) (as underlying implementation of ArrayList is plain array - removing any elemnt from the middle of array, requires shifting of the entire right part of this array).
As you do that in loop - finally, complexity of your algirithm would be O(N^2).
I'd suggest you to use LinkedList instead of ArrayList in this case.

You could improve your sorting by using one computation instead of 3 comparisons:
Collections.sort(intervals,new Comparator<Interval>(){
public int compare(Interval interval1, Interval interval2) {
return interval1.start - interval2.start;
}
});

Related

Recursive function that finds the minimum value in an ArrayList of Integers in Java

This is a problem that I have been thinking about as part of self-learning java. The problem consists of writing a recursive function that finds the minimum value in an ArrayList of Integers. Below you will find my attempt. I believe that it is working as intended, but I wonder if there are better ways to get this done. Any comments are appreciated.
public static int findMin(ArrayList<Integer> numbers){
// Base Case
if(numbers.size()==1){
return numbers.get(0).intValue();
}
ArrayList<Integer> numbers_short = new ArrayList<Integer>(numbers);
numbers.remove(numbers.size()-1);
return Math.min(numbers_short.get(numbers_short.size()-1).intValue(), findMin(numbers));
}
Your example is not so good in the way that you should not use recursivity in this case.
But anyway, you can avoid to copy your array each time, by using a method with a start and end parameters to analyze only a part of your initial array.
Something like that:
public static int findMin(ArrayList<Integer> numbers) {
return findMin(numbers, 0, numbers.size() - 1);
}
public static int findMin(ArrayList<Integer> numbers, int start, int end) {
if (end == start)
return numbers.get(start);
int middle = start + (end - start) / 2;
return Math.min(findMin(numbers, start, middle), findMin(numbers, middle + 1, end));
}
And add a check in case the array is empty if needed.
The reason why I'm using the "middle" method is that each time it divides the array by 2, meaning at the end it limits the risk of stack overflow because it will divide by 2 the maximum number of recursivity compare to recurse on every element.
You may want to avoid creating a new ArrayList object every time you call the method. This may seem non consequential for smaller inputs, but for really large inputs it may lead to StackOverflowError.
A cleaner solution with similar time complexity can be:
public static int findMin(ArrayList<Integer> numbers) {
return findMin(numbers, numbers.size());
}
public static int findMin(ArrayList<Integer> numbers, int len) {
// Base Case
if (len == 1) {
return numbers.get(0);
}
return Math.min(numbers.get(len-1), findMin(numbers, len-1));
}
Reference to garbage collector and recursion: Garbage Collection in Java with Recursive Function
Keeping the original method signature and formal parameters - the code can be simplified by eliminating the need to create a new temporary array each time.
public static int findMin(ArrayList<Integer> numbers){
if (numbers.size() == 1) return numbers.get(0);
return Math.min(numbers.remove(0), findMinimum(numbers));
}
numbers.remove(0) will simultaneously remove the first element and return the value of the removed element, eliminating the need to create a temporary array.

java - Remove nearly duplicates from a List

I have a List of Tweet objects (homegrown class) and I want to remove NEARLY duplicates based on their text, using the Levenshtein distance. I have already removed the identical duplicates by hashing the tweets' texts but now I want to remove texts that are identical but have up to 2-3 different characters. Since this is a O(n^2) approach, I have to check every single tweet text with all the others available. Here's my code so far:
int distance;
for(Tweet tweet : this.tweets) {
distance = 0;
Iterator<Tweet> iter = this.tweets.iterator();
while(iter.hasNext()) {
Tweet currentTweet = iter.next();
distance = Levenshtein.distance(tweet.getText(), currentTweet.getText());
if(distance < 3 && (tweet.getID() != currentTweet.getID())) {
iter.remove();
}
}
}
The first problem is that the code throws ConcurrentModificationException at some point and never completes. The second one: can I do anything better than this double loop? The list of tweets contains nearly 400.000 tweets so we're talking about 160 billion iterations!
This solution works for the question in hand(so far tested with possible inputs) but the normal set operations to remove duplicates wont work if you dont implement the full contract for compare to return 1,0 and -1.
Why dont you implement your own compare operation using the Set which can have only distinct values. It is going to be O(n log(n)).
Set set = new TreeSet(new Comparator() {
#Override
public int compare(Tweet first, Tweet second) {
int distance = Levenshtein.distance(first.getText(), second.getText());
if(distance < 3){
return 0;
}
return 1;
}
});
set.addAll(this.tweets);
this.tweets = new ArrayList<Tweet>(set);
As for the ConcurrentModificationException: As the others pointed out, I was removing elements from a list that I was also iterating in the outer for-each. Changing the for-each into a normal for resolved the problem.
As for the O(n^2) approach: There's no "better" algorithm regarding its complexity, than a O(n^2) approach. What I'm trying to do is an "all-to-all" comparison to find nearly duplicate elements. Of course there are optimizations to lower the total capacity of n, parallelization to concurrently parse sub-lists of the original list, but the complexity is quadratic at all times.

ArrayLinkedList Insertion Sort

I have to do an Array List for an insertion sort and my teacher sent this back to me and gave me an F, but says I can make it up before Friday.
I do not understand why this isn't an A.L insertion sort.
Can someone help me fix this so it hits his criteria?
Thanks.
HE SAID:
After checking your first insertion sort you all did it incorrectly. I specifically said to shift the numbers and move the number into its proper place and NOT SWAP THE NUMBER INTO PLACE. In the assignment in MySA I said if you do this you will get a 0 for the assignment.
import java.util.ArrayList;
public class AListINSSORT {
private static void insertionSort(ArrayList<Integer> arr) {
insertionSort();
}
private static void insertionSort() {
ArrayList<Integer> swap = new ArrayList<Integer>();
swap.add(1);
swap.add(2);
swap.add(3);
swap.add(4);
swap.add(5);
int prior = 0;
int latter = 0;
for (int i = 2; i <= latter; i++)
{
for (int k = i; k > prior && (swap.get(k - 1) < swap.get(k - 2)); k--)
{
Integer temp = swap.get(k - 2);
swap.set(k - 2, swap.get(k - 1));
swap.set(k - 1, temp);
}
}
System.out.println(swap);
}
}
First of all, it seems your teacher asked you to use a LinkedList instead of an ArrayList. There is quite a difference between them.
Secondly, and maybe more to the point. In your inner loop you are saving a temp variable and swapping the elements at position k - 2 and k - 1 with each other. From the commentary this is not what your teacher intended. Since he wants you to solve the problem with element insertion, I recommend you look at the following method definition of LinkedList.add(int i, E e): https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#add(int,%20E).
This should point you in the right direction.
As far as I see, your code does nothing at all.
The condition of the outer for loop
for (int i = 2; i <= latter; i++)
is not fulfilled.
As you start with i = 2 and as latter = 0, it never holds i <= latter.
Thus, you never run through the outer for loop and finally just give back the input values.
If you add the input values to swap in a different order (not already ordered), you will see that your code does not re-order them.
There's a lot of stuff wrong here.
Firstly, your method:
private static void insertionSort(ArrayList<Integer> arr) {
insertionSort();
}
takes an ArrayList and completely ignores it. This should presumably be the List which requires sorting.
Then in insertionSort() you create a new ArrayList, insert some numbers already in order, and then attempt something which looks nothing like insertion sort, but slightly more like bubble sort.
So, when you call insertionSort(List) it won't actually do anything to the list at all, all the work in insertionSort() happens to a completely different List!
Since on SO we don't generally do people's homework for them, I suggest looking at the nice little animated diagram on this page
What you should have then is something like:
public void insertionSort(LinkedList<Integer> numbers) {
//do stuff with numbers, using get() and add()
}

Stackoverflow error while implementing insertion sort using recursion

public static void insertionSortRecursion(String a[], int first, int last) {
if (first < last) {
//sort all but last
insertionSortRecursion(a, first, last - 1);
insertInOrder(a[last], a, first, last -1);
}
}
private static void insertInOrder(String element, String[] a, int first, int last) {
// System.out.println(last - 1);
// System.out.println(element);
// System.out.println(a[last]);
if (element.compareTo(a[last]) >= 0) {
a[last + 1] = element;
} else if(first < last) {
a[last + 1] = a[last];
insertInOrder(element, a, first, last - 1);
} else {
a[last + 1] = a[last];
a[last] = element;
}
}
Hey Guys,
I am trying to implement insertion sort using recursion it's working fine on small number of words but I am getting stackoverflow after implementing it because the size of file I am sorting have a lot of words around 10,000. Please suggest what should I do to remove the error.
These are the methods I am using for insertion sort using recursion and I am calling them in my constructor.
Assuming your algorithm is correct, leave this function as it is. Don't try to fix it. In general to get rid of stack overflow (while keeping recursion) there are two solutions :
Use tail call optimization
Increase the stack size
But let sit back and assume this code is going to be anything else than a programming exercise. Any other person who have to read will think :
Why does he use insertion sort ?
Why does he re-implement insertion-sort?
Did it have to be recursion?? my lord!!
Why did he waste his time to find a tail-call insertion algorithm? Or
Did he just increased the stack size for the only sake of running his method?
Good. Now we have 1000,000 items to sort and the program keep crashing.
Conclusion, they will erase your code at once and use Collections.sort().
As I said, if you are doing a programming exercise then good, your recursive insertion
sort work till some point. move on.
Java is not able to handle a recursion depth that deep (10000) by default. Consider the below oversimplified example still throws a StackOverflowError.
static void test(int i)
{
if (i == 0) return;
test(i-1);
}
public static void main(String[] args)
{
test(10000);
}
You must specify command-line parameters to achieve this (-Xss and possibly -Xmx to allocate more memory).
I ran your algorithm successfully for an array of size 100000 using -Xmx1000m -Xss10000000 (though it took a while).
I assume there a reason you're using recursion and not a simple double for loop.

Problem with recursive backtracking

Hey guys, recently posted up about a problem with my algorithm.
Finding the numbers from a set which give the minimum amount of waste
Ive amended the code slightly, so it now backtracks to an extent, however the output is still flawed. Ive debugged this considerablychecking all the variable values and cant seem to find out the issue.
Again advice as opposed to an outright solution would be of great help. I think there is only a couple of problems with my code, but i cant work out where.
//from previous post:
Basically a set is passed to this method below, and a length of a bar is also passed in. The solution should output the numbers from the set which give the minimum amount of waste if certain numbers from the set were removed from the bar length. So, bar length 10, set includes 6,1,4, so the solution is 6 and 4, and the wastage is 0. Im having some trouble with the conditions to backtrack though the set. Ive also tried to use a wastage "global" variable to help with the backtracking aspect but to no avail.
SetInt is a manually made set implementation, which can add, remove, check if the set is empty and return the minimum value from the set.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package recursivebacktracking;
/**
*
* #author User
*/
public class RecBack {
int WASTAGE = 10;
int BESTWASTAGE;
int BARLENGTH = 10;
public void work()
{
int[] nums = {6,1,2,5};
//Order Numbers
SetInt ORDERS = new SetInt(nums.length);
SetInt BESTSET = new SetInt(nums.length);
SetInt SOLUTION = new SetInt(nums.length);
//Set Declarration
for (int item : nums)ORDERS.add(item);
//Populate Set
SetInt result = tryCutting(ORDERS, SOLUTION, BARLENGTH, WASTAGE);
result.printNumbers();
}
public SetInt tryCutting(SetInt possibleOrders, SetInt solution, int lengthleft, int waste)
{
for (int i = 0; i < possibleOrders.numberInSet(); i++) // the repeat
{
int a = possibleOrders.min(); //select next candidate
System.out.println(a);
if (a <= lengthleft) //if accecptable
{
solution.add(a); //record candidate
lengthleft -= a;
WASTAGE = lengthleft;
possibleOrders.remove(a); //remove from original set
if (!possibleOrders.isEmpty()) //solution not complete
{
System.out.println("this time");
tryCutting(possibleOrders, solution, lengthleft, waste);//try recursive call
BESTWASTAGE = WASTAGE;
if ( BESTWASTAGE <= WASTAGE )//if not successfull
{
lengthleft += a;
solution.remove(a);
System.out.println("never happens");
}
} //solution not complete
}
} //for loop
return solution;
}
}
Instead of using backtracking, have you considered using a bitmask algorithm instead? I think it would make your algorithm much simpler.
Here's an outline of how you would do this:
Let N be number of elements in your set. So if the set is {6,1,2,5} then N would be 4. Let max_waste be the maximum waste we can eliminate (10 in your example).
int best = 0; // the best result so far
for (int mask = 1; mask <= (1<<N)-1; ++mask) {
// loop over each bit in the mask to see if it's set and add to the sum
int sm = 0;
for (int j = 0; j < N; ++j) {
if ( ((1<<j)&mask) != 0) {
// the bit is set, add this amount to the total
sm += your_set[j];
// possible optimization: if sm is greater than max waste, then break
// out of loop since there's no need to continue
}
}
// if sm <= max_waste, then see if this result produces a better one
// that our current best, and store accordingly
if (sm <= max_waste) {
best = max(max_waste - sm);
}
}
This algorithm is very similar to backtracking and has similar complexity, it just doesn't use recursion.
The bitmask basically is a binary representation where 1 indicates that we use the item in the set, and 0 means we don't. Since we are looping from 1 to (1<<N)-1, we are considering all possible subsets of the given items.
Note that running time of this algorithm increases very quickly as N gets larger, but with N <= around 20 it should be ok. The same limitation applies with backtracking, by the way. If you need faster performance, you'd need to consider another technique like dynamic programming.
For the backtracking, you just need to keep track of which element in the set you are on, and you either try to use the element or not use it. If you use it, you add it to your total, and if not, you proceeed to the next recursive call without increasing your total. Then, you decrement the total (if you incremented it), which is where the backtracking comes in.
It's very similar to the bitmask approach above, and I provided the bitmask solution to help give you a better understanding of how the backtracking algorithm would work.
EDIT
OK, I didn't realize you were required to use recursion.
Hint1
First, I think you can simplify your code considerably by just using a single recursive function and putting the logic in that function. There's no need to build all the sets ahead of time then process them (I'm not totally sure that's what you're doing but it seems that way from your code). You can just build the sets and then keep track of where you are in the set. When you get to the end of the set, see if your result is better.
Hint2
If you still need more hints, try to think of what your backtracking function should be doing. What are the terminating conditions? When we reach the terminating condition, what do we need to record (e.g. did we get a new best result, etc.)?
Hint3
Spoiler Alert
Below is a C++ implementation to give you some ideas, so stop reading here if you want to work on it some more by yourself.
int bestDiff = 999999999;
int N;
vector< int > cur_items;
int cur_tot = 0;
int items[] = {6,1,2,5};
vector< int > best_items;
int max_waste;
void go(int at) {
if (cur_tot > max_waste)
// we've exceeded max_waste, so no need to continue
return;
if (at == N) {
// we're at the end of the input, see if we got a better result and
// if so, record it
if (max_waste - cur_tot < bestDiff) {
bestDiff = max_waste - cur_tot;
best_items = cur_items;
}
return;
}
// use this item
cur_items.push_back(items[at]);
cur_tot += items[at];
go(at+1);
// here's the backtracking part
cur_tot -= items[at];
cur_items.pop_back();
// don't use this item
go(at+1);
}
int main() {
// 4 items in the set, so N is 4
N=4;
// maximum waste we can eliminiate is 10
max_waste = 10;
// call the backtracking algo
go(0);
// output the results
cout<<"bestDiff = "<<bestDiff<<endl;
cout<<"The items are:"<<endl;
for (int i = 0; i < best_items.size(); ++i) {
cout<<best_items[i]<<" ";
}
return 0;
}

Categories