The worst time complexity for `find()`

or `union()`

is O(n) since it may need to run through the whole chain of parents. So in the worst case, m operations can take O(mn) time.

Modify `union()`

to make the worst-case time of Θ(log n).

`find()`

has an amortized time nearly Θ(1)

Worst-case time complexity is **Θ(m α(m, n))**. for m>n operations, where n is the number of elements in the Union-Find tree.

Now, **α(m, n)** is constant when amortized over a big number of operations. So this turns the time complexity of m operations is just **O(m)** so each union or find operation is just O(1) on average!

Kosaraju’s algorithm finds the Topological Sorting of the original directed graph. For this, it uses DFS. Next it reverses the graph and runs DFS on the topologically sorted vertices. So it takes two DFS though the time complexity is O(|V|+|E|).

Tarjan’s algorithm, on the other hand, only uses one DFS but uses some extra tracking variables to maintain a stack. This stack helps find loops which for SCC.

First, watch this video by William Fiset. Then check out Wikipedia pseudocode here.

The following code implements it in Java.

```
import java.util.*;
public class TarjanSCC {
List<Integer>[] g;
boolean[] visited;
int[] low;
int[] index;
Stack<Integer> stack;
boolean[] onStack;
private int count;
List<List<Integer>> allSCC;
private List<List<Integer>> SCC(List<Integer>[] graph){
this.g = graph;
allSCC = new ArrayList<>();
low = new int[graph.length];
index = new int[graph.length];
stack = new Stack<>();
onStack = new boolean[graph.length];
visited = new boolean[graph.length];
for (int i=0; i<graph.length; i++) {
if (!visited[i]) {
DFS(i);
}
}
return allSCC;
}
void DFS(int v) {
low[v] = index[v] = count++;
visited[v] = true;
onStack[v] = true;
stack.push(v);
for (Integer w: g[v]) {
if (!visited[w]) {
DFS(w);
low[v] = Math.min(low[v], low[w]);
} else if (onStack[w]) {
low[v] = Math.min(low[v], index[w]);
}
}
if (low[v] == index[v]) {
List<Integer> scc = new ArrayList<>();
int x;
do {
x = stack.pop();
onStack[x] = false;
scc.add(x);
} while (x != v);
System.out.println(scc);
this.allSCC.add(scc);
}
}
public static void main(String[] args) {
List<Integer>[] g = new List[8];
g[0] = Arrays.asList(new Integer[]{1});
g[1] = Arrays.asList(new Integer[]{2});
g[2] = Arrays.asList(new Integer[]{0});
g[3] = Arrays.asList(new Integer[]{4,7});
g[4] = Arrays.asList(new Integer[]{5});
g[5] = Arrays.asList(new Integer[]{0,6});
g[6] = Arrays.asList(new Integer[]{0,2,4});
g[7] = Arrays.asList(new Integer[]{3,5});
TarjanSCC tarjanSCC = new TarjanSCC();
System.out.println(tarjanSCC.SCC(g));
}
}
```

There are three SCC’s as below:

`[[2, 1, 0], [6, 5, 4], [7, 3]]`

]]>To solve this one, it can not theoretically be any better than O(n) time complexity. Here I convert the string to character array, then for each character and if this is a small ASCII character between a-z, then subtract the value of a, and add the offset values, take modulus of 26 and add back the value of 26. This primitive integer value has to be cast to char value before replacing the original character.

Similar logic applies for capital case characters, A-Z. At this point, it deviates from the HackerRank problem as I consider numbers as well for encryption, where the modulus of 10 is taken.

The solution below is pretty self-explanatory.

```
class Main {
// Add any helper functions you may need here
String rotationalCipher(String input, int rotationFactor) {
char[] chars = input.toCharArray();
for (int i=0; i<chars.length; i++) {
rotate(i, chars, rotationFactor);
}
return String.valueOf(chars);
}
void rotate(int i, char[] chars, int rf) {
char c = chars[i];
char newCh;
if (c >= 'a' && c <= 'z') {
newCh = (char)((c-'a' + rf) % 26 + 'a');
} else if (c >= 'A' && c <= 'Z') {
newCh = (char)((c-'A' + rf) % 26 + 'A');
} else if (c >= '0' && c <= '9') {
newCh = (char)((c-'0' + rf) % 10 + '0');
} else {
return;
}
chars[i] = newCh;
return;
}
```

]]>```
sudo apt update
sudo apt install snapd
sudo apt install -y default-jdk
sudo snap install node --classic
sudo npm install -g @angular/cli --unsafe-perm=true --allow-root
sudo snap install intellij-idea-ultimate --classic --edge
sudo snap install --classic code
sudo snap install postman
sudo snap install http
```

We are going to show how to install PostgreSQL database on a Debian Linux system.

$ sudo apt-get install postgresql

Check status

$ /etc/init.d/postgresql status

Add password for the postgress account

$ sudo -u postgres psql postgres psql (9.5.10) Type "help" for help. postgres=# \password postgres Enter new password: Enter it again:

Create a new user with a password

$ sudo -u postgres createuser --interactive --password usertest Shall the new role be a superuser? (y/n) n Shall the new role be allowed to create databases? (y/n) y Shall the new role be allowed to create more new roles? (y/n) n Password:

Create a new database test_db with the new role as the owner

$ sudo -u postgres createdb test_db -O usertest

Now edit the `pg_hba.conf`

file to enable connection

$ sudo vi /etc/postgresql/12/main/pg_hba.conf

By changing the lines below with **trust**

# "local" is for Unix domain socket connections only local all all trust # IPv4 local connections: host all all 127.0.0.1/32 trust

Restart the server

$ sudo service postgresql restart

Check if the new role can access the new database

$ psql -U user_test -d test_db -W]]>

It can be solved in a naive manner to search for the start and end in a linear runtime O(n). But a better solution is to use Binary Search which runs in O(logn) time.

A typical binary search method looks like this if the array has unique and sorted numbers.

```
private int binarySearch(int[] nums, int target, int l, int r) {
int result = -1;
while (l<=r){
int mid = (l+r)/2;
if(nums[mid]==target){
return mid;
} else if (nums[mid] < target) {
l = mid + 1;
} else {
r = mid - 1;
}
}
return result;
}
```

But for this problem, the Binary Search requires a little modification because of the duplicates and also that we can design it in a way to look for not only the target value but also specifically search for the starting and ending occurrence. So check out the solution below.

```
public class SearchForARange {
public int[] searchRange(int[] nums, int target) {
int[] res = new int[]{-1,-1};
if (nums.length==0) return res;
res[0] = binarySearchLeft(nums, target, 0, nums.length-1);
if (res[0]>=0) {
res[1] = binarySearchRight(nums, target, res[0], nums.length-1);
}
return res;
}
private int binarySearchLeft(int[] nums, int target, int l, int r) {
int result = -1;
while(l<=r){
int mid = (l+r)/2;
if (nums[mid] == target){
result = mid;
r = mid-1;
} else if (nums[mid] > target){
r = mid - 1;
} else {
l = mid + 1;
}
}
return result;
}
private int binarySearchRight(int[] nums, int target, int l, int r) {
int result = -1;
while (l<=r){
int mid = (l+r)/2;
if(nums[mid]==target){
result = mid;
l = mid + 1;
} else if (nums[mid] > target) {
r = mid - 1;
} else {
l = mid + 1;
}
}
return result;
}
}
```

For understanding the logic, check out this post.

]]>A better approach is to use three-way partitioning of the array.

Below the threeWayPartitionSort() method splits the given an array, `[3,2,0,2,1,1,0,-1]`

, into three parts, where values equal to or 0 come first, in the last part, values equal to or greater than 2 show up. Anything in between stays in between. So the final result is `[-1,0,0, 1,1, 2,2,3]`

```
public class threeWayPartitionSort{
public void threeWayPartitionSort(int[] nums, int a, int b) {
int l = 0;
int r = nums.length - 1;
int i = 0;
while(i<=r){
if (nums[i]<=a) {
swap(nums, i++, l++);
} else if (nums[i]>=b){
swap(nums, i, r--);
} else {
i++;
}
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public static void main(String[] args) {
nums = new int[]{3,2,0,2,1,1,0,-1};
sortColors.sortColors(nums, 0, 2);
System.out.println(Arrays.toString(nums));
}
}
```

`Output: [-1, 0, 0, 1, 1, 2, 2, 3]`

Notice, that there are three pointers, `i`

for looping through the the array until it hits the right side marker `r`

, and the left side marker `l`

. Until `i`

hits `r`

, we keep looping, and each time a value below a is met it is swapped with left marker and both `l`

and `i`

are incremented. If a value greater than or equal to b is found, value at`r`

and `i`

are swapped, but only `r`

is decremented, showing that the ride side is already partitioned. For value in between, just increment `i`

. This expects, that if we move the larger values to the right region and smaller values in the left region, then every value in between should fall in the right middle region.

Using the above approach the solution for the Sort Color problem is below. This approach takes O(n) times.

```
class Solution {
public void sortColors(int[] nums) {
int l = 0;
int r = nums.length - 1;
int i = 0;
while(i<=r){
if (nums[i]==0) {
swap(nums, i++, l++);
} else if (nums[i]==2){
swap(nums, i, r--);
} else {
i++;
}
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
```

]]>Traditional stock prediction can be seen as a time series regression problem where many many algorithms already exist. A naive approach could be classification/regression but time series is more robust approach.

However, for a regression stock prediction model, one needs to map the predicted stock price to BUY / SELL / HOLD action space. So classification probably makes more sense. But Reinforcement Learning really helps a lot because it can optimize the total gains.

**Generic RNN, LSTM:**many resources available online**Transformer+Attention:**This Medium article and its corresponding GitHub repo applies Transformer and time embeddings which seems quite interesting**Dual-stage Attention -RNN (DA-RNN):**The paper is here https://arxiv.org/pdf/1704.02971.pdf and the implemented model is available here in this GitHub. A similar implementation in PyTorch is available here by KurochkinAlexey**Deep Reinforcement Learning:**Finally, this FinRL is an excellent library for applying Deep RL on stock prediction with demo and code examples to help you get started.

This is a work-in-progress note. So will update this as needed.

]]>```
public class FindPeakElement {
int[] nums;
public int findPeakElement(int[] nums){
this.nums = nums;
return search(0, this.nums.length-1);
}
private int search(int l, int r) {
if(l==r) return l;
int mid = (l+r)/2;
if (nums[mid]>nums[mid+1]){
return search(l, mid);
} else return search(mid+1, r);
}
}
```

```
public class FindPeakElement {
int[] nums;
public int findPeakElement(int[] nums){
this.nums = nums;
return searchIterative(0, this.nums.length-1);
}
private int searchIterative(int l, int r){
while(l<r){
int mid = (l+r)/2;
if (nums[mid]>nums[mid+1]){
r = mid;
} else {
l = mid+1;
}
}
return l;
}
```

]]>QuickSelect is a sorting algorithm that uses partitioning scheme like Hoare’s or Lomuto’s. It finds the k-th smallest value in O(n) time. It uses divide and conquer technique. It divides the space using partition function and then recursively sorts the left or right part until it finds the partition.

```
private void quickSelect(int left, int right){
if (left < right) {
int p = partition(left, right);
if (kSmallest <= p) quickSelect(left, p);
else {
quickSelect(p+1, right);
}
}
}
```

Notice if (kSmallest <= p), then we know the `nums`

array is partitioned from `left to p`

which has values smaller than the values on the right portion from indices `p+1 to right`

. So we only recursively sort the left.

If that is not the case, then we can sort on the right. But we cannot stop if p==kSmallest like in Lomuto’s partition because Hoare’s does not ensure that the value at the partition is the final position of the number.

Hoare’s partitioning is shown below. This partitioning scheme is much faster than Lomuto’s. There are plenty of online resources on this most of them are confusing in the one on Wikipedia. I wrote piece here on QuickSort that could help.

```
private int partition(int left, int right){
int p = (left+right)/2;
int pVal = nums[p];
int i = left - 1;
int j = right + 1;
while(true){
do {
i++;
} while( nums[i] < pVal);
do {
j--;
} while (nums[j] > pVal);
if(i<j){
swap(i,j);
} else{
return j;
}
}
}
```

The solution below beats 100% Java submissions on LeetCode for runtime.

```
public class KthLargestElement {
int kSmallest;
int[] nums;
public int findKthLargest(int[] nums, int k) {
this.nums = nums;
this.kSmallest = nums.length-k;
quickSelect(0, nums.length-1);
return nums[kSmallest];
}
private void quickSelect(int left, int right){
if (left < right) {
int p = partition(left, right);
if (kSmallest <= p) quickSelect(left, p);
else {
quickSelect(p+1, right);
}
}
}
private int partition(int left, int right){
int p = (left+right)/2;
int pVal = nums[p];
int i = left - 1;
int j = right + 1;
while(true){
do {
i++;
} while( nums[i] < pVal);
do {
j--;
} while (nums[j] > pVal);
if(i<j){
swap(i,j);
} else{
return j;
}
}
}
private void swap(int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
```

]]>