Friday, 18 March 2016

Undirected Weighted Graph

package exercises;

import java.util.*;

/**
 * Undirected Weighted Graph
 */
public class UWGraph {
private final String NA = "NA";
private final String NEIGHBOUR = "NEIGHBOUR";
private HashMap vertexMap = new HashMap<>();
private List vertices = new ArrayList<>();
public Vertex addVertex(String key) {
return this.addVertex(key, null);
}
public synchronized Vertex addVertex(String key, HashMap payload) {
if(vertexMap.containsKey(key)) return this.getVertex(key);
Vertex vertex = new Vertex(this.vertices.size() + 1, key, payload);
this.vertices.add(vertex);
this.vertexMap.put(key, vertex.getId());
return vertex;
}

public void addEdge(Edge e, Vertex start, Vertex end) {
if(this.vertexMap.containsKey(start.getKey()) && this.vertexMap.containsKey(end.getKey())) {
this.getVertex(start.getKey()).addAdjacent(end.getId(), e.getWeight());
this.getVertex(end.getKey()).addAdjacent(start.getId(), e.getWeight());
}
}
public int totalVertices() {
return this.vertices.size();
}
public int degree(String vertex) {
if(!this.hasVertex(vertex)) return 0;
return this.getVertex(vertex).degree();
}
public boolean hasVertex(String key) {
return this.vertexMap.containsKey(key);
}
public boolean hasEdge(String start, String end) {
return this.hasVertex(start) && this.hasVertex(end) && 
this.getVertex(start).hasEdgeTo(this.getVertexId(end));
}
public String getEdges(String vertex) {
return this.getVertex(vertex).toString();
}
public void dfs(String key) {
Vertex v = this.getVertex(key);
Stack<int[]> children = new Stack<>();
List visited = new ArrayList<>();
if(v == null) return;
List<int[]> adjacents = v.getAdjacents();
if(adjacents == null || adjacents.size() <= 0) return;
children.addAll(adjacents);
while(!children.isEmpty()) {
int vertex = children.pop()[0] - 1;
if(visited.contains(vertex)) continue;
visited.add(vertex); System.out.println("Visited : " + vertex);
List<int[]> childs = this.vertices.get(vertex).getAdjacents();
if(childs != null && childs.size() > 0) children.addAll(childs);
}
}
public void bfs(String key) {
Vertex v = this.getVertex(key);
Queue<int[]> children = new LinkedList<>();
List visited = new ArrayList<>();
if(v == null) return;
List<int[]> adjacents = v.getAdjacents();
if(adjacents == null || adjacents.size() <= 0) return;
children.addAll(adjacents);
while(!children.isEmpty()) {
int vertex = children.poll()[0] - 1;
if(visited.contains(vertex)) continue;
visited.add(vertex); System.out.println("Visited : " + vertex);
List<int[]> childs = this.vertices.get(vertex).getAdjacents();
if(childs != null && childs.size() > 0) children.addAll(childs);
}
}
private Vertex getVertex(String key) {
return this.vertices.get(this.vertexMap.get(key) - 1);
}
private int getVertexId(String key) {
return this.getVertex(key).getId();
}
}

class Vertex {
private int id;
private String key;
private HashMap payload;
private List<int[]> adjacents;
Vertex(int id, String key, HashMap payload) {
this.id = id;
this.key = key;
this.payload = payload;
this.adjacents = new ArrayList<int[]>();
}
List<int[]> getAdjacents() {
return this.adjacents;
}
String getKey() {
return key;
}
void setKey(String key) {
this.key = key;
}
int getId() {
return id;
}
void setId(int id) {
this.id = id;
}
HashMap getPayload() {
return payload;
}
void setPayload(HashMap payload) {
this.payload = payload;
}
void addAdjacent(int vertex, int weight) {
if(!this.hasEdgeTo(vertex)) this.adjacents.add(new int[] { vertex, weight });
}
int degree() {
if(this.adjacents == null || this.adjacents.size() <= 0) return 0;
return this.adjacents.size();
}
boolean hasEdgeTo(int vertex) {
/**
* Use Bloomfilter to check for FALSE_POSITIVE and proceed to avoid linear search
*/
if(this.adjacents == null || this.adjacents.size() <= 0) return false;
for(int[] adjacent : this.adjacents) {
if(adjacent[0] == vertex) return true;
}
return false;
}
@Override
public String toString() {
if(this.adjacents == null || this.adjacents.size() <= 0) return super.toString();
StringBuilder output = new StringBuilder();
output.append(this.getKey() + ":" + "{");
for(int[] adjacent : this.adjacents) {
output.append(adjacent[0] - 1 + " ");
}
output.append("}");
return output.toString();
}
}

class Edge {
private String key;
private int weight;
Edge(String key, int weight) {
this.key = key;
this.weight = weight;
}
int getWeight() {
return weight;
}
void setWeight(int weight) {
this.weight = weight;
}
String getKey() {
return key;
}
void setKey(String key) {
this.key = key;
}

}


/**
* [ [1, 6, 8],
[0, 4, 6, 9],
  [4, 6],
  [4, 5, 8],
  [1, 2, 3, 5, 9],
  [3, 4],
  [0, 1, 2],
  [8, 9],
  [0, 3, 7],
  [1, 4, 7] 
]
*/
public static void demoGraph() {
UWGraph graph = new UWGraph();
Vertex v0 = graph.addVertex("0"); Vertex v1 = graph.addVertex("1"); Vertex v2 = graph.addVertex("2");
Vertex v3 = graph.addVertex("3"); Vertex v4 = graph.addVertex("4"); Vertex v5 = graph.addVertex("5");
Vertex v6 = graph.addVertex("6"); Vertex v7 = graph.addVertex("7"); Vertex v8 = graph.addVertex("8");
Vertex v9 = graph.addVertex("9");
graph.addEdge(new Edge("01", 1), v0, v1); graph.addEdge(new Edge("06", 6), v0, v6); graph.addEdge(new Edge("08", 8), v0, v8);
graph.addEdge(new Edge("10", 10), v1, v0); graph.addEdge(new Edge("14", 14), v1, v4); graph.addEdge(new Edge("16", 16), v1, v6);
graph.addEdge(new Edge("19", 19), v1, v9);
graph.addEdge(new Edge("24", 24), v2, v4); graph.addEdge(new Edge("26", 26), v2, v6);
graph.addEdge(new Edge("34", 34), v3, v4); graph.addEdge(new Edge("35", 35), v3, v5); graph.addEdge(new Edge("38", 38), v3, v8);
graph.addEdge(new Edge("41", 41), v4, v1); graph.addEdge(new Edge("42", 42), v4, v2); graph.addEdge(new Edge("43", 43), v4, v3);
graph.addEdge(new Edge("45", 45), v4, v5); graph.addEdge(new Edge("49", 49), v4, v9);
graph.addEdge(new Edge("53", 53), v5, v3); graph.addEdge(new Edge("54", 54), v5, v4);
graph.addEdge(new Edge("60", 60), v6, v0); graph.addEdge(new Edge("61", 61), v6, v1); graph.addEdge(new Edge("62", 62), v6, v2);
graph.addEdge(new Edge("78", 78), v7, v8); graph.addEdge(new Edge("79", 79), v7, v9); 
graph.addEdge(new Edge("80", 80), v8, v0); graph.addEdge(new Edge("83", 83), v8, v3); graph.addEdge(new Edge("87", 87), v8, v7);
graph.addEdge(new Edge("91", 91), v9, v1); graph.addEdge(new Edge("94", 94), v9, v4); graph.addEdge(new Edge("97", 97), v9, v7);
System.out.println("Vertex 0,  Degree :" + graph.degree(v0.getKey()) + ", Edges : " + graph.getEdges(v0.getKey()));
System.out.println("Vertex 1,  Degree :" + graph.degree(v1.getKey()) + ", Edges : " + graph.getEdges(v1.getKey()));
System.out.println("Vertex 2,  Degree :" + graph.degree(v2.getKey()) + ", Edges : " + graph.getEdges(v2.getKey()));
System.out.println("Vertex 3,  Degree :" + graph.degree(v3.getKey()) + ", Edges : " + graph.getEdges(v3.getKey()));
System.out.println("Vertex 4,  Degree :" + graph.degree(v4.getKey()) + ", Edges : " + graph.getEdges(v4.getKey()));
System.out.println("Vertex 5,  Degree :" + graph.degree(v5.getKey()) + ", Edges : " + graph.getEdges(v5.getKey()));
System.out.println("Vertex 6,  Degree :" + graph.degree(v6.getKey()) + ", Edges : " + graph.getEdges(v6.getKey()));
System.out.println("Vertex 7,  Degree :" + graph.degree(v7.getKey()) + ", Edges : " + graph.getEdges(v7.getKey()));
System.out.println("Vertex 8,  Degree :" + graph.degree(v8.getKey()) + ", Edges : " + graph.getEdges(v8.getKey()));
System.out.println("Vertex 9,  Degree :" + graph.degree(v9.getKey()) + ", Edges : " + graph.getEdges(v9.getKey()));
//graph.dfs("0");
graph.bfs("0");
}

Thursday, 17 March 2016

Flood-fill Algorithm using Recursion

package exercises;

public class Floodfill {
private int[][] matrix;
private int size;
private int row;
private int column;
public Floodfill(int size) {
this.size = size;
this.matrix = new int[size][size];
}
public Floodfill row(int row) {
this.row = row;
return this;
}
public Floodfill column(int column) {
this.column = column;
return this;
}
public void add(int item) {
this.matrix[this.row - 1][this.column - 1] = item;
public void fill(int row, int column, int current, int _new) {
if(row > size || column > size || row < 0 || column < 0) return;
System.out.println("Row:" + row + ", Column:" + column);
if(matrix[row - 1][column - 1] != current) return;
//System.out.println("Row : " + row + ", Column : " + column);
matrix[row - 1][column - 1] = _new;
fill(row + 1, column, current, _new);
fill(row - 1, column, current, _new);
fill(row, column + 1, current, _new);
fill(row, column - 1, current, _new);
}
public void printAll() {
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
System.out.print(String.format("%d ", matrix[i][j])); 
}
System.out.print("\n");
}
System.out.println("***************");
}

}


/**
* screen[M][N] = {{1, 1, 1, 1, 1, 1, 1, 1},
                      {1, 1, 1, 1, 1, 1, 0, 0},
                      {1, 0, 0, 1, 1, 0, 1, 1},
                      {1, 3, 3, 3, 3, 0, 1, 0},
                      {1, 1, 1, 3, 3, 0, 1, 0},
                      {1, 1, 1, 3, 3, 3, 3, 0},
                      {1, 1, 1, 1, 1, 3, 1, 1},
                      {1, 1, 1, 1, 1, 3, 3, 1},
                      };
*/
public static void demoFloodfill() {
Floodfill matrix = new Floodfill(8);
matrix.row(1).column(1).add(1); matrix.column(2).add(1); matrix.column(3).add(1); matrix.column(4).add(1);
matrix.column(5).add(1); matrix.column(6).add(1); matrix.column(7).add(1); matrix.column(8).add(1);
matrix.row(2).column(1).add(1);matrix.column(2).add(1); matrix.column(3).add(1); matrix.column(4).add(1);
matrix.column(5).add(1); matrix.column(6).add(1); matrix.column(7).add(0); matrix.column(8).add(0);
matrix.row(3).column(1).add(1); matrix.column(2).add(0); matrix.column(3).add(0); matrix.column(4).add(1);
matrix.column(5).add(1); matrix.column(6).add(0); matrix.column(7).add(1); matrix.column(8).add(1);
matrix.row(4).column(1).add(1); matrix.column(2).add(3); matrix.column(3).add(3); matrix.column(4).add(3);
matrix.column(5).add(3); matrix.column(6).add(0); matrix.column(7).add(1); matrix.column(8).add(0);
matrix.row(5).column(1).add(1);matrix.column(2).add(1); matrix.column(3).add(1); matrix.column(4).add(3);
matrix.column(5).add(3); matrix.column(6).add(0); matrix.column(7).add(1); matrix.column(8).add(0);
matrix.row(6).column(1).add(1);matrix.column(2).add(1); matrix.column(3).add(1); matrix.column(4).add(3);
matrix.column(5).add(3); matrix.column(6).add(3); matrix.column(7).add(3); matrix.column(8).add(0);
matrix.row(7).column(1).add(1);matrix.column(2).add(1); matrix.column(3).add(1); matrix.column(4).add(1);
matrix.column(5).add(1); matrix.column(6).add(3); matrix.column(7).add(1); matrix.column(8).add(1);
matrix.row(8).column(1).add(1);matrix.column(2).add(1); matrix.column(3).add(1); matrix.column(4).add(1);
matrix.column(5).add(1); matrix.column(6).add(3); matrix.column(7).add(3); matrix.column(8).add(1);
matrix.printAll();
matrix.fill(4, 2, 3, 2);
matrix.printAll();
}

Friday, 12 February 2016

Rotate matrix +/- 90 with and without extra space

package exercises;

public class SquareMatrix {
private int[][] matrix;
private int size;
private int row;
private int column;
public SquareMatrix(int size) {
this.size = size;
this.matrix = new int[size][size];
}
public SquareMatrix row(int row) {
this.row = row;
return this;
}
public SquareMatrix column(int column) {
this.column = column;
return this;
}
public void add(int item) {
this.matrix[this.row - 1][this.column - 1] = item;
}
public void rotatePlus90_easy() {
int[][] rotated = new int[size][size];
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
rotated[i][j] = matrix[size - j - 1][i];
}
}
this.matrix = rotated;
}
public void rotateMinus90_easy() {
int[][] rotated = new int[size][size];
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
rotated[i][j] = matrix[j][size - i - 1];
}
}
this.matrix = rotated;
}
/**
* Imagine matrix as nested squares. Outer square contains a inner, which in turn contains another and so on. 
* Do below three steps for each square, start from Outer
* first rotate corners(clockwise)
* then rotate 2nd element in the square
* then rotate 3rd element and goes on.
* i = number of squares(3*3 is 1, 4*4 is 2, 5*5 is 2, 6*6 is 3). For odd size, inner most square is only one element. so it never moves
* j = for a square, move all elements. so it number of elements to be moved on a side
* First index should deal with 'j', if moving rows, else 'i' if moving columns.
* for ex(run and see 5*5 matrix), Top Right Corner 05 to 25 is rows, so use j. But 25 to 21 about columns, so use i.
*/
public void rotate90() {
for(int i = 0; i < size / 2; i++) {
for(int j = i; j < size - i - 1; j++) {
int temp = this.matrix[i][j];
this.matrix[i][j] = this.matrix[size - j - 1][i];
this.matrix[size - j - 1][i] = this.matrix[size - i - 1][size - j - 1];
this.matrix[size - i - 1][size - j - 1] = this.matrix[j][size - i - 1];
this.matrix[j][size - i - 1] = temp;
}
}
}

/**
* Trick is after initializing temp,
* Interchange first statement assignee with last's assigned
* Modify second and third assignment alone accordingly
*/
public void rotateminus90() {
for(int i = 0; i < size / 2; i++) {
for(int j = i; j < size - i - 1; j++) {
int temp = this.matrix[i][j];
this.matrix[i][j] = this.matrix[j][size - i - 1];
this.matrix[j][size - i - 1] = this.matrix[size - i - 1][size - j - 1];
this.matrix[size - i - 1][size - j - 1] = this.matrix[size - j - 1][i];
this.matrix[size - j - 1][i] = temp;
}
}
}
public void printAll() {
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
System.out.print(String.format("%02d ", matrix[i][j])); 
}
System.out.print("\n");
}
System.out.println("***************");
}

}

public static void demoMatrix() {
SquareMatrix matrix = new SquareMatrix(5);
matrix.row(1).column(1).add(1);
matrix.column(2).add(2);
matrix.column(3).add(3);
matrix.column(4).add(4);
matrix.column(5).add(5);
matrix.row(2).column(1).add(6);
matrix.column(2).add(7);
matrix.column(3).add(8);
matrix.column(4).add(9);
matrix.column(5).add(10);
matrix.row(3).column(1).add(11);
matrix.column(2).add(12);
matrix.column(3).add(13);
matrix.column(4).add(14);
matrix.column(5).add(15);
matrix.row(4).column(1).add(16);
matrix.column(2).add(17);
matrix.column(3).add(18);
matrix.column(4).add(19);
matrix.column(5).add(20);
matrix.row(5).column(1).add(21);
matrix.column(2).add(22);
matrix.column(3).add(23);
matrix.column(4).add(24);
matrix.column(5).add(25);
matrix.printAll();
matrix.rotatePlus90_easy();
matrix.printAll();
matrix.rotateMinus90_easy();
matrix.printAll();
matrix.rotate90();
matrix.printAll();
matrix.rotateminus90();
matrix.printAll();
}

Reverse stack using pop/push

package exercises;

import java.util.ArrayList;
import java.util.Stack;
import java.util.function.Consumer;

public class MyStack {
private Stack ints = new Stack<>();
public void add(int item) {
ints.push(item);
}
public void printall() {
ArrayList array = new ArrayList<>(ints);
array.forEach(new Consumer() {
@Override
public void accept(Integer t) {
System.out.print(t + "-->");
}
});
System.out.print("\n");
}
public void reverse_easy() {
Stack other = new Stack<>();
while(!ints.isEmpty()) {
other.push(ints.pop());
}
ints = other;
}
/**
* reverse relies on double recursion
* Outer Recursion : Pop all items
* Inner Recursion : Adds item at the bottom.
*/
public void reverse() {
this.reverse(this.ints);
}
private void reverse(Stack stack) {
Integer item = stack.pop();
if(!stack.isEmpty()) reverse(stack);
this.insertAtBottom(stack, item);
}
private void insertAtBottom(Stack stack, Integer item) {
if(stack.isEmpty()) {
stack.push(item);
} else {
Integer top = stack.pop();
insertAtBottom(stack, item);
stack.push(top);
}
}

}

Thursday, 11 February 2016

Reverse Double Linked List, Promote Node based on add/get(similar to LinkedHashMap)



public static void demoMyLinkedHashMap() {
SimpleLinkedList map = new SimpleLinkedList<>();
map.add(1);
map.add(2);
map.add(3);
map.add(4);
map.printAll();
map.print(1);
map.print(4);
map.print(9);
map.add(5);
map.printAll();
map.print(5);
map.insert(0, 1);
map.printAll();
map.print(5);
map.insert(0, 1);
map.insert(6, 6);
map.printAll();
map.print_last();
map.reverse();
map.printAll();
map.print_last();
map.reverse();
map.printAll();
map.print_last();
map.add(7);
map.printAll();
map.print_last();
}

package exercises;

public class SimpleLinkedList {
private class Node {
private T data = null;
private Node prev = null;
private Node next = null;

public Node(T data) {
this.setData(data);
this.setPrev(null);
this.setNext(null);
}

public T getData() {
return data;
}

public void setData(T data) {
this.data = data;
}

public Node getPrev() {
return prev;
}

public void setPrev(Node prev) {
this.prev = prev;
}

public Node getNext() {
return next;
}

public void setNext(Node next) {
this.next = next;
}
}

private Node root;
private Node current;

public void add(T data) {
if(this.root == null) {
this.root = new Node(data);
this.current = this.root;

return;
} else {
Node node = new Node(data);

node.setPrev(current);
current.setNext(node);
current = node;
}
}

/**
* ignore, will not promote node
* @param data
* @param position
*/
public void insert(T data, int position) {
Node pointer = this.getNode(position, false);

if(pointer == null || pointer.getData().equals(data)) {
System.out.println("Same data, Ignore");
return;
}

Node newNode = new Node(data);
newNode.setNext(pointer);
newNode.setPrev(pointer.getPrev());
pointer.setPrev(newNode);

if(newNode.getPrev() != null) {
newNode.getPrev().setNext(newNode);
} else {
root = newNode;
}
}

public T get(int position) {
Node pointer = this.getNode(position, true);

return (pointer == null) ? null : pointer.getData();
}

public void printAll() {
if(this.root == null) return;

for(Node pointer = root; pointer != null; pointer = pointer.getNext()) {
System.out.print(pointer.getData().toString());

if(pointer.getNext() != null) System.out.print("->");
else System.out.print("\n");
}
}

public void print(int position) {
if(this.root == null) return;

T pointer = this.get(position);
if(pointer == null) return;

System.out.println("Item at position : " + position + " is " + pointer.toString());
}

public void print_last() {
System.out.println("Last item is : " + current.getData().toString());
}

/**
* reverse relies on single recursion. method returns processed node
* Recursively traverse to end to make it 'root'. return r'oot'
* current next is its prev. its prev is returned processed node. return current
*/
public void reverse() {
if(this.root == this.current) return;

current = this.reverse(root);
}

private Node reverse(Node current) {
if(current.getNext() == null) {
root = current;
root.setNext(root.getPrev()); //Root next, should be its previous.
root.setPrev(null); //Root node previous should be null

return current;
}

Node prev = reverse(current.getNext()); //prev, last visited node

current.setNext(current.getPrev()); //curent.next should be its prev node
current.setPrev(prev); //current.prev should be last visited node

return current;
}

private void promote(Node accessed) {
if(accessed == null || accessed == current) return;

if(accessed.getPrev() != null) {
accessed.getPrev().setNext(accessed.getNext()); //previous node should point accessed's next
accessed.getNext().setPrev(accessed.getPrev());
} else {
root = accessed.getNext(); // accessed.prev is null only if its root node, so new root is accessed's next
root.setPrev(null); //root prev is always null;
}

current.setNext(accessed);
accessed.setPrev(current);
accessed.setNext(null);
current = accessed;
}

/**
* 1. Return NULL, If the root is null or position is invalid
* 2. While index < position && pointer != null
* move to pointer.next
* increment index
* @param position
* @param promote - to promote the node to front
* @return
*/
private Node getNode(int position, boolean promote) {
if(position <= 0) return null;

int index = 1;
Node pointer = root;

while(index < position && pointer != null) {
pointer = pointer.getNext();
index++;
}

if(promote && pointer != null) promote(pointer);

return pointer;
}
}