Если вы участвовали в каком-либо процессе собеседования, то вы знаете, что во время технического собеседования необходимо задать вопросы о структуре данных. На самом деле, это очень распространенная и самая важная тема для любого собеседования. С помощью вопросов DS интервьюер может оценить способности кандидата. В этой статье я собрал несколько основных вопросов DS, которые задаются на собеседовании по JavaScript.
Множество
1. Удалите все четные целые числа из массива.
Ввод: [4, 1, 9, 10, 15, 22, 5, 14]
Вывод: [4, 10, 22, 14]
У этой проблемы есть несколько решений, все полностью зависит от кандидата. Здесь я предлагаю два решения с пояснениями.
Решение - 1
const inputData = [4, 1, 9, 10, 15, 22, 5, 14] removeEvenNumbers (inputData) => { let odds = [] for (let number of inputData) { if (number % 2 != 0) odds.push(number) } return odds } console.log(removeEvenNumbers(inputData))) // [4, 10, 22, 14]
В приведенном выше решении мы перебираем каждый элемент и проверяем, четный он или нечетный. Если это странно, мы помещаем это в отдельный массив. Таким образом, временная сложность этой задачи равна O (n) O (n).
Решение - 2
removeEvenNumbers(inputData) => { return inputData.filter((number => (number % 2) != 0)) } console.log(removeEvenNumbers(inputData))
Это решение также выполняет итерацию по всем элементам и проверяет их четность. Если он четный, он отфильтровывает этот элемент. Я использовал filter
для фильтрации данных массива. Он просто отфильтровывает данные, которые возвращают ложное значение. Имеет такую же временную сложность.
2. Найдите все повторяющиеся числа в массиве
Ввод: [1,2,4,5,6,1,3,7,9,10]
Вывод: [1, 2, 4, 5, 6, 3, 7, 9, 10]
const findUniqueNos = (inputData) => { let uniqueNumbers = [] inputData.map(number => { let counts = uniqueNumbers.filter(uniqueNo => uniqueNo == number) if(counts.length != 1) uniqueNumbers.push(number) }) return uniqueNumbers } console.log(findUniqueNos(inputData))
Простой? Да, вам нужно пройти через массив, а перед этим вам нужно создать один пустой массив и продолжать вводить в него уникальный номер. Просто используйте фильтрацию, чтобы определить, есть ли номер там или нет.
Куча
1. Подтвердите сбалансированные скобки
Напишите функцию, которая принимает только круглые скобки (фигурные {}
, квадратные []
или круглые ()
). Он должен проверить, сбалансированы ли все круглые скобки в предоставленной строке. Просто он должен проверить, есть ли открывающие скобки, а затем должны быть закрывающие скобки.
Первый ввод: {[({})]}
Первый вывод: true
Второй ввод: {[({})}
Второй вывод: false
class Stack { constructor() { this.items = [] this.top = null } getTop() { if (this.items.length == 0) return null return this.top } isEmpty() { return this.items.length == 0 } size() { return this.items.length } push(element) { this.items.push(element) this.top = element } pop() { if (this.items.length != 0) { if (this.items.length == 1) { this.top = null return this.items.pop() } else { this.top = this.items[this.items.length - 2] return this.items.pop() } } else return null } } isBalancedParantheses(exp) => { let myStack = new Stack() // Loop through input string for (let i = 0 i < exp.length i++) { // Check for every closing parantheses if there's opeaning parantheses or not. if (exp[i] == '}' || exp[i] == ')' || exp[i] == ']') { if (myStack.isEmpty()) return false let output = myStack.pop() //If no opening parentheses for any closing one then immediatly return false if (((exp[i] == "}") && (output != "{")) || ((exp[i] == ")") && (output != "(")) || ((exp[i] == "]") && (output != "["))) { return false } } else { //For each opening parentheses, push it into stack myStack.push(exp[i]) } } //after traversal of input data, if there's any opening parentheses left in stack then also return false else return true at the end if (myStack.isEmpty() == false) { return false } return true } let firstInputData = "{[({})]}" console.log(isBalancedParantheses(firstInputData)) secondInputData = "{[({})}" console.log(isBalancedParantheses(secondInputData))
Итак, вначале мы перебираем строку и проверяем символ за символом. Есть два способа определить несбалансированные круглые скобки. Сначала по значению стека, затем по верхнему элементу стека. Для этого нам нужно проверить, пуст ли стек? ИЛИ Подходит ли верхний элемент в стеке? Выполняется любое из этих двух условий, мы немедленно возвращаем false
Opeaning paranthesis, помещенный в стек, и, если мы получили совпадение, оно будет вставлено. Так что вы можете задаться вопросом, какова временная сложность этого кода, поскольку мы повторяем только один раз, сложность будет O (n).
2. Напишите функцию преобразования чисел в основание 2 и 8.
В этой программе вы должны написать одну функцию, которая будет принимать целочисленное значение и одно базовое значение, а затем преобразовывать их соответствующим образом. Как, например, если введено число = 14
и основание = 2
, тогда результат будет 1110
, а число = 14
и основание = 8, тогда результат будет 16
.
Stack() => { constructor() { this.items = [] this.top = 0 } push (element) => { this.items[this.top++] = element } pop () => { return this.items[--this.top] } length () => { return this.top } } convertBase(num, base) => { let s = new Stack() while( num > 0 ){ s.push(num % base) num = Math.floor(num /= base) } let converted = "" while (s.length() > 0) { converted += s.pop() } return converted } let num = 14 let base = 2 console.log(convertBase(num, base))
В этой программе в основном мы помещаем число в стек после преобразования, затем вставляем одну за другой цифру числа и затем возвращаем целое число.
Очередь
1. Выведите двоичное число до N, где N может быть любым положительным целым числом.
В этой задаче нам нужно написать программу, которая будет принимать целые числа и до предела генерировать двоичные числа. Подобно входному числу n = 3
, результат должен быть [1,10,11]
module.exports = class Queue { constructor() { this.items = [] this.front = null this.back = null } isEmpty() { return this.items.length == 0 } getFront() { if (this.items.length != 0) { return this.items[0] } else return null } size() { return this.items.length } enqueue(element) { this.items.push(element) } dequeue() { if (this.items.length == 0) { return null } else { return this.items.shift() } } } generateBinaryNumbers(n) => { let result = [] let myQueue = new Queue() let s1, s2 myQueue.enqueue("1") for (let i = 0 i < n i++) { result.push(myQueue.dequeue()) s1 = result[i] + "0" s2 = result[i] + "1" myQueue.enqueue(s1) myQueue.enqueue(s2) } return result } console.log(generateBinaryNumbers(3))
Для генерации двоичного числа нам нужно добавить 0 и 1 к предыдущему двоичному числу, например, из 1
мы можем сгенерировать 10
и 11
, добавив 0 и 1. Как только вы сгенерируете двоичное число, тогда enqueue
в очередь для генерации следующего числа, добавив 0 и 1. Временная сложность данного решения находится в O (n) O (n), потому что одна и та же операция выполняется n раз.
2. Объясните, как работает система приоритетной очереди.
В этой программе сначала нужно создать очередь, а затем реализовать очередь с приоритетом. Разрешите пояснить на примере.
Patient(name, code) => { this.name = name this.code = code } Queue() => { this.dataStore = [] enqueue(element) => { this.dataStore.push(element) } dequeue() => { let priority = this.dataStore[0].code for (let i = 1; i < this.dataStore.length; ++i) { if (this.dataStore[i].code < priority) { priority = i } } return this.dataStore.splice(priority,1) } front() => { return this.dataStore[0] } back() => { return this.dataStore[this.dataStore.length-1] } toString() => { let retStr = "" for (let i = 0; i < this.dataStore.length; ++i) { retStr += this.dataStore[i].name + " code: " + this.dataStore[i].code + "\n" } return retStr } empty() => { if (this.dataStore.length == 0) { return true } else { return false } } let p = new Patient("Smith",5) let ed = new Queue() ed.enqueue(p) p = new Patient("Jones", 4) ed.enqueue(p) p = new Patient("Fehrenbach", 6) ed.enqueue(p) p = new Patient("Brown", 1) ed.enqueue(p) p = new Patient("Ingram", 1) ed.enqueue(p) console.log(ed.toString()) let seen = ed.dequeue() console.log("Patient being treated: " + seen[0].name) console.log("Patients waiting to be seen: ") console.log(ed.toString()) // another round let seen = ed.dequeue() console.log("Patient being treated: " + seen[0].name) console.log("Patients waiting to be seen: ") console.log(ed.toString()) let seen = ed.dequeue() console.log("Patient being treated: " + seen[0].name) console.log("Patients waiting to be seen: ") console.log(ed.toString())
Сгенерированный результат показан ниже,
Smith code: 5 Jones code: 4 Fehrenbach code: 6 Brown code: 1 Ingram code: 1 Patient being treated: Jones Patients waiting to be seen: Smith code: 5 Fehrenbach code: 6 Brown code: 1 Ingram code: 1 Patient being treated: Ingram Patients waiting to be seen: Smith code: 5 Fehrenbach code: 6 Brown code: 1 Patient being treated: Brown Patients waiting to be seen: Smith code: 5 Fehrenbach code: 6
Как следует из названия, приоритетная очередь используется, когда вы хотите удалить что-то из очереди на основе приоритета. Итак, здесь я возьму пример пациента, и это номер посещения. В основном это приемная любой больницы. Здесь функция dequeue()
удалит пациента из очереди на основе самого низкого приоритета, после чего toString()
изменит обработанный объект пациента.
Связанный список
1. Напишите программу для переворота связного списка.
Ввод: такой связанный список LinkedList = 0->1->2->3-4
Вывод: список с обратной связью LinkedList = 4->3->2->1->0
class Node { constructor(data) { this.data = data this.nextElement = null } } class LinkedList { constructor() { this.head = null } //Insertion At Head insertAtHead(newData) { let tempNode = new Node(newData) tempNode.nextElement = this.head this.head = tempNode return this //returning the updated list } isEmpty() { return (this.head == null) } to print the linked lis=> t printList() { if (this.isEmpty()) { console.log("Empty List") return false } else { let temp = this.head while (temp != null) { process.stdout.write(String(temp.data)) process.stdout.write(" -> ") temp = temp.nextElement } console.log("null") return true } } getHead() { return this.head } setHead(newHead) { this.head = newHead return this } getListStr() { if (this.isEmpty()) { console.log("Empty List") return "null" } else { let st = "" let temp = this.head while (temp != null) { st += String(temp.data) st += " -> " temp = temp.nextElement } st += "null" return st } } insertAtTail(newData) { //Creating a new Node with data as newData let node = new Node(newData) //check for case when list is empty if (this.isEmpty()) { //Needs to Insert the new node at Head this.head = node return this } //Start from head let currentNode = this.head //Iterate to the last element while (currentNode.nextElement != null) { currentNode = currentNode.nextElement } //Make new node the nextElement of last node of list currentNode.nextElement = node return this } search(value) { //Start from the first element let currentNode = this.head //Traverse the list until you find the value or reach the end while (currentNode != null) { if (currentNode.data == value) { return true //value found } currentNode = currentNode.nextElement } return false //value not found } deleteAtHead() { //if list is empty, do nothing if (this.isEmpty()) { return this } //Get the head and first element of the list let firstElement = this.head //If list is not empty, link head to the nextElement of firstElement this.head = firstElement.nextElement return this } deleteVal(value) { let deleted = null //True or False //Write code here //if list is empty return false if (this.isEmpty()) { return false } //else get pointer to head let currentNode = this.head // if first node's is the node to be deleted, delete it and return true if (currentNode.data == value) { this.head = currentNode.nextElement return true } // else traverse the list while (currentNode.nextElement != null) { // if a node whose next node has the value as data, is found, delete it from the list and return true if (currentNode.nextElement.data == value) { currentNode.nextElement = currentNode.nextElement.nextElement return true } currentNode = currentNode.nextElement } //else node was not found, return false deleted = false return deleted } deleteAtTail() { // check for the case when linked list is empty if (this.isEmpty()) { return this } //if linked list is not empty, get the pointer to first node let firstNode = this.head //check for the corner case when linked list has only one element if (firstNode.nextElement == null) { this.deleteAtHead() return this } //otherwise traverse to reach second last node while (firstNode.nextElement.nextElement != null) { firstNode = firstNode.nextElement } //since you have reached second last node, just update its nextElement pointer to point at null, skipping the last node firstNode.nextElement = null return this } } /Access HeadNode => list.getHead() //Set the value of HeadNode => list.getHead() //Check if list is empty => list.isEmpty() //Insert at head => list.insertAtHead(value) //Delete at head => list.deleteAtHead() //Insert at tail => list.insertAtTail(value) //Search for element => list.search(value) //Delete by value => list.deleteVal(value) //Node class { data Node nextElement} reverse(list) => { let previousNode = null let currentNode = list.getHead() // The current node let nextNode = null // The next node in the list //Reversal while (currentNode != null) { nextNode = currentNode.nextElement //stores thecurrent
node’snextElement
innext
currentNode.nextElement = previousNode // Setcurrent
node’snextElement
toprevious
previousNode = currentNode // Make thecurrent
node the newprevious
for the next iteration currentNode = nextNode // Usenext
to go to the next node } //Set the last element as the new head node list.setHead(previousNode) } let list = new LinkedList() list.insertAtHead(4) list.insertAtHead(9) list.insertAtHead(6) list.insertAtHead(1) list.insertAtHead(0) list.printList() reverse(list) list.printList()
В приведенной выше программе сначала мы перебираем цикл и продолжаем добавлять элементы в связанный список и делать его обратным. Как видите, цикл выполняется только один раз, поэтому программа завершается за O (n).
Дерево
1. Найдите минимальное значение из двоичного дерева поиска (BST).
Вход: корневой узел для двоичного дерева поиска.
bst = {
6 -> 4, 9 //parent -> leftChild, rightChild
4 -> 2, 5
9 -> 8, 12
12 -> 10, 14
}
Вывод: 2
class Node { constructor(value) { this.val = value this.leftChild = null this.rightChild = null } } class BinarySearchTree { constructor(rootValue) { this.root = new Node(rootValue) } insert(currentNode, newValue) { if (currentNode === null) { currentNode = new Node(newValue) } else if (newValue < currentNode.val) { currentNode.leftChild = this.insert(currentNode.leftChild, newValue) } else { currentNode.rightChild = this.insert(currentNode.rightChild, newValue) } return currentNode } insertBST(newValue) { if(this.root==null){ this.root=new Node(newValue) return } this.insert(this.root, newValue) } preOrderPrint(currentNode) { if (currentNode !== null) { console.log(currentNode.val) this.preOrderPrint(currentNode.leftChild) this.preOrderPrint(currentNode.rightChild) } } inOrderPrint(currentNode) { if (currentNode !== null) { this.inOrderPrint(currentNode.leftChild) console.log(currentNode.val) this.inOrderPrint(currentNode.rightChild) } } postOrderPrint(currentNode) { if (currentNode !== null) { this.postOrderPrint(currentNode.leftChild) this.postOrderPrint(currentNode.rightChild) console.log(currentNode.val) } } search(currentNode, value) { if (currentNode !== null) { if (value == currentNode.val) { return currentNode } else if (value < currentNode.val) { return this.search(currentNode.leftChild, value) } else { return this.search(currentNode.rightChild, value) } } else { return null } } searchBST(value) { return this.search(this.root, value) } delete(currentNode, value) { if (currentNode == null) { return false } let parentNode while (currentNode && (currentNode.val != value)) { parentNode = currentNode if (value < currentNode.val) { currentNode = currentNode.leftChild } else { currentNode = currentNode.rightChild } } if (currentNode === null) { return false } else if (currentNode.leftChild == null && currentNode.rightChild == null) { if(currentNode.val==this.root.val){ this.root=null return true } else if (currentNode.val < parentNode.val) { parentNode.leftChild = null return true } else { parentNode.rightChild = null return true } } else if (currentNode.rightChild == null) { if(currentNode.val==this.root.val){ this.root=currentNode.leftChild return true } else if (currentNode.leftChild.val < parentNode.val) { parentNode.leftChild = currentNode.leftChild return true } else { parentNode.rightChild = currentNode.leftChild return true } } else if (currentNode.leftChild == null) { if(currentNode.val==this.root.val){ this.root = currentNode.rightChild return true } else if (currentNode.rightChild.val < parentNode.val) { parentNode.leftChild = currentNode.rightChild return true } else { parentNode.rightChild = currentNode.rightChild return true } } else { let minRight = currentNode.rightChild while (minRight.leftChild !== null) { minRight = minRight.leftChild } let temp=minRight.val this.delete(this.root, minRight.val) currentNode.val = temp return true } } } findMin(rootNode) => { if(rootNode == null) return null else if(rootNode.leftChild == null) return rootNode.val else return findMin(rootNode.leftChild) } let BST = new BinarySearchTree(6) BST.insertBST(20) BST.insertBST(-1) console.log(findMin(BST.root))
Эта программа начинается с проверки, является ли корень BST null
или нет. Если не ноль, то перемещается в левую часть дерева и продолжает проверку, пока вы не сможете отреагировать в конце. Итак, тогда вы получите наименьшее число.
График
1. Удалить край
Реализуйте программу, чтобы получить данные графика, которые включают источник и место назначения. Он также должен определять, есть ли между ними граница.
Входные данные: график, источник и пункт назначения.
Вывод: график с удаленным краем между источником и местом назначения.
removeEdge(graph, 2, 3)
class Node { constructor(data) { this.data = data this.nextElement = null } } class LinkedList { constructor() { this.head = null; } //Insertion At Head insertAtHead(newData) { let tempNode = new Node(newData); tempNode.nextElement = this.head; this.head = tempNode; return this; //returning the updated list } isEmpty() { return (this.head == null); } //function to print the linked list printList() { if (this.isEmpty()) { console.log("Empty List"); return false; } else { let temp = this.head; while (temp != null) { process.stdout.write(String(temp.data)); process.stdout.write(" -> "); temp = temp.nextElement; } console.log("null"); return true; } } getHead() { return this.head; } setHead(newHead) { this.head = newHead; return this; } getListStr() { if (this.isEmpty()) { console.log("Empty List"); return "null"; } else { let st = ""; let temp = this.head while (temp != null) { st += String(temp.data); st += " -> "; temp = temp.nextElement; } st += "null"; return st; } } insertAtTail(newData) { //Creating a new Node with data as newData let node = new Node(newData); //check for case when list is empty if (this.isEmpty()) { //Needs to Insert the new node at Head this.head = node; return this; } //Start from head let currentNode = this.head; //Iterate to the last element while (currentNode.nextElement != null) { currentNode = currentNode.nextElement; } //Make new node the nextElement of last node of list currentNode.nextElement = node; return this; } search(value) { //Start from the first element let currentNode = this.head; //Traverse the list until you find the value or reach the end while (currentNode != null) { if (currentNode.data == value) { return true; //value found } currentNode = currentNode.nextElement } return false; //value not found } deleteAtHead() { //if list is empty, do nothing if (this.isEmpty()) { return this; } //Get the head and first element of the list let firstElement = this.head; //If list is not empty, link head to the nextElement of firstElement this.head = firstElement.nextElement; return this; } deleteVal(value) { let deleted = null; //True or False //Write code here //if list is empty return false if (this.isEmpty()) { return false; } //else get pointer to head let currentNode = this.head; // if first node's is the node to be deleted, delete it and return true if (currentNode.data == value) { this.head = currentNode.nextElement; return true; } // else traverse the list while (currentNode.nextElement != null) { // if a node whose next node has the value as data, is found, delete it from the list and return true if (currentNode.nextElement.data == value) { currentNode.nextElement = currentNode.nextElement.nextElement; return true; } currentNode = currentNode.nextElement; } //else node was not found, return false deleted = false; return deleted; } deleteAtTail() { // check for the case when linked list is empty if (this.isEmpty()) { return this; } //if linked list is not empty, get the pointer to first node let firstNode = this.head; //check for the corner case when linked list has only one element if (firstNode.nextElement == null) { this.deleteAtHead(); return this; } //otherwise traverse to reach second last node while (firstNode.nextElement.nextElement != null) { firstNode = firstNode.nextElement; } //since you have reached second last node, just update its nextElement pointer to point at null, skipping the last node firstNode.nextElement = null; return this; } } class Graph { constructor(vertices) { this.vertices = vertices this.list = [] let it for (it = 0; it < vertices; it++) { let temp = new LinkedList() this.list.push(temp) } } addEdge(source, destination) { if (source < this.vertices && destination < this.vertices) this.list[source].insertAtHead(destination) return this } printGraph() { console.log(">>Adjacency List of Directed Graph<<") let i for (i = 0; i < this.list.length; i++) { process.stdout.write("|" + String(i) + "| => ") let temp = this.list[i].getHead() while (temp != null) { process.stdout.write("[" + String(temp.data) + "] -> ") temp = temp.nextElement } console.log("null ") } } strGraph() { let str = "" let i for (i = 0; i < this.list.length; i++) { str = str + "|" + String(i) + "| => " let temp = this.list[i].getHead() while (temp != null) { str += ("[" + String(temp.data) + "] -> ") temp = temp.nextElement } str += "null " } return str } } removeEdge(graph, source, dest) => { if(graph.list.length == 0){ return graph } if(source >= graph.list.length || source < 0){ return graph } if(dest >= graph.list.length || dest < 0){ return graph } graph.list[source].deleteVal(dest) return graph } let g = new Graph(5) g.addEdge(0, 1) g.addEdge(0, 2) g.addEdge(1, 3) g.addEdge(2, 4) g.addEdge(4, 0) console.log("Before removing edge") g.printGraph() removeEdge(g, 1, 3) console.log("\nAfter removing edge") g.printGraph()
В этом решении мы используем индексацию и удаление. Надеюсь, вы проверили решение. Поскольку мы храним вершины графа в массиве, мы можем получить доступ к source
связанному списку. тогда вам просто нужно вызвать функцию delete
для связанных списков, чтобы удалить края. Временная сложность этой программы равна O (E), здесь E обозначает пройденные ребра.
Хеш-таблица
1. Преобразование максимальной кучи в минимальную кучу
Вам нужно написать программу, которая преобразует двоичную максимальную кучу в двоичную минимальную кучу.
Ввод: максимальное количество [9,4,7,1,-2,6,5]
Вывод: [-2,1,5,9,4,6,7]
minHeapify(heap, index) => { let left = index * 2 let right = (index * 2) + 1 let smallest = index if ((heap.length > left) && (heap[smallest] > heap[left])) { smallest = left } if ((heap.length > right) && (heap[smallest] > heap[right])) smallest = right if (smallest != index) { let tmp = heap[smallest] heap[smallest] = heap[index] heap[index] = tmp minHeapify(heap, smallest) } return heap } convertMax(maxHeap) => { for (let i = Math.floor((maxHeap.length) / 2); i > -1; i--) maxHeap = minHeapify(maxHeap, i) return maxHeap } let maxHeap = [9,4,7,1,-2,6,5] console.log(convertMax(maxHeap))
Здесь мы рассматриваем maxHeap
как массив и выполняем с ним операции хеширования массива. Вы можете увидеть это в приведенной выше программе. Таким образом, временная сложность этой программы составляет O (nlog (n)) O (nlog (n)).
Вот и все!
Вначале вы можете найти какую-то программу немного сложной, но как только вы узнаете логику, вы сможете легко ее написать. Также существует несколько решений одной и той же проблемы. Если вы найдете оптимальное решение, вы можете просто прокомментировать его ниже. Спасибо за чтение.
Если вам нравится эта статья, помогите мне купить кофе: https://www.buymeacoffee.com/harry1408