Algorithms Toolbox

Trees

  • Tree cannot contain cycles
  • Leaf: node without children

Binary Tree

  • Each node up to 2 children
  • Complete Binary Tree: every level if fully filled, except for perhaps the lst level. Last level must be filled left to right.
  • Full Binary Tree: Every node has either zero or 2 children. No nodes have only one child.

Perfect Binary Tree

  • All interior nodes have 2 children and all leaf nodes are at the same level.
  • Very rare in interviews and in real life

Balanced tree

  • Not terribly imbalanced
  • Ensures O(log n) times for INSERT and FIND

Red-Black Tree

  • Self-balancing BST - O(log N) insertions, deletions and retrievals
  • Require a bit less memory
  • Can rebalance faster: Used in situations where the tree will be modified frequently
  • Every node is either red or black
  • The root is black
  • The leaves, which are NULL nodes, are considered black
  • Every red node must have 2 black children. That is, a red node cannot have red children (although a black node can have black children)
  • Every path from a node to its leaves must have the same number of black children

AVL Tree

  • One way to implement tree balancing
  • Stores in each node the height of the subtrees rooted at this node
  • For any node, we can check if it is height balanced: heights of left subtree and right subtree differ by no more than 1
  • We can check and fix the balance at each node though a series of rotations (left or right)

BST - Binary Search Tree

  • Binary tree in which every node: left descendents <= parent < right descendents

Traversal (Binary Trees)

  • In-order: Ascending order - left branch, current node, right branch.
  • Pre-order: Root first, left branch then right branch.
  • Post-order: Root last. Left branch first, right branch and then current node.

Bloom Filter

  • Like hashmap
  • More space efficient
  • Cannot delete
  • Cannot store pointers to objects
  • 0.1 to 1% false positive probability

String

Rabin-Karp Substring Search

Graph

  • Tree is a type of graph (connected without cycles)
  • Directed: "one way street"
  • Undirected: "two way street"
  • Connected graph: there is a path between evey pair of vertices
  • 2 ways of implementing: adjacency list and adjacency matrices

Graph Search

  • DFS - Depth-first search (visit all nodes starting from root)
  • BFS - Breadth-first search (used for shortest path between 2 nodes)

Topological sort

  • Only for directed and acyclic (DAGs)
  • Way of ordering the list of nodes such that if (a,b) is an edge then a will appear before b in the list
  • Implementation: create 2 queues: order and processNext

Dijkstra Shortest Path

  • Weighted direct graph
  • Can have cycles
  • Edges with positive values only
  • n vertices
  • m edges
  • Uses priority queue
  • Priority queues are implemented by array O(n2) or min heap O((m+n)log n)
  • Use array if dense graph because O(n2) better than O((n+n2)log n)
  • Use min heap if sparse graph

Useful math

  • Sum of integers (1 through N): (n*(n+1))/2
  • Sum of powers of 2: 2^0 + 2^1 + 2^2 + ... + 2^n = 2^(n+1) - 1
  • Log base convertion: 2 to 10: log10 p = log2 p / log2 10
  • Permutations: k length string with n unique characters (no repetition): n!/(n-k)!
  • Combinations: n choose k = n!/(k!*(n-k)!)

Big O

Estrutura Running Time Running Time
Sorted Array SEARCH log n
MIN 1
MAX 1
PREDECESSOR log n
SUCCESSOR log n
OUTPUT SORTED n
SELECT 1
RANK log n
INSERT n (LENTO !)
DELETE n (LENTO !)
B S Tree SEARCH log n
MIN log n
MAX log n
PREDECESSOR log n
SUCCESSOR log n
OUTPUT SORTED n
SELECT log n
RANK log n
INSERT log n
DELETE log n
Hash table LOOKUP 1
INSERT 1
DELETE 1
Heap INSERT log n
EXTRACT MIN log n
FIND MIN 1
HEAPIFY n
DELETE log n
ArrayList GET 1
ADD 1
REMOVE n
LinkedList GET n
ADD 1 (amortized)
REMOVE n

Recursão

Todo algoritmo de recursão ocupa O(n) de espaço

SOLID

  • Single responsability - Não pode haver mais de uma razão para uma classe mudar. Exemplos de razões de mudanças: formato da mensagem (Json/XML), protocolo (Html), segurança na comunicação (autenticação). Se dentro do controller temos a lógica de validação de usuário, precisamos criar uma nova classe UserValidator.
  • Open Closed - Entidades (classes, módulos, métodos) devem estar abertas para extensão, mas fechadas para modificações. Exemplo: ter uma classe abstrata mãe para extensão.
  • Liskov Substitution - Deve ser possível substituir as classes base pelas classes filhas sem alteração de comportamento / características do software. Exemplo: Se estendemos retangulo para criar a classe quadrado, e a classe retangulo já tem um teste feito para que a altura tenha 20 e a largura tenha 30. Vai falhar para quadrado. Solução: Quadrado não deve mais estender de retangulo, pois o comportamento de um retangulo é distinto de um quadrado. Devemos criar uma interface Shape com o metodo comum: computeArea()
  • Interface Segregation - Clientes nao devem ser forçados a depender de interfaces que eles não utilizam. Interface pollution. Sinais de violação: métodos com implementação vazia ou retornando null / default / valor dummy ou estourando UnsupportedOperationException (ou similar). Exemplo: ter na interface um metodo findByName e fazer uma classe implementar isto sem precisar.
  • Dependency Inversion - Trata de acoplamento entre classes. Módulos de alto nível (Regra de negócios) nao devem depender de módulos de baixo nível (SDKs, métodos de linguaguem). Modulos de alto e baixo niveis devem depender de abstrações. As abstrações, por sua vez, não devem depender de detalhes, mas de abstrações. Ex: tenho um método que pega um json e grava no disco. Se eu utilizo funcoes acopladas ao metodo Json e ao disco, eu fico refem destas classes. Solução: enviar a interface como parametro: public void writeReport(Formatter formatter, Writer writer) { Report report = new Report; String report = formatter.format(report); writer.write("My Report");