Skip to content

Commit 6fa502d

Browse files
committed
Merge Deque changes to new structure and resolve conflicts
2 parents 203cdd1 + 77384d2 commit 6fa502d

File tree

5 files changed

+304
-36
lines changed

5 files changed

+304
-36
lines changed

src/main/java/algorithms/patternFinding/KMP.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
* there is no prefix ending before its index, 0, that can be matched with.
1818
* Read: ^ ^ 'B' and 'C' cannot be matched with any prefix which are just 'A' and 'AB' respectively.
1919
* Read: ^ Can be matched with an earlier 'A'. So we store 1.
20-
* Prefix is the substring from idx 0 to 1 (exclusive).
21-
* Which can also be interpreted as the index of the next character to match against!
20+
* Prefix is the substring from idx 0 to 1 (exclusive). Note consider prefix from 0-indexed.
21+
* Realise 1 can also be interpreted as the index of the next character to match against!
2222
* Read: ^ ^ Similarly, continue matching
2323
* Read: ^ ^ No matches, so 0
2424
* Read: ^ ^ ^ ^ ^ ^ Match with prefix until position 6!
@@ -34,12 +34,13 @@
3434
* String : ABABCABABABAB
3535
*
3636
* A B A B C A B A B A B A B
37-
* Read: ^ to ^ Continue matching until with Pattern[0:4]
38-
* Read: ^ try ^ Unable to match Pattern[4]. But since last two characters form a sub-pattern
39-
* Read: try matching until Pattern[0:3] by checking if Pattern[2] == 'C'.
40-
* Read: Turns out no. No previously identified sub-pattern with 'C'. Restart.
37+
* Read: ^ to ^ Continue matching where possible, leading to Pattern[0:4] matched.
38+
* unable to match Pattern[4]. But notice that last two characters of String[0:4]
39+
* form a sub-pattern with Pattern[0:2] Maybe Pattern[2] == 'C' and we can 're-use' Pattern[0:2]
40+
* Read: ^ try ^ by checking if Pattern[2] == 'C'
41+
* Read: Turns out no. No previously identified sub-pattern with 'C'. Restart matching Pattern.
4142
* Read: ^ to ^ Found complete match! But rather than restart, notice that last 4 characters
42-
* Read: form a prefix sub-pattern of Pattern, so,
43+
* Read: form a prefix sub-pattern of Pattern, which is Pattern[0:4] = "ABAB", so,
4344
* Read: ^ ^ Start matching from Pattern[4] and finally Pattern[5]
4445
*/
4546
public class KMP {
@@ -53,6 +54,7 @@ private static int[] getPrefixIndices(String pattern) {
5354
int len = pattern.length();
5455
int[] prefixIndices = new int[len + 1];
5556
prefixIndices[0] = -1;
57+
prefixIndices[1] = 0; // 1st character has no prefix to match with
5658

5759
int currPrefixMatched = 0; // num of chars of prefix pattern currently matched
5860
int pos = 2; // Starting from the 2nd character, recall 1-indexed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package dataStructures.queue;
2+
3+
public class Deque<T> {
4+
5+
private Node<T> first;
6+
private Node<T> last;
7+
private int size;
8+
9+
/**
10+
* Constructor for empty Deque.
11+
*/
12+
public Deque() {
13+
this.size = 0;
14+
this.first = this.last = null; // implemented with double-linked list
15+
}
16+
17+
/**
18+
* Check if deque is empty.
19+
*
20+
* @return True if empty.
21+
*/
22+
public boolean isEmpty() {
23+
return this.size == 0;
24+
}
25+
26+
/**
27+
* Get size of deque.
28+
*
29+
* @return Size of the deque.
30+
*/
31+
public int getSize() {
32+
return this.size;
33+
}
34+
35+
/**
36+
* Add element into the back of the deque.
37+
*
38+
* @param val Element to be added.
39+
*/
40+
public void addElement(T val) {
41+
Node<T> newNode = new Node<>(val);
42+
if (this.isEmpty()) {
43+
this.last = this.first = newNode;
44+
size++;
45+
return;
46+
}
47+
Node<T> temp = this.last;
48+
temp.next = newNode;
49+
newNode.prev = temp;
50+
this.last = newNode;
51+
this.size++;
52+
}
53+
54+
/**
55+
* Add a element into the front of the deque.
56+
* @param val Element to be added.
57+
*/
58+
public void addFirst(T val) {
59+
Node<T> newNode = new Node<>(val);
60+
if (this.isEmpty()) {
61+
this.last = this.first = newNode;
62+
size++;
63+
return;
64+
}
65+
Node<T> temp = this.first;
66+
temp.prev = newNode;
67+
newNode.next = temp;
68+
this.first = newNode;
69+
size++;
70+
}
71+
72+
/**
73+
* Peek the first element of the deque.
74+
*
75+
* @return The value in the first node of the deque.
76+
*/
77+
public T peekFirst() {
78+
if (this.isEmpty()) {
79+
return null;
80+
}
81+
return first.val;
82+
}
83+
84+
/**
85+
* Peek the last element of the deque.
86+
*
87+
* @return The value in the last node of the deque.
88+
*/
89+
public T peekLast() {
90+
if (this.isEmpty()) {
91+
return null;
92+
}
93+
return last.val;
94+
}
95+
96+
/**
97+
* Removes and retrieves the first element of the deque.
98+
*
99+
* @return The value in the first node of the deque.
100+
*/
101+
public T pollFirst() {
102+
if (this.isEmpty()) {
103+
return null;
104+
}
105+
Node<T> firstNode = this.first;
106+
Node<T> newFirstNode = this.first.next;
107+
if (newFirstNode != null) {
108+
newFirstNode.prev = null;
109+
}
110+
this.first = newFirstNode;
111+
firstNode.next = null;
112+
this.size--;
113+
return firstNode.val;
114+
}
115+
116+
/**
117+
* Removes and retrieves the last element of the deque.
118+
*
119+
* @return The value in the last node of the deque.
120+
*/
121+
public T pollLast() {
122+
if (this.isEmpty()) {
123+
return null;
124+
}
125+
Node<T> lastNode = this.last;
126+
Node<T> newLastNode = lastNode.prev;
127+
if (newLastNode != null) {
128+
newLastNode.next = null;
129+
}
130+
lastNode.prev = null;
131+
this.last = newLastNode;
132+
this.size--;
133+
return lastNode.val;
134+
}
135+
136+
/**
137+
* Converts Deque into String iteratively.
138+
*
139+
* @return String representation of elements in the deque.
140+
*/
141+
@Override
142+
public String toString() {
143+
if (this.isEmpty()) {
144+
return "[]";
145+
}
146+
String ret = "[";
147+
Node<T> temp = this.first;
148+
while (temp != null) {
149+
ret += " " + temp.toString() + " ";
150+
temp = temp.next;
151+
}
152+
return ret + "]";
153+
}
154+
155+
private static class Node<T> {
156+
private T val;
157+
Node<T> next;
158+
Node<T> prev;
159+
160+
public Node(T val) {
161+
this.val = val;
162+
this.next = this.prev = null;
163+
}
164+
165+
@Override
166+
public String toString() {
167+
return this.val.toString();
168+
}
169+
}
170+
}

src/main/java/dataStructures/queue/MonotonicQueue.java

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import java.util.ArrayDeque;
55

66
/**
7-
* Implementation of a non-increasing monotonic queue for certain (but common) use case:
7+
* Implementation of a non-increasing (decreasing) monotonic queue for certain (but common) use case:
88
* When larger objects pushed to the queue are able to replace and represent smaller objects that come before it.
99
* Callable methods are:
1010
* isEmpty()
@@ -20,8 +20,9 @@
2020
* 4 2 [1, 2] #2->1 [5, 3, 2] 2 kick out 1 #2->3
2121
* 5 4 [1, 2, 4] #4->2 [5,4] 4 kick out 2, 3 #4->2
2222
*/
23+
2324
public class MonotonicQueue<T extends Comparable<T>> {
24-
private Deque<Pair<T>> dq = new ArrayDeque<>(); // or LinkedList
25+
private Deque<T> dq = new ArrayDeque<>(); // or LinkedList
2526

2627
/**
2728
* Checks if queue is empty.
@@ -37,12 +38,10 @@ public boolean isEmpty() {
3738
*/
3839
public void push(T obj) {
3940
Integer count = 0;
40-
while (!dq.isEmpty() && obj.compareTo(dq.peekLast().value) >= 0) {
41-
Pair<T> popped = dq.pollLast();
42-
// accumulate count of objects that were popped to maintain the non-increasing property
43-
count += 1 + popped.countDeleted;
41+
while (!dq.isEmpty() && obj.compareTo(dq.peekLast()) > 0) {
42+
dq.pollLast(); // Removes elements that do not conform the non-increasing sequence.
4443
}
45-
dq.offerLast(new Pair<T>(obj, count));
44+
dq.offerLast(obj);
4645
}
4746

4847
/**
@@ -53,7 +52,7 @@ public T max() {
5352
if (isEmpty()) {
5453
return null;
5554
}
56-
return dq.peek().value;
55+
return dq.peek();
5756
}
5857

5958
/**
@@ -64,26 +63,6 @@ public T pop() {
6463
if (dq.isEmpty()) {
6564
return null;
6665
}
67-
Pair<T> node = dq.peek();
68-
if (node.countDeleted > 0) {
69-
node.countDeleted -= 1;
70-
return node.value;
71-
}
72-
dq.poll();
73-
return node.value;
74-
}
75-
76-
/**
77-
* Node class that is represented as a pair.
78-
* Tracks the deleted count and the value to be wrapped.
79-
*/
80-
private static class Pair<T> {
81-
private T value;
82-
private Integer countDeleted;
83-
84-
private Pair(T val, Integer count) {
85-
this.value = val;
86-
this.countDeleted = count;
87-
}
66+
return dq.poll(); // Returns & remove head of deque
8867
}
8968
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package dataStructures.queue;
2+
3+
import org.junit.Assert;
4+
import org.junit.Test;
5+
6+
public class MonotonicQueueTest {
7+
@Test
8+
public void testEmpty() {
9+
MonotonicQueue<Integer> q = new MonotonicQueue<>();
10+
Assert.assertEquals(true, q.isEmpty());
11+
Assert.assertEquals(null, q.max());
12+
Assert.assertEquals(null, q.pop());
13+
}
14+
15+
@Test
16+
public void testMax() {
17+
MonotonicQueue<Integer> q = new MonotonicQueue<>();
18+
q.push(2);
19+
Assert.assertEquals("2", q.max().toString());
20+
q.push(7);
21+
Assert.assertEquals("7", q.max().toString());
22+
q.push(1);
23+
Assert.assertEquals("7", q.max().toString());
24+
q.push(7);
25+
Assert.assertEquals("7", q.max().toString());
26+
q.push(5);
27+
Assert.assertEquals("7", q.max().toString());
28+
q.push(4);
29+
Assert.assertEquals("7", q.max().toString());
30+
q.push(3);
31+
q.push(2);
32+
q.push(5);
33+
Assert.assertEquals("7", q.max().toString());
34+
}
35+
36+
@Test
37+
public void testPop() {
38+
MonotonicQueue<Integer> q = new MonotonicQueue<>();
39+
q.push(2);
40+
q.push(7);
41+
q.push(1);
42+
q.push(7);
43+
q.push(5);
44+
q.push(4);
45+
q.push(3);
46+
q.push(2);
47+
q.push(5);
48+
q.push(2);
49+
50+
Assert.assertEquals("7", q.pop().toString());
51+
Assert.assertEquals("7", q.pop().toString());
52+
Assert.assertEquals("5", q.pop().toString());
53+
q.pop();
54+
Assert.assertEquals("2", q.pop().toString());
55+
Assert.assertEquals(null, q.pop());
56+
}
57+
}

0 commit comments

Comments
 (0)