JavaScript 面試中常見演算法問題詳解
JavaScript Specification
闡述下 JavaScript 中的變數提升
所謂提升,顧名思義即是 JavaScript 會將所有的宣告提升到當前作用域的頂部。這也就意味著我們可以在某個變數宣告前就使用該變數,不過雖然 JavaScript 會將宣告提升到頂部,但是並不會執行真的初始化過程。
闡述下 use strict;
的作用
use strict;
顧名思義也就是 JavaScript 會在所謂嚴格模式下執行,其一個主要的優勢在於能夠強制開發者避免使用未宣告的變數。對於老版本的瀏覽器或者執行引擎則會自動忽略該指令。
// Example of strict mode "use strict"; catchThemAll(); function catchThemAll() { x = 3.14; // Error will be thrown return x * x; }
解釋下什麼是 Event Bubbling 以及如何避免
Event Bubbling 即指某個事件不僅會觸發當前元素,還會以巢狀順序傳遞到父元素中。直觀而言就是對於某個子元素的點選事件同樣會被父元素的點選事件處理器捕獲。避免 Event Bubbling 的方式可以使用event.stopPropagation()
或者 IE 9 以下使用event.cancelBubble
。
== 與 === 的區別是什麼
===
也就是所謂的嚴格比較,關鍵的區別在於===
會同時比較型別與值,而不是僅比較值。
// Example of comparators 0 == false; // true 0 === false; // false 2 == '2'; // true 2 === '2'; // false
解釋下 null 與 undefined 的區別
JavaScript 中,null 是一個可以被分配的值,設定為 null 的變數意味著其無值。而 undefined 則代表著某個變數雖然宣告瞭但是尚未進行過任何賦值。
解釋下 Prototypal Inheritance 與 Classical Inheritance 的區別
在類繼承中,類是不可變的,不同的語言中對於多繼承的支援也不一樣,有些語言中還支援介面、final、abstract 的概念。而原型繼承則更為靈活,原型本身是可以可變的,並且物件可能繼承自多個原型。
陣列
找出整型陣列中乘積最大的三個數
給定一個包含整數的無序陣列,要求找出乘積最大的三個數。
var unsorted_array = [-10, 7, 29, 30, 5, -10, -70]; computeProduct(unsorted_array); // 21000 function sortIntegers(a, b) { return a - b; } // greatest product is either (min1 * min2 * max1 || max1 * max2 * max3) function computeProduct(unsorted) { var sorted_array = unsorted.sort(sortIntegers), product1 = 1, product2 = 1, array_n_element = sorted_array.length - 1; // Get the product of three largest integers in sorted array for (var x = array_n_element; x > array_n_element - 3; x--) { product1 = product1 * sorted_array[x]; } product2 = sorted_array[0] * sorted_array[1] * sorted_array[array_n_element]; if (product1 > product2) return product1; return product2 };
尋找連續陣列中的缺失數
給定某無序陣列,其包含了 n 個連續數字中的 n – 1 個,已知上下邊界,要求以O(n)
的複雜度找出缺失的數字。
// The output of the function should be 8 var array_of_integers = [2, 5, 1, 4, 9, 6, 3, 7]; var upper_bound = 9; var lower_bound = 1; findMissingNumber(array_of_integers, upper_bound, lower_bound); //8 function findMissingNumber(array_of_integers, upper_bound, lower_bound) { // Iterate through array to find the sum of the numbers var sum_of_integers = 0; for (var i = 0; i < array_of_integers.length; i++) { sum_of_integers += array_of_integers[i]; } // 以高斯求和公式計算理論上的陣列和 // Formula: [(N * (N + 1)) / 2] - [(M * (M - 1)) / 2]; // N is the upper bound and M is the lower bound upper_limit_sum = (upper_bound * (upper_bound + 1)) / 2; lower_limit_sum = (lower_bound * (lower_bound - 1)) / 2; theoretical_sum = upper_limit_sum - lower_limit_sum; // return (theoretical_sum - sum_of_integers) }
陣列去重
給定某無序陣列,要求去除陣列中的重複數字並且返回新的無重複陣列。
// ES6 Implementation var array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8]; Array.from(new Set(array)); // [1, 2, 3, 5, 9, 8] // ES5 Implementation var array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8]; uniqueArray(array); // [1, 2, 3, 5, 9, 8] function uniqueArray(array) { var hashmap = {}; var unique = []; for(var i = 0; i < array.length; i++) { // If key returns null (unique), it is evaluated as false. if(!hashmap.hasOwnProperty([array[i]])) { hashmap[array[i]] = 1; unique.push(array[i]); } } return unique; }
陣列中元素最大差值計算
給定某無序陣列,求取任意兩個元素之間的最大差值,注意,這裡要求差值計算中較小的元素下標必須小於較大元素的下標。譬如[7, 8, 4, 9, 9, 15, 3, 1, 10]
這個陣列的計算值是 11( 15 – 4 ) 而不是 14(15 – 1),因為 15 的下標小於 1。
var array = [7, 8, 4, 9, 9, 15, 3, 1, 10]; // [7, 8, 4, 9, 9, 15, 3, 1, 10] would return `11` based on the difference between `4` and `15` // Notice: It is not `14` from the difference between `15` and `1` because 15 comes before 1. findLargestDifference(array); function findLargestDifference(array) { // 如果陣列僅有一個元素,則直接返回 -1 if (array.length <= 1) return -1; // current_min 指向當前的最小值 var current_min = array[0]; var current_max_difference = 0; // 遍歷整個陣列以求取當前最大差值,如果發現某個最大差值,則將新的值覆蓋 current_max_difference // 同時也會追蹤當前陣列中的最小值,從而保證 `largest value in future` - `smallest value before it` for (var i = 1; i < array.length; i++) { if (array[i] > current_min && (array[i] - current_min > current_max_difference)) { current_max_difference = array[i] - current_min; } else if (array[i] <= current_min) { current_min = array[i]; } } // If negative or 0, there is no largest difference if (current_max_difference <= 0) return -1; return current_max_difference; }
陣列中元素乘積
給定某無序陣列,要求返回新陣列 output ,其中 output[i] 為原陣列中除了下標為 i 的元素之外的元素乘積,要求以 O(n) 複雜度實現:
var firstArray = [2, 2, 4, 1]; var secondArray = [0, 0, 0, 2]; var thirdArray = [-2, -2, -3, 2]; productExceptSelf(firstArray); // [8, 8, 4, 16] productExceptSelf(secondArray); // [0, 0, 0, 0] productExceptSelf(thirdArray); // [12, 12, 8, -12] function productExceptSelf(numArray) { var product = 1; var size = numArray.length; var output = []; // From first array: [1, 2, 4, 16] // The last number in this case is already in the right spot (allows for us) // to just multiply by 1 in the next step. // This step essentially gets the product to the left of the index at index + 1 for (var x = 0; x < size; x++) { output.push(product); product = product * numArray[x]; } // From the back, we multiply the current output element (which represents the product // on the left of the index, and multiplies it by the product on the right of the element) var product = 1; for (var i = size - 1; i > -1; i--) { output[i] = output[i] * product; product = product * numArray[i]; } return output; }
陣列交集
給定兩個陣列,要求求出兩個陣列的交集,注意,交集中的元素應該是唯一的。
var firstArray = [2, 2, 4, 1]; var secondArray = [1, 2, 0, 2]; intersection(firstArray, secondArray); // [2, 1] function intersection(firstArray, secondArray) { // The logic here is to create a hashmap with the elements of the firstArray as the keys. // After that, you can use the hashmap's O(1) look up time to check if the element exists in the hash // If it does exist, add that element to the new array. var hashmap = {}; var intersectionArray = []; firstArray.forEach(function(element) { hashmap[element] = 1; }); // Since we only want to push unique elements in our case... we can implement a counter to keep track of what we already added secondArray.forEach(function(element) { if (hashmap[element] === 1) { intersectionArray.push(element); hashmap[element]++; } }); return intersectionArray; // Time complexity O(n), Space complexity O(n) }
字串
顛倒字串
給定某個字串,要求將其中單詞倒轉之後然後輸出,譬如”Welcome to this Javascript Guide!” 應該輸出為 “emocleW ot siht tpircsavaJ !ediuG”。
var string = "Welcome to this Javascript Guide!"; // Output becomes !ediuG tpircsavaJ siht ot emocleW var reverseEntireSentence = reverseBySeparator(string, ""); // Output becomes emocleW ot siht tpircsavaJ !ediuG var reverseEachWord = reverseBySeparator(reverseEntireSentence, " "); function reverseBySeparator(string, separator) { return string.split(separator).reverse().join(separator); }
亂序同字母字串
給定兩個字串,判斷是否顛倒字母而成的字串,譬如Mary
與Army
就是同字母而順序顛倒:
var firstWord = "Mary"; var secondWord = "Army"; isAnagram(firstWord, secondWord); // true function isAnagram(first, second) { // For case insensitivity, change both words to lowercase. var a = first.toLowerCase(); var b = second.toLowerCase(); // Sort the strings, and join the resulting array to a string. Compare the results a = a.split("").sort().join(""); b = b.split("").sort().join(""); return a === b; }
會問字串
判斷某個字串是否為迴文字串,譬如racecar
與race car
都是迴文字串:
isPalindrome("racecar"); // true isPalindrome("race Car"); // true function isPalindrome(word) { // Replace all non-letter chars with "" and change to lowercase var lettersOnly = word.toLowerCase().replace(/\s/g, ""); // Compare the string with the reversed version of the string return lettersOnly === lettersOnly.split("").reverse().join(""); }
棧與佇列
使用兩個棧實現入隊與出隊
var inputStack = []; // First stack var outputStack = []; // Second stack // For enqueue, just push the item into the first stack function enqueue(stackInput, item) { return stackInput.push(item); } function dequeue(stackInput, stackOutput) { // Reverse the stack such that the first element of the output stack is the // last element of the input stack. After that, pop the top of the output to // get the first element that was ever pushed into the input stack if (stackOutput.length <= 0) { while(stackInput.length > 0) { var elementToOutput = stackInput.pop(); stackOutput.push(elementToOutput); } } return stackOutput.pop(); }
判斷大括號是否閉合
建立一個函式來判斷給定的表示式中的大括號是否閉合:
var expression = "{{}}{}{}" var expressionFalse = "{}{{}"; isBalanced(expression); // true isBalanced(expressionFalse); // false isBalanced(""); // true function isBalanced(expression) { var checkString = expression; var stack = []; // If empty, parentheses are technically balanced if (checkString.length <= 0) return true; for (var i = 0; i < checkString.length; i++) { if(checkString[i] === '{') { stack.push(checkString[i]); } else if (checkString[i] === '}') { // Pop on an empty array is undefined if (stack.length > 0) { stack.pop(); } else { return false; } } } // If the array is not empty, it is not balanced if (stack.pop()) return false; return true; }
遞迴
二進位制轉換
通過某個遞迴函式將輸入的數字轉化為二進位制字串:
decimalToBinary(3); // 11 decimalToBinary(8); // 1000 decimalToBinary(1000); // 1111101000 function decimalToBinary(digit) { if(digit >= 1) { // If digit is not divisible by 2 then recursively return proceeding // binary of the digit minus 1, 1 is added for the leftover 1 digit if (digit % 2) { return decimalToBinary((digit - 1) / 2) + 1; } else { // Recursively return proceeding binary digits return decimalToBinary(digit / 2) + 0; } } else { // Exit condition return ''; } }
二分搜尋
function recursiveBinarySearch(array, value, leftPosition, rightPosition) { // Value DNE if (leftPosition > rightPosition) return -1; var middlePivot = Math.floor((leftPosition + rightPosition) / 2); if (array[middlePivot] === value) { return middlePivot; } else if (array[middlePivot] > value) { return recursiveBinarySearch(array, value, leftPosition, middlePivot - 1); } else { return recursiveBinarySearch(array, value, middlePivot + 1, rightPosition); } }
數字
判斷是否為 2 的指數值
isPowerOfTwo(4); // true isPowerOfTwo(64); // true isPowerOfTwo(1); // true isPowerOfTwo(0); // false isPowerOfTwo(-1); // false // For the non-zero case: function isPowerOfTwo(number) { // `&` uses the bitwise n. // In the case of number = 4; the expression would be identical to: // `return (4 & 3 === 0)` // In bitwise, 4 is 100, and 3 is 011. Using &, if two values at the same // spot is 1, then result is 1, else 0. In this case, it would return 000, // and thus, 4 satisfies are expression. // In turn, if the expression is `return (5 & 4 === 0)`, it would be false // since it returns 101 & 100 = 100 (NOT === 0) return number & (number - 1) === 0; } // For zero-case: function isPowerOfTwoZeroCase(number) { return (number !== 0) && ((number & (number - 1)) === 0); }
相關文章
- 21個JavaScript 面試中常見演算法問題詳解JavaScript面試演算法
- 邦芒面試:面試中常見的4個致命問題面試
- 熟悉面試中常見的的 web 安全問題面試Web
- JavaScript經典面試題詳解JavaScript面試題
- 連結串列專題——面試中常見的連結串列問題面試
- Vue.js筆試題解決業務中常見問題Vue.js筆試
- 【Java面試】 Javascript常見面試題!JavaScript面試題
- 軟體測試面試中常見必問(二)自動化問題 內附答案面試
- 常見的JavaScript面試演算法JavaScript面試演算法
- 【面試】面試常見問題整理面試
- vue中常見的問題以及解決方法Vue
- 2019 JavaScript面試題詳解(基礎+進階)JavaScript面試題
- 問卷調查中常見問題及解決方法
- Redis最常見面試問題Redis面試
- Redis面試常見問題Redis面試
- 常見面試SQL問題面試SQL
- Spring 常見面試問題Spring面試
- Python面試常見問題Python面試
- JavaScript中的演算法(附10道面試常見演算法題解決方法和思路)JavaScript演算法面試
- 我使用jest測試專案中常見的問題
- JavaScript中揹包問題(面試題)JavaScript面試題
- 常見的Java面試問題Java面試
- 求職面試常見問題:Python常見面試題全解析附答案求職Python面試題
- JavaScript常見面試題彙總(含答案)JavaScript面試題
- 軟體測試面試常見問題面試
- 開發中常見問題總結
- JVM記憶體管理面試常見問題全解JVM記憶體面試
- 面試常問的20個資料庫高頻面試題詳解!資料庫面試題
- Redis的那些最常見面試問題Redis面試
- 2019年.net常見面試問題面試
- Flask專案常見面試問題Flask面試
- JAVA中常見的阻塞佇列詳解Java佇列
- 最失敗的 JavaScript 面試問題JavaScript面試
- 前端面試之webpack面試常見問題前端面試Web
- 資料結構與演算法常見問題(面試題)不定時更新資料結構演算法面試題
- 演算法面試:陣列編碼面試問題演算法面試陣列
- Linux MIPI 除錯中常見的問題Linux除錯
- 一文詳解面試常考的TopK問題面試TopK
- JavaScript面試題JavaScript面試題