I'm trying to solve https://leetcode.com/problems/lru-cache/description/.
I'm using treeset to save unique keys and order them based on when it's inserted. The treeset is not returning elements in the way I specified using Camparator.
class LRUCache {
Map<Integer, Integer> keyValue;// ()
TreeSet<Pair> keys; //key, timestamp (1,-1000)
int capacity;//2
int timestamp;
public LRUCache(int capacity) {
keyValue = new HashMap<>(capacity);
keys = new TreeSet<>((Pair a,Pair b) -> {
System.out.println("inside comparator implementation");
int result = a.x == b.x ? 0 : a.y - b.y == 0 ? -1 : a.y - b.y;
System.out.println("result: " + result);
return result;
});
this.capacity = capacity;
}
public int get(int key) {
timestamp++;
Pair pair = new Pair(key, timestamp);
boolean found = keys.contains(pair);
if (found) {
System.out.println("keys contains " + key + ". So, removing it to update");
keys.remove(pair);
} else {
System.out.println("keys doesn't contains " + key + ". So, not removing it. Directly adding it");
}
boolean added = keys.add(pair);
System.out.println("add status: " + added + " for: " + pair);
return keyValue.getOrDefault(key, -1);
}
public void put(int key, int value) {
int priority = Integer.MIN_VALUE + timestamp++;
Pair pair = new Pair(key, priority);
System.out.println("key: " + key + " priority: " + priority);
boolean found = keys.contains(pair);
if (!found) {
System.out.println("keys doesn't " + key + " and " + value + ". So, adding to keys");
keys.add(pair);
} else {
System.out.println("keys contains " + key + " and " + value + ". So, not adding to keys");
}
keyValue.put(key, value);
if (keys.size() > capacity) {
System.out.println("size > capacity");
Pair remove = keys.first();
System.out.println("removing: " + remove);
keys.remove(remove);
keyValue.remove(remove.x);
}
}
public static void main(String[] args) {
LRUCache lruCache = new LRUCache(2);
System.out.println();
System.out.println("putting 1,1");
lruCache.put(1, 1);
System.out.println();
System.out.println("putting 2,2");
lruCache.put(2, 2);
System.out.println();
System.out.println("getting 1");
System.out.println(lruCache.get(1));
System.out.println();
System.out.println("c");
lruCache.put(3, 3);
System.out.println();
System.out.println("getting 2");
System.out.println(lruCache.get(2));
}
}
class Pair{
int x;
int y;
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
public boolean equals(Object o) {
System.out.println("inside pair equals");
if (this == o) {
return true;
}
if (!(o instanceof Pair)) {
return false;
}
return this.x == ((Pair) o).x;
}
public int hashCode() {
return x;
}
@Override
public String toString() {
return "Pair{" +
"x=" + x +
", y=" + y +
'}';
}
}
I'm expecting (2, -2147483647) to be dropped after adding (3,3), since (2, -2147483647) has negative timestamp.
This is the set that is printed before I expected (2, -2147483647) is removed.
[Pair{x=1, y=3}, Pair{x=2, y=-2147483647}, Pair{x=3, y=-2147483645}]
Why is Pair{x=1, y=3}
first compared to {x=2, y=-2147483647}
.
I wrote the comparator to order in treeset based on y values, why is it working as expected?
I tried creating a TreeSetPractise
public class TreeSetPractise {
public static void main(String[] args) {
TreeSet<Pair> ts = new TreeSet<>(( a, b) -> {
System.out.println("inside comparator implementation");
int result = a.x == b.x ? 0 : a.y - b.y == 0 ? -1 : a.y - b.y;
System.out.println("result: " + result);
return result;
});
ts.add(new Pair(1,10));
ts.add(new Pair(2, -20));
ts.add(new Pair(3, 30));
System.out.println(ts);
for (Pair i : ts) {
System.out.println(i);
}
}
}
class Pair {
int x;
int y;
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "Pair{" +
"x=" + x +
", y=" + y +
'}';
}
}
This is working as expected.
The main problem here is, for the elements of TreeSet:Pair{x,y} has to check equality on x and ordering on y.
Meaning Set functionality is based on x and Tree functionality is based on y.
Update: Most of the comments/answers points out here that my comparator is wrong. The only problem with it might be overflow, but there is no problem with logic.
Also, the bigger problem for me is, TreeSet is considering two objects to be equal if comparator is returning 0. Shouldn't it call equals method on if compareTo returns 0?
Looking at the comparator logic:
int result = a.x == b.x ? 0 : a.y - b.y == 0 ? -1 : a.y - b.y;
There are a few issues with a.y - b.y == 0 ? -1 : a.y - b.y
.
a.y
equals b.y
then it considers a < b
, which is likely not intended.b.y
can be a large negative number like Integer.MIN_VALUE
.If the goal is to compare y
if x
is not the same, you can replace that part with a.y == b.y ? 0 : (a.y < b.y) ? - 1 : 1
. However, a safer (less error prone) approach is to just use Integer.compare
to compare a.y
and b.y
.
int result = a.x == b.x ? 0 : Integer.compare(a.y, b.y);
Oh boy. Let's start with the big issues:
And finally, your code is rather complicated for what it does.
The simple way to implement a LRUCache in Java is this:
class LRUCache<K,V> extends LinkedHashMap<K,V> {
final int capacity;
LRUCache(int capacity) {
super(10, 0.75f, true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Entry<K, V> eldest) {
return size() > capacity;
}
}
As you can see from the class name of the super class, the data is kept in a map for fast lookup, with a linked list for keeping track of access order. To maintain the list in access order, we remove the node on access (which is O(1)), and then add it to the tail of the list (which is O(1)).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With