1. Bit operations

  • The left < <
  • Right >> : YesUsed in the dichotomy algorithm to pick the median, such as13 > > 1

2. Operate by bit

  • Bitwise and&: If each digit is 1, the result is 1
  • Bitwise or|: one of the digits is 1, and the result is 1
  • The bitwise exclusive or^: Each digit is different, so the result is 1

3. The stack

  • Features: Last in, First out (LIFO)
  • Algorithm basic idea: because can only push data from the top of the stack can only pop data from the top of the stack, so you can use a single linked list. Because you only operate on top of the stack, borrowing the head of a single linked list allows all operations to be done in O(1) time
  • Scenario: When solving a problem, only the last operation is concerned. After the last operation is processed, the previous operation can be found in O(1) time. For example, leecode20 (valid parentheses), 739 (daily temperature)
  • Use stacks to solve mazes
Let maze = [,1,1,1,1,1,1,1,1,1 [1], [1,0,0,1,0,0,0,1,0,1],,0,0,1,0,0,0,1,0,1 [1], [1,0,0,0,0,1,1,0,0,1]. ,0,0,0,1,0,0,0,0,1,0,1,1,1,0,0,0,0,1 [1], [1], [1,0,1,0,0,0,1,0,0,1],,0,1,1,1,0,1,1,0,1 [1], [1,1,0,0,0,0,0,0,0,1], [1,1,1,1,1,1,1,1,1,1,1]] function maza_path(){let stack=[],nextNode stack.append((x1,y1))) while(stack.length>0){let If (curNode[0]==x2&&curNode[1]==y2){for(P in stack){console.log(P)} return true} for(P in stack){console.log(P)} return true} //x -1,y; x+1,y; x,y-1; X,y+1 for(dir in dirs){nextNode=dir(curNode[0],curNode[1]) if(maze[nextNode[0][nextNode[1]] =0){ Stack. Append (nextNode) maze[nextNode[0]][nextNode[1]]==2 //2 ==2 Stack.pop ()}else{console.log(' no way ') return false}}Copy the code

4. The queue

  • Features: First-in, first-out (FIFO), view and add data at the end of the queue, view and delete data at the head of the queue
  • Implementation: Using double linked lists
  • Scenario: When the data is processed in a certain order and the data is constantly changing, such as breadth-first search.

The idea behind breadth-first search is :(1) start at one node and look for all the points you can continue to move on until you find the exit. (2) use a queue to store the nodes currently under consideration

(1)Queue implementation - ring queue

Ring queue: when front==Maxsize+1 at the end of the queue, it automatically reaches 0 after one more position

  • Advance the first pointer 1:front=(front+1)% Maxsize
  • Trailing pointer forward 1:rear=(rear+1)% Maxsize
  • Team air conditions:rear==front
  • Full conditions:(rear+1)% Maxsize==front
Queue(){function init(self,size=100){self.queue=[0,size.random()] self.size=size self.front=0 } function push(self,element){self.rear=(self.rear+1)%self.size self.queue[self.rear]=element} function pop(self){ if(! self.isEmpty()){ self.front=(self.front+1) % self.size return self.queue[self.front] }else{ console.log('error') } } function isEmpty(self){ return self.rear==self.front } function isFilled(self){ return (self.rear+1)%self.size==self.front } }Copy the code

(2) Dual-end queue:

  • You can use a double linked list
  • Data can be viewed, added, and deleted at both ends of the queue in O(1) time
  • Scenario: Implement a window or continuous interval of dynamically varying length. Leecode239 problem (maximum sliding window)

(3) Priority queue

  • Different from ordinary queue: Ensure that the element retrieved each time is the highest priority in the queue, and the priority can be customized
  • The most common scenario: filtering data in order (or priority) from disordered data
  • The Binary Heap is an array structure that implements a full Binary tree
  • Property: The first element in an arrayarray[0]Have the highest priority
  • Given a lower indexiSo, for the elementsarray[i]In terms of
  • The element index corresponding to the parent node is(i-1)/2
  • The element index corresponding to the left child node is2*i+1
  • The subscript of the element corresponding to the right subnode is2*i+2
  • Each element in the array must have a higher priority than the child nodes on either side
  • Basic operation: filter up, filter down
  • Time complexity:O(logk)
  • Initialize a heap of size n with a time complexity ofO(n). Leetcode347 topic

5. The sorting

Bubble sort, selection sort, and insertion sort are all O(n*n) times.

  1. Bubble sort: Starts with the first element and compares the size to the next indexed element.Swap positions if the current element is largeTo the last element. So the last element is going to be the largest number in the array. The next round repeats the above, but at this pointThe last element is already the maximumSo we don’t have to compare the last element, we just have to compare tolength-2The location of the
    • The time complexity is O(n*n)
// Use a double loop to sort. Function sort(array){let TMP = 0; function sort(array){let TMP = 0; for(let i = 0; i < array.length; i++){ for(let j = 0; j < array.length - i - 1; j++){ if(array[j] > array[j+1]){ tmp = array[j]; array[j] = array[j+1]; array[j+1] = tmp; }}} return array} let array =[5,8,6,3,9,2,1,7]; sort(array);Copy the code

Optimization: If we can determine that the sequence is in order and make a mark (so that we use a variable to judge), the remaining rounds of sorting can be done without performing, and the bundle work can be finished earlier

function sort(array){ let tmp = 0; for(let i = 0; i < array.length; I++) {// sorted tags, each round starts with true let isSorted = true; for(let j = 0; j < array.length - i - 1; j++) { if(array[j] > array[j+1]){ tmp = array[j]; array[j] = array[j+1]; array[j+1] = tmp; isSorted = false; }} if(isSorted){break;}} if(isSorted){break; }}} let array = [5,8,6,3,9,2,1,7]; sort(array);Copy the code

If the rest of the array is ordered, you can optimize by * setting the boundary of an unordered sequence and stopping the sorting every time it reaches this point

function sort(array){ let tmp = 0; let lastExchangeIndex = 0; Let sortBorder = array. Length - 1; For (let I = 0; let I = 0; i < array.length; i++){ let isSorted = true; For (let j = 0; let j = 0; j < sortBorder; j++){ if(array[j] > array[j+1]){ tmp = array[j]; array[j] = array[j+1]; array[j+1] = tmp; isSorted = false; // lastExchangeIndex = j; }} sortBorder = lastExchangeIndex;}} sortBorder = lastExchangeIndex; if(isSorted){ break; }}} let array = [3,4,2,1,5,6,7,8]; sort(array);Copy the code
  1. Insertion sort:The first element is sorted by default, and compare the next element with the current one, switching positions if the current one is large. So the first element is the current minimum, so the next fetch starts with the third element, compares forward, and repeats the previous operation. Such as:,38,5,47,36,26 [3]
    • Time complexity O(n*n) : LeetCode 147 Problem
// You can imagine that the value to be inserted is a card drawn from somewhere else, Function insert_sort(li){for (var I in (1, {let TMP =li[I] j=i-1 while(j>=0 && TMP <li[j]){ Li [j+1]= li[j] j=j-1} li[j+1]= TMP} li[j+1]= TMPCopy the code
  1. Selection sort: Traverses the array and sets the index of the minimum value to 0. If the retrieved value is smaller than the current minimum value, the minimum index is replaced. After traversing, the first element is exchanged with the value on the minimum index. After that, the first element is the minimum value in the array, and the next iteration can repeat the operation starting at index 1. Such as:,38,5,47,36,26 [3]
    • The time complexity is O(n*n)
// Since the minimum value of the unordered region can be obtained each time traversal, the region where the swapped value is located is the ordered region. Function select_sort(li){for (var I in li.length-1){let min_loc= I, select_sort(li){for (var I in li.length-1){let min_loc= I, So let's say it's the first place in the unordered region for(var j; J > = I + 1 & j < li. Length; J ++){if(li[j]<li[min_loc]){min_loc=j}} li[I]=li[min_loc] li[min_loc]=li[i] } return li }Copy the code

Merge sort, quicksort, heapsort —- all have order nlogn time.

  • In general, in terms of running time: quicksort < merge sort < heap sort
  • Disadvantages of the three sorting algorithms:
    1. Quicksort: Sorting is inefficient in extreme cases
    2. Merge sort: Additional memory overhead
    3. Heapsort: relatively slow among fast sorting algorithms
  1. Merge sort: The array is divided into two elements of a group of multiple arrays, then the order of the synthesis of a large array
    • Time is O(N*logN), space is O(N).
    • steps
      1. Decompose: Break the list down into smaller and smaller pieces until it is a single element
      2. Termination condition: An element is ordered
      3. Merge: Merge two ordered lists to make the list bigger and bigger
      function merge(li,low,mid,high){ let i=low, J = + 1 LTMP mid = [] while (I < = mid & j < = high) {/ / as long as both sides have several if li [I] < = li [j]) {LTMP. Append (li) [I] I + = 1} else {LTMP. Append (li [j].) J +=1}} j+=1}} While (I <=mid){ltmp.append(li[I]) I +=1} while(j<=high){ltmp.append(li[J]) j+=1} li[low,high+1]= LTMP} function mergesort(li,low,high){ if(low<high){ mid=(low+high)/2 mergesort(li,low,mid) mergesort(li,mid+1,high) merge(li,low,mid,high) } }Copy the code
  2. Quick row: first take out a reference value, put the larger value on the right, put the smaller value on the left, after the comparison is completed, the reference value and the first value larger than the reference value exchange position, and then the array is divided into two parts according to the position of the reference value, continue the recursion above operation.

Quicksort is nlogn in general, and n*n in the worst case. (You can only sort one more order value each time you recurse.)

function partition(li,left,right){ let tmp=li[left] while(left < right){ while(left<right && } li[right] =li[right] while(left<right && li[right]<= TMP){li[right] =li[right] =li[right]; Left +=1} li[right]=li[left] return left} function quick_sort(li,left,right){ If (left<right){if(mid=partition(li,left,right) =partition(li,left,right);Copy the code
  1. Heap sort* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    • Establish a heap
    • Get the top element of the heap, which is the largest element
    • Remove the top of the heap and place the last element of the heap on top of the heap. At this point, the heap can be reordered by a single adjustment
    • The top element of the heap is the second largest
    • Repeat Step 3 until the heap is empty

Downward adjustment properties of the heap :1. Assume that the left and right subtrees of the root node are heaps, but the root node does not satisfy the properties of heap; 2. 2. It can be adjusted down to a heap time complexity of nlogn

Function sift(data,low,high){let I =low, j=2* I +1, j=2* I +1, While (j<=high){// if(j<high&&data[j]<data[j+1]){// if(j<high&&data[j]<data[j+1]){// if(j<high&&data[j]<data[j+1]){// if(j<high&&data[j]<data[j+1]){// if(j<high&&data[j]<data[j+1]){// if(j<high&&data[j]<data[j+1]){// if(j<high&&data[j]<data[j+1]) } the if (temp < data [j]) {data [I] = data [j] I = j / / to look down a layer of j = 2 * I + 1} else {/ / TMP is bigger, Break}} data[I]= TMP} function heap_sort(data){let n=data.length for(let I in) For (let j in range(n-1,-1,-1)){sift(data, I,n-1); for(let j in range(n-1,-1,-1)) Data [0] = data data [I] [I] = data [0] sift (data, 0, I - 1) / / I - 1 is a new high}}Copy the code

Extension: topK problem: now there are n numbers, design the algorithm to get the first k large number (k<n) (such as weibo hot search)

  • solution
    1. Take the first k elements of the list and build a little root heap. The top of the heap is the KTH largest number so far
    2. The list is traversed backwards. If the element in the list is smaller than the top of the heap, the element is ignored. If it is larger than the top of the heap, the top of the heap is replaced with that element, and the heap is adjusted once
    3. After iterating through all the elements of the list, the top of the heap pops up in reverse order
  • The solution
    1. After sorting sliceO(nlogn)
    2. Bubble sort, selection sort, insertion sortO(kn)
    3. Heap sort IdeaO(nlogk)
Function sift(data,low,high){let I =low, j=2* I +1, j=2* I +1, While (j<=high){if(j<high&&data[j]>data[j+1]){j+=1} If (temp>data[j]){data[I]=data[j] I =j // else{break}} data[I]= TMP // else} function topk(li,k){ let heap=li[0,k] for(let i in range((k-2/2),-1,-1)){ sift(heap,i,k-1) } //1. Pile built for (the let I in range (k, li. Length - 1)) {if li [I] > heap [0]) {heap [0] = li [I] sift (heap, 0, k - 1)}} / / 2. Traverse the for (let I in range (k - 1, 1, 1)) {heap heap [0], [I] = heap [I], heap [0] sift (heap, 0, I - 1)} / / 3. Return heap}Copy the code

Conclusion:

6. List

  • A linked list is a collection of elements made up of a series of nodes. Each node contains two parts, the data domainitemAnd a pointer to the next nodenext. Through the mutual connection between nodes, the final series into a linked list
class Node(object){ function init(self,item){ self.item=item self.next=None } } function create_linklist(li){ let head=Node(li[0]) for(element in li){ node=Node(element) node.next=head head=node } return head } function create_linklist_tail(li){ let head=Node(li[0]), tail=head for(element in li){ node=Node(element) tail.next=node tail=node } return head } Lk = create_linklist_tail (,2,3,5,6 [1])Copy the code
  • Create a linked list: head insert, tail insert
  • Insertion and deletion of linked list nodes
    • Insert:
       p.next=curNode.next
       curNode.next=p
    Copy the code

  • delete
  p=curNode.next
  curNode.next=curNode.next.next
  del p
Copy the code

  • Double-linked list: Each node of a double-linked list has two Pointers: one to the latter and one to the former

  • Insertion of a double linked list node
    p.next=curNode.next
    curNode.next.prior=p
    p.prior=curNode
    curNode.next=p
    Copy the code

  • The double-linked list node is deleted
  p=curNode.next
  curNode.next=p.next
  p.next.prior=curNode
  del p
Copy the code

  • Linked list and sequential list

    • Linked lists are significantly faster than sequential lists in insert and delete operations
    • Linked list memory can be allocated more flexibly (try using linked list to reallocate stacks and queues)
    • The linked list, a data structure stored in chain, has great implications for the structure of trees and graphs
  • What is the difference between an array and a linked list? What are the characteristics of a linked list?

    • Array allocates memory statically, linked list allocates memory dynamically;
    • Arrays are contiguously in memory, lists are not contiguously;
    • Array elements in the stack area, list elements in the heap area;
    • Arrays can be quickly located by subscript with time complexity of O(1), and linked list elements with time complexity of O(n) (because linked list access to elements requires moving the pointer);
    • Arrays are O(n) time to insert or delete elements (because a large number of elements need to be moved), and lists are O(1) time to insert or delete elements (because only pointer changes are needed).

Javascript implements the linked list data structure and inverts the single list method

Function myReverse (linkedList) {var head = linkedList. Head // 2 . = = = null | | head next = = = null) return linkedList, three pointer var / / 3, the current head var pre = null var next = = null If the current node is not null, get the next node of the current node and set current to the next node, pre to the current node while(current! = null) { next = current.next current.next = pre pre = current current = next } linkedList.head = pre }Copy the code

Extension: obtain the reciprocal KTH node of the list, the list of intermediate nodes and determine whether there is a link blog.csdn.net/qq_40608516…

Tree of 7.

  • A tree is a data structure, such as a directory structure
  • A tree is a data structure that can be defined recursively
  • A tree is a set of n nodes: if n=0, it is an empty tree; If n>0, there is one node as the root node of the tree, and the other nodes can be divided into m sets, each of which is itself a tree
  • Degree of tree: The maximum number of forks of a node in a tree is the degree of the tree
  • Tree commonality: intuitive structure, through the tree problem to investigate the mastery of recursive algorithm proficiency
  • The tree shapes often tested in the interview are: ordinary binary tree, balanced binary tree, complete binary tree, binary search tree, quadtree, multi-tree

Special trees: red-black trees, self-balancing binary search trees

(1) Binary tree

First of all, what is a binary tree

  1. Binary tree
    • Binary tree: a tree whose degree does not exceed 2
    • Each node has a maximum of two child nodes
    • The two child nodes are divided into the left child node and the right child node
  2. Full binary tree: A binary tree that is full if the tree of nodes at each level reaches its maximum value
  3. Complete binomial tree: a binomial tree whose leaf nodes can only appear in the lowest level and the second level, and the nodes in the lowest level are concentrated in the leftmost positions of the layer
    • Large root heap: a complete binary tree where any node is larger than the other child nodes
    • Small root heap: a complete binary tree where any node is smaller than its children

Binary tree storage (representation)

  1. Chain storage: the node of the binary tree is defined as an object, and the nodes are connected by a link way similar to a chain list
  2. Sequential storage (with lists)

Binary tree first order, order, order after traversal

  • Preorder traversal means to access the root node first, then the left node, and finally the right node: Application scenario (searching in the tree or creating a new tree)
  • In the order traversal, the left node is first accessed, then the root node is accessed, and finally the right node is accessed: Application scenario (binary search tree: the root node is greater than the left node and less than the right node, generally does not occur repeated values), Leetcode 第230题
  • A sequential traversal means visiting the left node first, then the right node, and finally the root node: for example, problem LeetCode250

Specific introduction reference:Binary tree traversal (first order, middle order, last order)

In order traversal of the predecessor and successor nodes:

Precursor node: is the relative previous successor node in the in-order traversal sort: is the relative last node in the in-order traversal sort

The depth of the tree

(2) Prefix tree (also known as dictionary tree) : This data structure is widely used in dictionary lookups

What is a dictionary lookup? For example /; Given a list of strings that make up a dictionary, find all the strings starting with “ABC” in the dictionary

    • Method one: violent search method

    Time complexity: O(M*N) starts with M

    • Method two: prefix tree

    Time complexity: O(M)

  1. Application scenario:
  • Enter the search text in the search box to return to a list of related searches that begin with the search term
  • Chinese pinyin input method
  1. Important properties:
  • Each node contains at least two basic properties
    • Children: an array or collection that lists all the characters contained in each branch
    • IsEnd: A Boolean value indicating whether the object is the end of a string
  • The root node is empty
  • All nodes except the root node may be the end of the word, and the leaf node must be the end of the word

4. Basic operations

  • Create by
    • Iterates over the input string, iterating over the characters of each string
    • Each character is added to the children character set of the node, starting from the root node of the prefix tree
    • If the character set already contains this character, skip it
    • If the current character is the last of the string, mark the isEnd of the current node as true
  • Search by
    • The input prefix characters are matched one by one starting from the root node of the prefix tree
    • If you do, move on to the next level
    • If not, return immediately

Leetcode212 (you can use the depth-first algorithm)

(3) Line segment tree

Suppose I take the sum (or average) of the elements in any interval of an array.

  • Method 1: Walk through the array: time is O(n)
  • Method 2: line segment tree: the time complexity is O(logn), which depends on the height of the tree

What is a segment tree? A structure that stores data in the form of a binary tree, where each node holds the sum of a segment of an array for example

(4) Tree array

Recursion and backtracking

  • Recursion: top down
  • 5. Leetcode 39 (Sum of combinations)

Can be used in the following algorithm:

  • Definition and traversal of binary trees
  • Merge sort, quicksort
  • Dynamic programming
  • Binary search
Extension 1: What are the advantages and disadvantages of recursion

Advantage: Simple code. Easy to understand

Disadvantages:

  1. Time and space consumption is relatively large:

Recursion is due to the function call itself, and function calls consume time and space. With each function call, space needs to be allocated in the memory stack to hold parameters, return values, and temporary variables. Pushing and popping data on the stack also takes time, which reduces efficiency.

  1. Double counting:

In recursion, many calculations are repeated. The essence of recursion is to decompose a problem into two or more problems, and there are overlapping parts of multiple problems, that is, there is double calculation. Such as Fibonacci sequence recursive implementation.

  1. Stack overflow.

Recursion can have stack overflow, with each call allocating space in the memory stack. The capacity of the stack space is limited. When the number of calls is too many, the capacity of the stack may be exceeded, resulting in the call stack overflow

Extension 2: Find the number of occurrences of a number in an ordered array:
  • You can use binary search
  • A direct comparison
int findCount(int a[],int len ,int key) { int i,count = 0; for(i=0; i<len; i++) { if(key==a[i]) count++; } return count; }Copy the code

9. Dynamic programming

Dynamic programming contains three important concepts:

  • Optimal substructure
  • The border
  • State transition formula

The essence of dynamic programming is actually two points: 1. Decompose subproblems from the bottom up; 2. Store calculated solutions through variables

  • Dynamic programming of Fibonacci series:
    • The Fibonacci sequence starts at 0 and 1, so that’s the bottom of the subproblem
    • An array is used to store the Fibonacci sequence values for each bit
  • 0-1 knapsack problem: reference algorithm problem of dynamic programming -01 knapsack problem

The hash table

A data structure that uses a hash function to calculate where data is stored. It usually supports the following operations:

  • Insert (key,value) : insert(key,value)
  • Get (key) : Return value if there is a key-value pair with key, null otherwise
  • Delete (key) : deletes the key-value pair whose key is key
  1. We have 100,000 pieces of data in the array, so let’s take the time difference between the first element and the 100,000th element

    JavaScript doesn’t really have arrays. All arrays are actually objects whose “indexes” look like numbers but are actually converted to strings that are used as property names (the key of the object). So whether you take the first element or you take the 100,000th element, it takes about the same amount of time to find the table exactly with the key.

  2. Given two arrays, write a method to calculate their intersection

    The space-for-time idea is to use a Hash table to store the elements of array 1 and the number of occurrences (in this case, you need to iterate n times and have an N-level space).

Iterates through array 2, finds Hash table values in array 2, stores them in array Result, and reduces the Hash table value by one (Delete after 0). If it doesn’t exist in the Hash table, skip it. So the time complexity is m plus n.

The other method has two arrays m,n. If so, push the value in m to the Result array and remove it from the m array (splice). In this way, there is no extra space, but the time complexity is increased.

const intersect = (nums1, nums2) => { const map = {} const res = [] for (let n of nums1) { if (map[n]) { map[n]++ } else { map[n] = 1 } } for (let  n of nums2) { if (map[n] > 0) { res.push(n) map[n]-- } } return res }Copy the code
  1. Continuous numerical reduction
Write a function that does the following: Input '1, 2, 3, 5, 7, 8, 10' Output '1 to 3, 5, 7 to 8, 10' Input description Input '1, 2, 3, 5, 7, 8, 10' Output description Output '1 to 3, 5, 7 to 8, 10' example 1 input 1,2,3,5,7,8,10 output 1 to 3,5,7 to 8,10Copy the code

The answer:

function transformStr(str) {
    let arr = str.split(',')
    let i = 0
    let ret = []
    for (let j = 1; j <= arr.length; j++) {
        if (arr[j] - arr[j - 1] !== 1) {
            ret.push(j - i === 1 ? arr[i] : `${arr[i]}~${arr[j - 1]}`)
            i = j
        }
    }
    return ret.join(',')
}
或者
function simplifyStr(num) {
  var result = [];
  var temp = num[0]
  num.forEach((value, index) => {
    if (value + 1 !== num[index + 1]) {
      if (temp !== value) {
        result.push(`${temp}~${value}`)
      } else {
        result.push(`${value}`)
      }
      temp = num[index + 1]
    }
  })
  return result;
}

Copy the code
  1. Data conversion
function commonSearch(target, id, mode) { const staskOrQuene = [...target] do { const current = staskOrQuene[mode === 'dfs' ? 'pop' : 'shift']() if (current.children) { staskOrQuene.push(... current.children.map(x => ({ ... x, path: (current.path || current.id) + '-' + x.id }))) } if (current.id === id) { return current } } while(staskOrQuene.length) Return undefined} var aa = [{id: 1, name: 'in guangdong, the children: [{id:' 11 ', name: 'shenzhen', children: [{id: '111', name: 'nanshan district'}, {id: '112', name: '*'}]}}]] commonSearch (aa, 112).Copy the code

Leetcode-cn.com/explore/int…

11. Figure

Most basic knowledge:

  • Degree (exit degree, entry degree)
  • Tree, forest, ring
  • Digraph, undigraph, completely digraph, completely undigraph
  • Connected graph, connected component
  • The storage and expression of graphs: adjacency matrix, adjacency list

Algorithm around the graph:

  • Graph traversal: depth-first, breadth-first
  • Detection of rings: directed and undirected graphs
  • A topological sort
  • Shortest path algorithm
  • Connectivity correlation algorithm
  • Graph coloring, traveling salesman problem, etc

Knowledge points to master:

  • The storage and expression of graphs: adjacency matrix, adjacency list
  • Graph traversal: depth-first, breadth-first
  • Bipartite graph detection, tree detection, ring detection: directed graph, undirected graph
  • A topological sort
  • Joint search algorithm
  • The shortest path