├── .DS_Store
├── modal
├── modal.js
├── modal.html
└── modal.css
├── accordion
├── index.js
├── index.css
└── index.html
├── star
├── style.css
├── index.html
└── main.js
├── clock
├── index.html
├── index.css
└── index.js
├── debounce
├── index.js
└── index.html
├── query-selector-all
└── index.js
├── throttle
├── throttle.js
└── index.html
├── function-chain
└── index.js
├── memoize
└── memoize.js
├── tic-tac-toe
├── index.css
├── index.html
└── index.js
├── data-structures
├── trie
│ └── trie.js
├── disjoint-set
│ └── unionFind.js
└── heap
│ ├── maxHeap.js
│ └── minHeap.js
├── carousel
├── index.html
├── index.js
└── index.css
├── custom-promise
└── index.js
├── popover
└── popover.html
└── README.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sivakumarsc/frontend-practice-questions/HEAD/.DS_Store
--------------------------------------------------------------------------------
/modal/modal.js:
--------------------------------------------------------------------------------
1 | function showModal() {
2 | let modal = document.getElementsByClassName('modal-wrapper')[0];
3 |
4 | modal.style.display = 'block';
5 | }
6 |
7 | function hideModal() {
8 | let modal = document.getElementsByClassName('modal-wrapper')[0];
9 |
10 | modal.style.display = 'none';
11 | }
--------------------------------------------------------------------------------
/accordion/index.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var wrapper = document.getElementsByClassName('accordion-wrapper')[0];
3 | console.log(wrapper)
4 |
5 | wrapper.addEventListener("click", function(e) {
6 | console.log('*************', e.target.parentElement);
7 | e.target.parentElement.classList.toggle('active');
8 | });
9 |
10 | })();
--------------------------------------------------------------------------------
/star/style.css:
--------------------------------------------------------------------------------
1 | rating-container * {
2 | padding: 0;
3 | margin: 0;
4 | }
5 |
6 | ul {
7 | list-style: none;
8 | display: flex;
9 | }
10 |
11 | ul li {
12 | font-size: 40px;
13 | color: grey;
14 | cursor: pointer;
15 | }
16 |
17 | ul li.active,
18 | ul li:hover {
19 | color: gold;
20 | transform: scale(1.2);
21 | }
22 |
--------------------------------------------------------------------------------
/clock/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
--------------------------------------------------------------------------------
/star/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Star Rating
9 |
10 |
11 | - ★
12 | - ★
13 | - ★
14 | - ★
15 | - ★
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/debounce/index.js:
--------------------------------------------------------------------------------
1 | window.addEventListener("load", function (){
2 | const textBox = document.getElementById("text-box");
3 | let timerId = null;
4 |
5 | function debounce(callback, delay) {
6 | if (timerId) {
7 | clearTimeout(timerId);
8 | }
9 |
10 | timerId = setTimeout(() => {
11 | callback(arguments[2])
12 | }, delay);
13 | }
14 |
15 | function printVal(e) {
16 | console.log('********************', e.target.value);
17 | }
18 |
19 | textBox.addEventListener("keypress", function(e){
20 | debounce(printVal, 200, e);
21 | });
22 |
23 |
24 | });
--------------------------------------------------------------------------------
/debounce/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/query-selector-all/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Implement document.querySelectorAll() in JS
3 | */
4 |
5 | document.prototype.myQuerySelectorAll = function(selector) {
6 | let result = [];
7 |
8 | // Selector will be compared as a regex
9 | function isMatch(node) {
10 | return node.matches(selector);
11 | }
12 |
13 | function traverse(node) {
14 | if (!node) {
15 | return;
16 | }
17 | if (isMatch(node)) {
18 | result.add(node);
19 | }
20 | for (let childNode of node.children) {
21 | traverse(childNode);
22 | }
23 | }
24 |
25 | // To travserse from root HTML element
26 | traverse(this.documentElement);
27 |
28 | return result;
29 | }
--------------------------------------------------------------------------------
/modal/modal.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
22 |
23 |
--------------------------------------------------------------------------------
/throttle/throttle.js:
--------------------------------------------------------------------------------
1 | window.addEventListener("load", function() {
2 | const wrapper = document.getElementsByClassName('wrapper')[0];
3 | let timerId = null;
4 |
5 | function throttle(callback, delay) {
6 | if (timerId) {
7 | return;
8 | }
9 |
10 | timerId = setTimeout(function() {
11 | callback();
12 |
13 | clearTimeout(timerId);
14 | // After clearTimeout also, we will have timerId. So, explicitly making it as null.
15 | timerId = null;
16 | }, delay);
17 | }
18 |
19 | function handleScroll() {
20 | console.log('*****************************');
21 | }
22 |
23 |
24 | wrapper.addEventListener("scroll", function() {
25 | throttle(handleScroll, 500);
26 | });
27 | });
--------------------------------------------------------------------------------
/accordion/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | padding: 0;
3 | margin: 0;
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: pink;
9 | }
10 |
11 | .accordion-wrapper {
12 | margin: 50px auto;
13 | width: 500px;
14 | }
15 |
16 | .accordion {
17 | border: 1px solid #000;
18 | border-radius: 4px;
19 | background: #fff;
20 | padding: 10px;
21 | margin: 10px;
22 | }
23 |
24 | .accordion.active .accordion-body {
25 | max-height: 100px;
26 | overflow: auto;
27 | }
28 |
29 | .accordion-title {
30 | border-bottom: 1px solid #000;
31 | cursor: pointer;
32 | }
33 |
34 | .accordion-body {
35 | max-height: 0;
36 | overflow: hidden;
37 | transition: max-height 0.5s ease-out;
38 | }
39 |
40 | .content {
41 | padding: 10px;
42 | }
--------------------------------------------------------------------------------
/function-chain/index.js:
--------------------------------------------------------------------------------
1 | `
2 | Implement a function chain like below snippet
3 | const developer = new DeveloperBuilder('John')
4 | .addSkill('ES6')
5 | .addSkill('TypeScript')
6 | .setFramework('React');
7 | `
8 |
9 | class DeveloperBuilder {
10 | constructor(name) {
11 | this.name = name;
12 | this.skills = [];
13 | this.framework = null;
14 | }
15 |
16 | addSkill(skill) {
17 | this.skills.push(skill);
18 |
19 | return this;
20 | }
21 |
22 | setFramework(framework) {
23 | this.framework = framework;
24 |
25 | return this;
26 | }
27 | }
28 |
29 | const developer = new DeveloperBuilder('John')
30 | .addSkill('ES6')
31 | .addSkill('TypeScript')
32 | .setFramework('React');
33 |
34 | console.log(developer);
--------------------------------------------------------------------------------
/memoize/memoize.js:
--------------------------------------------------------------------------------
1 | function multiplyBy2(x) {
2 | return x * 2;
3 | }
4 |
5 | function memoize(func) {
6 | let map = new Map();
7 |
8 | return function(x) {
9 | if (map.has(x)) {
10 | return `Returned from memory ${map.get(x)}`;
11 | }
12 |
13 | let result = func(x);
14 | map.set(x, result);
15 |
16 | return `Returned from function ${result}`;
17 | }
18 | }
19 |
20 | let wrapper = memoize(multiplyBy2);
21 | console.log(wrapper(2)); // Returned from function 4
22 | console.log(wrapper(4)); // Returned from function 8
23 | console.log(wrapper(5)); // Returned from function 10
24 | console.log(wrapper(2)); // Returned from memory 4
25 | console.log(wrapper(2)); // Returned from memory 4
26 | console.log(wrapper(6)); // Returned from function 12
--------------------------------------------------------------------------------
/throttle/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/tic-tac-toe/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | padding: 0;
4 | margin: 0;
5 | }
6 |
7 | body {
8 | background-color: beige;
9 | }
10 |
11 | .container {
12 | display: flex;
13 | justify-content: center;
14 | align-items: center;
15 | }
16 |
17 | .board {
18 | width: 300px;
19 | display: grid;
20 | grid-template-columns: repeat(3, auto);
21 | }
22 |
23 | .cell {
24 | width: 100px;
25 | height: 100px;
26 | font-size: 20px;
27 | text-align: center;
28 | background-color: #fff;
29 | border: 1px solid #000;
30 | cursor: pointer;
31 | }
32 |
33 | .game-result {
34 | text-align: center;
35 | display: none;
36 | font-size: 18px;
37 | }
38 |
39 | .restart-game {
40 | padding: 20px;
41 | margin: 10px;
42 | background: #fff;
43 | cursor: pointer;
44 | font-size: 14px;
45 | }
--------------------------------------------------------------------------------
/clock/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | padding: 0;
3 | margin: 0;
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: powderblue;
9 | }
10 |
11 | .container {
12 | width: 70%;
13 | margin: 0 auto;
14 | }
15 |
16 | .clock .outer-circle {
17 | border: 5px solid #000;
18 | border-radius: 50%;
19 | width: 200px;
20 | height: 200px;
21 | margin: 100px auto;
22 | position: relative;
23 | }
24 |
25 | .numbers {
26 | position: absolute;
27 | left: 50%;
28 | top: 50%;
29 | height: 100%;
30 | width: 10px;
31 | }
32 |
33 | .hand {
34 | position: absolute;
35 | transform: translateX(-50%) rotate(90deg);
36 | background-color: #000;
37 | bottom: 50%;
38 | left: 50%;
39 | transform-origin: bottom;
40 | }
41 |
42 | .second {
43 | width: 2px;
44 | height: 40%;
45 | }
46 |
47 | .minute {
48 | width: 4px;
49 | height: 40%;
50 | }
51 |
52 | .hour {
53 | width: 6px;
54 | height: 30%;
55 | }
--------------------------------------------------------------------------------
/tic-tac-toe/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/modal/modal.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | padding: 0;
4 | margin: 0;
5 | }
6 |
7 | body {
8 | background-color: aquamarine;
9 | }
10 |
11 | .wrapper {
12 | height: 100%;
13 | display: flex;
14 | justify-content: center;
15 | align-items: center;
16 | }
17 |
18 | .wrapper button {
19 | border-radius: 4px;
20 | padding: 8px;
21 | text-align: center;
22 | background-color: #fff;
23 | color: #000;
24 | cursor: pointer;
25 | }
26 |
27 | .modal-wrapper {
28 | position: fixed;
29 | top: 0;
30 | left: 0;
31 | width: 100%;
32 | height: 100%;
33 | background-color: rgba(0, 0, 0, 0.4);
34 | padding-top: 100px;
35 | display: none;
36 | }
37 |
38 | .modal {
39 | background: #fff;
40 | width: 500px;
41 | height: 300px;
42 | margin: auto;
43 | }
44 |
45 | .modal-header {
46 | padding: 20px;
47 | text-align: center;
48 | position: relative;
49 | }
50 |
51 | .close {
52 | position: absolute;
53 | top: -30px;
54 | right: -30px;
55 | font-size: 40px;
56 | cursor: pointer;
57 | }
--------------------------------------------------------------------------------
/data-structures/trie/trie.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Implement trie-prefix tree
3 | * https://leetcode.com/problems/implement-trie-prefix-tree/solution/
4 | */
5 |
6 | class TrieNode {
7 | constructor() {
8 | this.edges = new Map();
9 | this.isWordEnd = false;
10 | }
11 | }
12 |
13 | class Trie {
14 | constructor() {
15 | this.root = new TrieNode();
16 | }
17 |
18 | insert(word) {
19 | let node = this.root;
20 | for(let w of word) {
21 | if (!node.edges.has(w)) {
22 | node.edges.set(w, new TrieNode());
23 | }
24 | node = node.edges.get(w);
25 | }
26 | node.isWordEnd = true;
27 | }
28 |
29 | traverse(word) {
30 | let node = this.root;
31 | for(let w of word) {
32 | if (!node.edges.has(w)) {
33 | return null;
34 | }
35 | node = node.edges.get(w);
36 | }
37 | return node;
38 | }
39 |
40 | search(word) {
41 | let node = this.traverse(word);
42 | return node !== null && node.isWordEnd;
43 | }
44 |
45 | startsWith(word) {
46 | let node = this.traverse(word);
47 | return node !== null;
48 | }
49 | }
--------------------------------------------------------------------------------
/carousel/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 | -
21 |
22 |
23 | -
24 |
25 |
26 | -
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/carousel/index.js:
--------------------------------------------------------------------------------
1 | window.addEventListener("load", function() {
2 | console.log('****** loaded ****');
3 |
4 | let currentIndex = 0;
5 | const prevButton = document.getElementsByClassName('prev')[0];
6 | const nextButton = document.getElementsByClassName('next')[0];
7 | const carouselWrapper = document.getElementsByClassName('carousel-item-wrapper')[0];
8 | const totalItems = carouselWrapper.children.length;
9 | const percent = 100/totalItems;
10 | console.log(totalItems);
11 |
12 | function handlePrevClick() {
13 | slideTo(currentIndex - 1);
14 | }
15 |
16 | function handleNextClick() {
17 | slideTo(currentIndex + 1);
18 | }
19 |
20 | function slideTo(index) {
21 | let slideIndex = index;
22 |
23 | if (index < 0) {
24 | slideIndex = totalItems - 1;
25 | } else if(index >= carouselWrapper.children.length) {
26 | slideIndex = 0;
27 | }
28 | carouselWrapper.style.transform = `translate(-${slideIndex*percent}%, 0)`;
29 | currentIndex = slideIndex;
30 | }
31 |
32 | prevButton.addEventListener("click", handlePrevClick);
33 | nextButton.addEventListener("click", handleNextClick);
34 |
35 | });
--------------------------------------------------------------------------------
/carousel/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | padding: 0;
3 | margin: 0;
4 | box-sizing: border-box;
5 | }
6 |
7 | .carousel-section {
8 | width: 70%;
9 | margin: 0 auto;
10 | }
11 |
12 | .carousel-wrapper {
13 | width: 100%;
14 | position: relative;
15 | overflow: hidden;
16 | }
17 |
18 | .carousel {
19 | width: 500%;
20 | }
21 |
22 | .carousel-item-wrapper {
23 | transition: all 800ms;
24 | }
25 |
26 | .carousel-item {
27 | width: 20%;
28 | float: left;
29 | list-style: none;
30 | }
31 | .carousel-item .item {
32 | width: 100%;
33 | height: 500px;
34 | }
35 |
36 | .item1 {
37 | background-color: red;
38 | }
39 |
40 | .item2 {
41 | background-color: black;
42 | }
43 |
44 | .item3 {
45 | background-color: green;
46 | }
47 |
48 | .item4 {
49 | background-color: orange;
50 | }
51 |
52 | .item5 {
53 | background-color: blue;
54 | }
55 |
56 | .action-btn {
57 | position: absolute;
58 | top: 50%;
59 | padding: 20px;
60 | background-color: pink;
61 | cursor: pointer;
62 | z-index: 1;
63 | border: 0;
64 | transform: translateY(-50%);
65 | font-size: 20px;
66 | }
67 |
68 | .prev {
69 | left: 0;
70 | }
71 |
72 | .next {
73 | right: 0;
74 | }
--------------------------------------------------------------------------------
/data-structures/disjoint-set/unionFind.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A QuickFind Implementation
3 | *
4 | * Time Complexity:
5 | * find - O(1)
6 | * union - O(n)
7 | * completed - O(1)
8 | */
9 |
10 | class UnionFind {
11 | constructor(size) {
12 | this.root = Array.from({ length: size }, (_, i) => i);
13 | }
14 |
15 | find(x) {
16 | return this.root[x];
17 | }
18 |
19 | union(x, y) {
20 | let rootX = this.find(x);
21 | let rootY = this.find(y);
22 |
23 | if (rootX !== rootY) {
24 | for(let i=0; i
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Accordion 1
13 | Hello
14 |
15 |
16 | Accordion 2
17 | Hello 2
18 |
19 |
20 |
21 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/star/main.js:
--------------------------------------------------------------------------------
1 | window.addEventListener("load", function() {
2 | const stars = document.getElementsByTagName("li");
3 | const starContainer = document.getElementsByClassName("rating-container")[0];
4 | let active = -1;
5 |
6 | starContainer.addEventListener("click", function(el) {
7 | if (el.target.dataset.id) {
8 | let currentIndex = el.target.dataset.id;
9 | active = currentIndex - 1;
10 |
11 | for(let i=0; i {};
5 |
6 | this.onResolve = this.onResolve.bind(this);
7 | this.onReject = this.onReject.bind(this);
8 |
9 | callback(this.onResolve, this.onReject);
10 | }
11 |
12 | then(onResolve) {
13 | this.promiseChain.push(onResolve);
14 |
15 | return this;
16 | }
17 |
18 | catch(error) {
19 | this.handleError = error;
20 |
21 | return this;
22 | }
23 |
24 | onResolve(value) {
25 | let previousValue = value;
26 | try {
27 | this.promiseChain.forEach(nextFunction => {
28 | previousValue = nextFunction(previousValue);
29 | });
30 | } catch(e) {
31 | this.onReject(e);
32 | }
33 | }
34 |
35 | onReject(error) {
36 | this.handleError(error);
37 | }
38 | }
39 |
40 | function fakePromise() {
41 | return new CustomPromise((resolve, reject) => {
42 | setTimeout(() => {
43 | const sample = Math.round((Math.random() * 2));
44 | if (sample % 2 === 0) {
45 | resolve(sample);
46 | } else {
47 | reject(sample);
48 | }
49 | }, 1000);
50 | });
51 | }
52 |
53 | fakePromise().then((res) => {
54 | console.log(`Response 1 ${res}`);
55 | return res;
56 | }).then((res) => {
57 | console.log(`Response 2 ${res}`);
58 | }).catch((err) => {
59 | console.log(`Error ${err}`);
60 | });
--------------------------------------------------------------------------------
/popover/popover.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
I am a pop over title
53 |
I am a pop over content
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/clock/index.js:
--------------------------------------------------------------------------------
1 | window.addEventListener("load", function() {
2 | let circle = document.getElementsByClassName('outer-circle')[0];
3 |
4 | function createNumbers() {
5 | let fragment = document.createDocumentFragment();
6 | let deg = 0;
7 | for(let i=0; i<12; i+=1) {
8 | let div = document.createElement('div');
9 | div.classList.add('numbers');
10 | deg += 30;
11 | div.style.transform = `translate(-50%, -50%)rotate(${deg}deg)`;
12 |
13 | let num = document.createElement('div');
14 | num.textContent = i + 1;
15 | num.style.transform = `rotate(-${deg}deg)`;
16 | div.appendChild(num);
17 | fragment.appendChild(div);
18 | }
19 | circle.appendChild(fragment);
20 | }
21 |
22 | function drawHands(handType) {
23 | let hand = document.createElement('div');
24 | hand.classList.add('hand', handType);
25 | circle.appendChild(hand);
26 | }
27 |
28 | function setCurrentTime() {
29 | let date = new Date();
30 | let sec = date.getSeconds() / 60;
31 | let min = (date.getMinutes() + sec) / 60;
32 | let hour = (date.getHours() + min) / 12;
33 |
34 | let hourHand = document.getElementsByClassName('hour')[0];
35 | let minuteHand = document.getElementsByClassName('minute')[0];
36 | let secondHand = document.getElementsByClassName('second')[0];
37 |
38 | console.log(hour, min, sec);
39 |
40 | hourHand.style.transform = "rotate(" + (hour * 360) + "deg)";
41 | minuteHand.style.transform = "rotate(" + (min * 360) + "deg)";
42 | secondHand.style.transform = "rotate(" + (sec * 360) + "deg)";
43 | }
44 |
45 | createNumbers();
46 | drawHands('second');
47 | drawHands('minute');
48 | drawHands('hour');
49 | setCurrentTime();
50 | setInterval(setCurrentTime, 1000);
51 | });
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # frontend-practice-questions
2 | Created this repo for practicing some common frontend interview questions. The answers given are **functional but may not follow best practices.**
3 |
4 | ## Common Interview Questions
5 |
6 | * [Accordion](https://github.com/scsiva1991/frontend-practice-questions/tree/master/accordion)
7 | * [Carousel](https://github.com/scsiva1991/frontend-practice-questions/tree/master/carousel)
8 | * [Analog clock](https://github.com/scsiva1991/frontend-practice-questions/tree/master/clock)
9 | * [Memoize](https://github.com/scsiva1991/frontend-practice-questions/tree/master/memoize)
10 | * [Popover](https://github.com/scsiva1991/frontend-practice-questions/tree/master/popover)
11 | * [Star Rating](https://github.com/scsiva1991/frontend-practice-questions/tree/master/star)
12 | * [Debounce](https://github.com/scsiva1991/frontend-practice-questions/tree/master/debounce)
13 | * [Throtlle](https://github.com/scsiva1991/frontend-practice-questions/tree/master/throttle)
14 | * [Custom Promise](https://github.com/scsiva1991/frontend-practice-questions/tree/master/custom-promise)
15 | * [Modal](https://github.com/scsiva1991/frontend-practice-questions/tree/master/modal)
16 | * [Tic-Tac-Toe](https://github.com/scsiva1991/frontend-practice-questions/tree/master/tic-tac-toe)
17 | * [Function chaining](https://github.com/scsiva1991/frontend-practice-questions/tree/master/function-chain)
18 | * [Implement querySelector All](https://github.com/scsiva1991/frontend-practice-questions/tree/master/query-selector-all)
19 |
20 | ## Data Structures
21 |
22 | * [Trie](https://github.com/scsiva1991/frontend-practice-questions/tree/master/data-structures/trie)
23 | * [Heap](https://github.com/scsiva1991/frontend-practice-questions/tree/master/data-structures/heap)
24 | * [Disjoint Set](https://github.com/scsiva1991/frontend-practice-questions/tree/master/data-structures/disjoint-set)
--------------------------------------------------------------------------------
/data-structures/heap/maxHeap.js:
--------------------------------------------------------------------------------
1 | /**
2 | * MaxHeap Implementation
3 | *
4 | * Time Complexity
5 | * Insertion - O(log n)
6 | * Deletion - O(log n)
7 | * To get min value - O(1)
8 | */
9 | class MaxHeap {
10 | constructor(heapSize) {
11 | this.maxHeapSize = heapSize;
12 | this.maxHeap = Array.from({ length: heapSize + 1}, () => 0);
13 | this.currentSize = 0;
14 | }
15 |
16 | add(num) {
17 | this.currentSize += 1;
18 |
19 | if (this.currentSize > this.maxHeapSize) {
20 | this.currentSize -= 1;
21 | throw new Error("Heap size exceeds!!");
22 | }
23 |
24 | this.maxHeap[this.currentSize] = num;
25 | let index = this.currentSize;
26 | let parentIndex = Math.floor(index / 2);
27 |
28 | while(index > 1 && this.maxHeap[index] > this.maxHeap[parentIndex]) {
29 | [this.maxHeap[index], this.maxHeap[parentIndex]] = [this.maxHeap[parentIndex], this.maxHeap[index]];
30 | index = parentIndex;
31 | parentIndex = Math.floor(index / 2);
32 | }
33 | }
34 |
35 | peek() {
36 | return this.maxHeap[1];
37 | }
38 |
39 | pop() {
40 | if (this.currentSize < 1) {
41 | throw new Error("Heap is empty");
42 | }
43 | let itemToBeRemoved = this.maxHeap[1];
44 | this.maxHeap[1] = this.maxHeap[this.currentSize];
45 | this.currentSize -= 1;
46 | let index = 1;
47 |
48 | while (index < this.currentSize && index <= Math.floor(this.currentSize/2)) {
49 | let left = index * 2, right = index * 2 + 1;
50 | if (this.maxHeap[index] < this.maxHeap[left] || this.maxHeap[index] < this.maxHeap[right]) {
51 | if (this.maxHeap[left] > this.maxHeap[right]) {
52 | [this.maxHeap[index], this.maxHeap[left]] = [this.maxHeap[left], this.maxHeap[index]];
53 | index = left;
54 | } else {
55 | [this.maxHeap[index], this.maxHeap[right]] = [this.maxHeap[right], this.maxHeap[index]];
56 | index = right;
57 | }
58 | } else {
59 | break;
60 | }
61 | }
62 |
63 | return itemToBeRemoved;
64 | }
65 |
66 | size() {
67 | return this.currentSize;
68 | }
69 | }
70 |
71 | // test case
72 | let maxHeap = new MaxHeap(5);
73 | maxHeap.add(3);
74 | maxHeap.add(1);
75 | maxHeap.add(2);
76 | console.log(maxHeap.peek()); // 3
77 | console.log(maxHeap.pop()); // 3
78 | console.log(maxHeap.pop()); // 2
79 | console.log(maxHeap.pop()); // 1
80 | maxHeap.add(5);
81 | maxHeap.add(4);
82 | console.log(maxHeap.peek()); // 5
--------------------------------------------------------------------------------
/data-structures/heap/minHeap.js:
--------------------------------------------------------------------------------
1 | /**
2 | * MinHeap Implementation
3 | *
4 | * Time Complexity
5 | * Insertion - O(log n)
6 | * Deletion - O(log n)
7 | * To get min value - O(1)
8 | */
9 | class MinHeap {
10 | constructor(heapSize) {
11 | this.minHeapSize = heapSize;
12 | this.minHeap = Array.from({length: heapSize + 1}, () => 0);
13 | this.currentSize = 0;
14 | }
15 |
16 | add(num) {
17 | this.currentSize += 1;
18 |
19 | if (this.currentSize > this.minHeapSize) {
20 | this.currentSize -= 1;
21 | throw new Error("Heap size exceeds!!");
22 | }
23 |
24 | this.minHeap[this.currentSize] = num;
25 |
26 | let index = this.currentSize;
27 | let parentIndex = Math.floor(index/2);
28 |
29 | while(index > 1 && this.minHeap[index] < this.minHeap[parentIndex]) {
30 | [this.minHeap[index], this.minHeap[parentIndex]] = [this.minHeap[parentIndex], this.minHeap[index]];
31 | index = parentIndex;
32 | parentIndex = Math.floor(index/2);
33 | }
34 | }
35 |
36 | peek() {
37 | return this.minHeap[1];
38 | }
39 |
40 | pop() {
41 | if (this.currentSize < 1) {
42 | throw new Error("Heap is empty");
43 | }
44 |
45 | let itemToBeRemoved = this.minHeap[1];
46 | this.minHeap[1] = this.minHeap[this.currentSize];
47 | this.currentSize -= 1;
48 | let index = 1;
49 |
50 | while(index < this.currentSize && index <= Math.floor(this.currentSize/2)) {
51 | let left = index * 2, right = index * 2 + 1;
52 | if (this.minHeap[index] > this.minHeap[left] || this.minHeap[index] > this.minHeap[right]) {
53 | if (this.minHeap[left] < this.minHeap[right]) {
54 | [this.minHeap[index], this.minHeap[left]] = [this.minHeap[left], this.minHeap[index]];
55 | index = left;
56 | } else {
57 | [this.minHeap[index], this.minHeap[right]] = [this.minHeap[right], this.minHeap[index]];
58 | index = right;
59 | }
60 | } else {
61 | break;
62 | }
63 | }
64 |
65 | return itemToBeRemoved;
66 | }
67 |
68 | size() {
69 | return this.currentSize;
70 | }
71 | }
72 |
73 | // test case
74 | let minHeap = new MinHeap(5);
75 | minHeap.add(3);
76 | minHeap.add(1);
77 | minHeap.add(2);
78 | console.log(minHeap.peek()); // 1
79 | console.log(minHeap.pop()); // 1
80 | console.log(minHeap.pop()); // 2
81 | console.log(minHeap.pop()); // 3
82 | minHeap.add(5);
83 | minHeap.add(4);
84 | console.log(minHeap.peek()); // 4
--------------------------------------------------------------------------------
/tic-tac-toe/index.js:
--------------------------------------------------------------------------------
1 | window.addEventListener("load", function() {
2 | let currentPlayer = 'X';
3 | let gameScores = [];
4 | let board = document.getElementsByClassName('board')[0];
5 | let gameResult = document.getElementsByClassName('game-result')[0];
6 | let gameStatus = document.getElementsByClassName('status')[0];
7 | let restartBtn = document.getElementsByClassName('restart-game')[0];
8 |
9 | function initGame() {
10 | currentPlayer = 'X';
11 | gameScores = new Array(9).fill('');
12 | gameResult.style.display = 'none';
13 | document.querySelectorAll('.cell').forEach(cell => cell.innerHTML = "");
14 | }
15 |
16 | function updateGameStatus(isWon) {
17 | if (isWon) {
18 | gameStatus.innerHTML = `Congrats!!. ${currentPlayer} won the game.`
19 | } else {
20 | gameStatus.innerHTML = 'Math drawn.'
21 | }
22 |
23 | gameResult.style.display = 'block';
24 | }
25 |
26 | function updateCurrentPlayer() {
27 | currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
28 | }
29 |
30 | function checkGameStatus() {
31 | let validMoves = [
32 | [0, 1, 2],
33 | [3, 4, 5],
34 | [6, 7, 8],
35 | [0, 3, 6],
36 | [1, 4, 7],
37 | [2, 5, 8],
38 | [0, 4, 8],
39 | [2, 4, 6],
40 | ];
41 |
42 | let isWon = false;
43 |
44 | for(let i=0; i<=7; i+=1) {
45 | let [a, b, c] = validMoves[i];
46 |
47 | if (gameScores[a] && gameScores[b] && gameScores[c] &&
48 | gameScores[a] === gameScores[b] && gameScores[b] === gameScores[c]) {
49 | updateGameStatus(true);
50 | isWon = true;
51 | break;
52 | }
53 | }
54 |
55 | if (!isWon) {
56 | console.log(gameScores)
57 | let isMoveExists = gameScores.find(score => score === '');
58 |
59 | console.log(isMoveExists)
60 | if (isMoveExists === undefined) {
61 | updateGameStatus(false);
62 | return;
63 | }
64 | }
65 |
66 | updateCurrentPlayer();
67 | }
68 |
69 | function handleClick(cell) {
70 | const index = cell.getAttribute("data-index");
71 |
72 | if (gameScores[index] !== '') {
73 | return;
74 | }
75 |
76 | cell.innerHTML = currentPlayer;
77 | gameScores[index] = currentPlayer;
78 |
79 | checkGameStatus();
80 |
81 |
82 | }
83 |
84 | board.addEventListener("click", function(e) {
85 | handleClick(e.target);
86 | });
87 |
88 | restartBtn.addEventListener("click", function() {
89 | initGame();
90 | });
91 |
92 | initGame();
93 | });
--------------------------------------------------------------------------------