摘要:先去空白,去掉空白之后取第一個字符,判斷正負符號,若是英文直接返回,若數字則不取。回文數題目描述判斷一個整數是否是回文數。回文數是指正序從左向右和倒序從右向左讀都是一樣的整數。
JS算法題之leetcode(1~10) 前言
一直以來,前端開發的知識儲備在數據結構以及算法層面是有所暫缺的,可能歸根于我們的前端開發的業務性質,但是我認為任何的編程崗位都離不開數據結構以及算法。
因此,我作為一名前端菜雞,打算做一個專欄,就是關于用JavaScript來解答算法題,會持續跟新,希望大家督促。同時,本人才疏學淺,文章內容可能有錯誤的地方,希望各位大神指出,謝謝。
no more bb, show me the code!
題目均來自樂扣(leetcode)
兩數之和 題目描述給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和為目標值的那 兩個 整數,并返回他們的數組下標。
示例給定 nums = [2, 7, 11, 15], target = 9
因為 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
這題不難,遍歷nums,用targer減去當前元素,得到的元素如果在數組中,那就完事了。不過要注意統一元素不能用兩次
var twoSum = function(nums, target) { let idx1, idx2; nums.forEach((ele, index) => { let tempIdx = nums.indexOf(target - ele); if(tempIdx !== -1 && tempIdx !== index){ idx1 = index; idx2 = tempIdx; } }); return [idx1, idx2] };兩數相加 題目描述
給出兩個?非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照?逆序?的方式存儲的,并且它們的每個節點只能存儲?一位?數字。
如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。
您可以假設除了數字 0 之外,這兩個數都不會以 0?開頭。
輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出:7 -> 0 -> 8
原因:342 + 465 = 807
這題不難,不過稍微有點復雜,涉及到了鏈表,同時考擦了js大數的運算情況。
先遍歷兩個鏈表獲得對應的數字,然后相加,最后反推算出結果對應的鏈表即可。
function ListNode(val) { this.val = val; this.next = null; return { val: this.val, next: null } } function addBigNumber(a, b) { var res = "", temp = 0; a = a.split(""); b = b.split(""); while (a.length || b.length || temp) { temp += ~~a.pop() + ~~b.pop(); res = (temp % 10) + res; temp = temp > 9; } return res.replace(/^0+/, ""); } var addTwoNumbers = function(l1, l2) { let num1 = "", num2 = "", cur; cur = l1; while(cur){ num1 += cur.val.toString(); cur = cur.next; } cur = l2; while(cur){ num2 += cur.val.toString(); cur = cur.next; } num1 = num1.split("").reverse().join(""); num2 = num2.split("").reverse().join(""); let total; if(num1.length > 21 || num2.length > 21){ total = addBigNumber(num1, num2) } else{ total = Number(num1) + Number(num2) } total = total.toLocaleString().toString().split("").reverse().join("").replace(/,/g, "") console.log(num1, num2, total) let l3 = ListNode(total[0]); cur = l3; for(let i = 1; i < total.length; i++){ let node = ListNode(total[i]); cur.next = node; cur = node; } return l3; };無重復字符的最長子串 題目描述
給定一個字符串,請你找出其中不含有重復字符的 最長子串 的長度。
示例輸入: "abcabcbb"
輸出: 3
解釋: 因為無重復字符的最長子串是 "abc",所以其長度為 3。
輸入: "bbbbb"
輸出: 1
解釋: 因為無重復字符的最長子串是 "b",所以其長度為 1。
輸入: "pwwkew"
輸出: 3
解釋: 因為無重復字符的最長子串是?"wke",所以其長度為 3。
請注意,你的答案必須是 子串 的長度,"pwke"?是一個子序列,不是子串。
解答維護一個數組用于存放無重復子串,遍歷輸入的字符串,若當前字符不在無重復數組中,則添加,否則,無重復數組清空,并push當前字符。
同時要維護另外一個最長無重復子串的數組。
var lengthOfLongestSubstring = function(s) { let max = 0, maxArr = [], oldArr= []; s.split("").forEach((ele, index) => { if(maxArr.indexOf(ele) === -1){ maxArr.push(ele) if(maxArr.length > max){ max = maxArr.length; } } else{ maxArr = [ele] let tempItem = oldArr.pop(); while(tempItem != ele){ maxArr.unshift(tempItem) tempItem = oldArr.pop(); } } oldArr = [...maxArr] }) return max; };尋找兩個有序數組的中位數 題目描述
給定兩個大小為 m 和 n 的有序數組?nums1 和?nums2。
請你找出這兩個有序數組的中位數,并且要求算法的時間復雜度為?O(log(m + n))。
你可以假設?nums1?和?nums2?不會同時為空。
示例nums1 = [1, 3]
nums2 = [2]
則中位數是 2.0
nums1 = [1, 2]
nums2 = [3, 4]
則中位數是 (2 + 3)/2 = 2.5
將兩個數組合并然后排序,之后獲取中位數即可。問題在于限定時間復雜度為?O(log(m + n))的情況下,如何排序呢?
我們這里直接使用sort()方法,該方法底層原理是將多個排序集于一體,根據數組的長度不同選擇不同的排序方法,加上V8引擎的優化,綜合來說時間復雜度是能滿足的。
好像有點偷雞摸狗的感覺。。。
sort方法的源碼:Array API源碼,從710行開始看吧
var findMedianSortedArrays = function(nums1, nums2) { let num = nums1.concat(nums2); num = num.sort((a, b) => a - b); let mid = Math.floor(num.length / 2); if (num.length % 2 === 0) { return (num[mid-1] + num[mid])/2 } else { return num[mid] } };最長回文子串 題目描述
給定一個字符串 s,找到 s 中最長的回文子串。你可以假設 s 的最大長度為 1000。
示例輸入: "babad"
輸出: "bab"
注意: "aba" 也是一個有效答案。
輸入: "cbbd"
輸出: "bb"
這題要用動態規劃來做,先是判斷出所有長度為1,2,3的子串是否回文。
長度為1,必定回文。
長度為2或者3,取決于首位字符是否相同。
長度大于3,取決于該子串去掉首位字符之后是否回文,并且首位字符是否相同。
核心在于 dp[i][j] == dp[i+1][j-1] && s[i] === s[j]
var longestPalindrome = function(s) { let dp = []; for(let i = 0; i < s.length; i++){ dp[i] = []; } let max = -1, str = ""; for(let k = 0; k < s.length; k++){ // k為所遍歷的子串長度 - 1,即左下標到右下標的距離 for(let i = 0; i + k < s.length; i++){ let j = i + k; // i為子串開始的左下標,j為子串開始的右下標 if(k == 0){ // 當子串長度為1時,必定是回文 dp[i][j] = true; } else if(k <= 2){ // 當子串長度為2時,兩字符相同則符合回文,長度為3,首位字符相同則符合回文 if(s[i] == s[j]){ dp[i][j] = true; } else{ dp[i][j] = false; } } else{ // 當子串長度超過3,取決于去掉頭尾之后的子串是否回文并且首位字符是否相同 if(dp[i+1][j-1] && (s[i] == s[j])){ dp[i][j] = true; } else{ dp[i][j] = false; } } if(dp[i][j] && k > max){ max = k; str = s.substring(i, j + 1) } } } return str; };Z 字形變換 題目描述
將一個給定字符串根據給定的行數,以從上往下、從左到右進行?Z 字形排列。
比如輸入字符串為 "LEETCODEISHIRING"?行數為 3 時,排列如下:
L C I R E T O E S I I G E D H N
之后,你的輸出需要從左往右逐行讀取,產生出一個新的字符串,比如:"LCIRETOESIIGEDHN"。
請你實現這個將字符串進行指定行數變換的函數:
string convert(string s, int numRows);
輸入: s = "LEETCODEISHIRING", numRows = 3
輸出: "LCIRETOESIIGEDHN"
輸入: s = "LEETCODEISHIRING", numRows =?4
輸出:?"LDREOEIIECIHNTSG"
解釋:
L D R E O E I I E C I H N T S G解答
這題目的結構有點怪,但也是有規律可循的,我們發現這個”Z“的字符順序是這樣子的:垂直向下,斜向上,然后再垂直向下。
那其實我們可以直接將該結構簡化為一個二維數組,去掉中間的空格,再一行一行地遍歷就能獲取到答案了。
如:
L D R E O E I I E C I H N T S G
可以變成
L D R E O E I I E C I H N T S G
接著再一行一行讀,拼成字符串,便可。
var convert = function(s, numRows) { if(numRows == 1){ return s; } let arr = [], direction = "down", line = 0, str = ""; for(let i = 0; i < numRows; i++){ arr[i] = []; } for(let i = 0; i < s.length; i++){ arr[line].push(s[i]); if(line == 0){ line++; direction = "down" } else if(line == numRows - 1){ line--; direction = "up" } else{ if(direction == "down"){ line++; } else if(direction = "up"){ line--; } } } for(let i = 0; i < numRows; i++){ str += arr[i].join(""); } return str; };整數反轉 題目描述
給出一個 32 位的有符號整數,你需要將這個整數中每位上的數字進行反轉。
注意:
假設我們的環境只能存儲得下 32 位的有符號整數,則其數值范圍為?[?231,? 231?? 1]。請根據這個假設,如果反轉后整數溢出那么就返回 0。
輸入: 123
輸出: 321
輸入: -123
輸出: -321
輸入: 120
輸出: 21
這題就很簡單了,不過要考慮好邊緣溢出情況即可。
var MAX = Math.pow(2, 31) - 1 var MIN = -1 * Math.pow(2, 31) var reverse = function(x) { let str = x.toString().split(""), symbolFlag = false; if(str[0] == "-"){ symbolFlag = true; str.shift(); } str = str.reverse(); if(symbolFlag){ str.unshift("-"); } let num = Number(str.join("")) if(num < MIN || num > MAX){ return 0 } else{ return num } };字符串轉換整數 (atoi) 題目描述
請你來實現一個?atoi?函數,使其能將字符串轉換成整數。
首先,該函數會根據需要丟棄無用的開頭空格字符,直到尋找到第一個非空格的字符為止。
當我們尋找到的第一個非空字符為正或者負號時,則將該符號與之后面盡可能多的連續數字組合起來,作為該整數的正負號;假如第一個非空字符是數字,則直接將其與之后連續的數字字符組合起來,形成整數。
該字符串除了有效的整數部分之后也可能會存在多余的字符,這些字符可以被忽略,它們對于函數不應該造成影響。
注意:假如該字符串中的第一個非空格字符不是一個有效整數字符、字符串為空或字符串僅包含空白字符時,則你的函數不需要進行轉換。
在任何情況下,若函數不能進行有效的轉換時,請返回 0。
說明:
假設我們的環境只能存儲 32 位大小的有符號整數,那么其數值范圍為?[?231,? 231?? 1]。如果數值超過這個范圍,qing返回 ?INT_MAX (231?? 1) 或?INT_MIN (?231) 。
題目很長是吧,沒關系,我們直接看示例。
輸入: "42"
輸出: 42
輸入: " -42"
輸出: -42
解釋: 第一個非空白字符為 "-", 它是一個負號。
? 我們盡可能將負號與后面所有連續出現的數字組合起來,最后得到 -42 。
輸入: "4193 with words"
輸出: 4193
解釋: 轉換截止于數字 "3" ,因為它的下一個字符不為數字。
輸入: "words and 987"
輸出: 0
解釋: 第一個非空字符是 "w", 但它不是數字或正、負號。
因此無法執行有效的轉換。
輸入: "-91283472332"
輸出: -2147483648
解釋: 數字 "-91283472332" 超過 32 位有符號整數范圍。
因此返回 INT_MIN (?231) 。
這題不難,但是有很多坑。首先我們采取ASCII編碼的方式來判斷字符為數字還是英文還是別的。
先去空白,去掉空白之后取第一個字符,判斷正負符號,若是英文直接返回0,若數字則不取。
從第二個字符開始遍歷,若不是數字則退出循環。
最后還要考慮溢出情況。
const MIN = -1 * Math.pow(2, 31); const MAX = Math.pow(2, 31) - 1; var myAtoi = function(str) { str = str.trim(); let result = "", symbol = ""; let idx = 0; if(str.charCodeAt(0) === 45){ idx++; symbol = "-"; } else if(str.charCodeAt(0) === 43){ idx++; } else if(str.charCodeAt(0) < 48 || str.charCodeAt(0) > 57){ return 0; } for(let i = idx; i < str.length; i++){ if(str.charCodeAt(i) === 46){ break; } else if(str.charCodeAt(i) >= 48 && str.charCodeAt(i) <= 57){ result += str[i]; } else{ break } } result = symbol.toString() + result.toString(); if(Number(result) !== Number(result)){ return 0; } else if(Number(result) < MIN){ return MIN; } else if(Number(result) > MAX){ return MAX; } else{ return Number(result) } };回文數 題目描述
判斷一個整數是否是回文數。回文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。
示例輸入: 121
輸出: true
輸入: -121
輸出: false
解釋: 從左向右讀, 為 -121 。 從右向左讀, 為 121- 。因此它不是一個回文數。
輸入: 10
輸出: false
解釋: 從右向左讀, 為 01 。因此它不是一個回文數
這題比較簡單,反轉對比即可
var isPalindrome = function(x) { let y = x.toString().split("").reverse().join(""); return x == y };正則表達式匹配 題目描述
給你一個字符串?s?和一個字符規律?p,請你來實現一個支持 "."?和?"*"?的正則表達式匹配。
"." 匹配任意單個字符
"*" 匹配零個或多個前面的那一個元素
所謂匹配,是要涵蓋?整個?字符串?s的,而不是部分字符串。
說明:
s?可能為空,且只包含從?a-z?的小寫字母。
p?可能為空,且只包含從?a-z?的小寫字母,以及字符?.?和?*。
輸入:
s = "aa"
p = "a"
輸出: false
解釋: "a" 無法匹配 "aa" 整個字符串。
輸入:
s = "aa"
p = "a*"
輸出: true
解釋:?因為 "*" 代表可以匹配零個或多個前面的那一個元素, 在這里前面的元素就是 "a"。因此,字符串 "aa" 可被視為 "a" 重復了一次。
輸入:
s = "ab"
p = ".*"
輸出: true
解釋:?"." 表示可匹配零個或多個("")任意字符(".")。
輸入:
s = "aab"
p = "cab"
輸出: true
解釋:?因為 "*" 表示零個或多個,這里 "c" 為 0 個, "a" 被重復一次。因此可以匹配字符串 "aab"。
輸入:
s = "mississippi"
p = "misisp*."
輸出: false
這題稍微有點復雜,我們采用了遞歸方法將兩個字符串對比,每次只對比一個字符。
將當前遞歸p的下一個字符是否為*進行分類比較:
①p的下一個字符是*
若s和p的當前字符相同或者p的當前字符為.,則結果就取決于:
isMatch(s.slice(1), p) || isMatch(s.slice(1), p.slice(2)) || isMatch(s, p.slice(2))
若p的最后兩個字符為.*就返回true
若不符合上面兩種情況就將取決于
isMatch(s,p.slice(2))
②p的下一個字符不為*
這種情況就簡單了
若s和p的當前字符相同或者p的當前字符為.,返回true
否則返回false
var isMatch = function(s, p) { if(s.length === 0 && p.length === 0){ return true; } if(s.length !== 0 && p.length === 0){ return false; } let str = s[0], pattern = p[0]; let isNextStart = p[1] === "*"; if(isNextStart){ if(str && (str === pattern || pattern === ".")){ return isMatch(s.slice(1), p) || isMatch(s.slice(1), p.slice(2)) || isMatch(s, p.slice(2)) } else if(pattern === "." && p.slice(2).length === 0){ return true } else{ return isMatch(s,p.slice(2)); } } else{ if(str && (str === pattern || pattern === ".")){ return isMatch(s.slice(1), p.slice(1)) } else{ return false; } } };總結
本文所有題目均來自樂扣(leetcode),做法不唯一,甚至可能還有所錯誤,希望各位大神指出,弟弟虛心學習。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/106682.html
摘要:給定一個整數,將其轉為羅馬數字。字符數值例如,羅馬數字寫做,即為兩個并列的。通常情況下,羅馬數字中小的數字在大的數字的右邊。給定一個羅馬數字,將其轉換成整數。注意空字符串可被認為是有效字符串。 JS算法題之leetcode(11~20) showImg(https://segmentfault.com/img/bVbwmfg?w=1790&h=714);這次的十道題目都比較容易,我們簡...
摘要:準備面試,多看點題。來自雨夜帶刀需求描述從一組有序的數據中生成一組隨機并且不重復的數,類似于簡單的抽獎程序的實現。 (準備面試,多看點題。來自雨夜帶刀s Blog) 需求描述:從一組有序的數據中生成一組隨機并且不重復的數,類似于簡單的抽獎程序的實現。 先來生成一個有序的數組: var arr = [], length = 100, i = 0; for( ; i < length;...
摘要:這是一道魔性面試題,難倒了無數英雄好漢上面代碼的執行順序是這樣的從上到下第一個函數就是實現了一個簡單的加法運算第二個函數是一個生成器函數,如果調用它會返回一個生成器這一行調用了生成器函數,所以此刻就是一個生成器它的本質還是迭代器然后執行循環 這是一道魔性面試題,難倒了無數英雄好漢…… def add(n,i): return n+i def test(): for i...
摘要:來自雨夜帶刀需求描述從一組數組中找出一組按不同順序排列的字符串的數組元素。最后用編碼和作為對象的來保存編碼和一致的字符串。方法方法是將字符串轉換成數組后再對數組進行排序,和使用排序后會變成,將拍好序的字符串作為對象的來保存排序一致的字符串。 (準備面試,多看點題。來自雨夜帶刀s Blog ) 需求描述:從一組數組中找出一組按不同順序排列的字符串的數組元素。假如有這樣一個數組: [ ...
閱讀 2952·2023-04-26 01:52
閱讀 3478·2021-09-04 16:40
閱讀 3636·2021-08-31 09:41
閱讀 1770·2021-08-09 13:41
閱讀 570·2019-08-30 15:54
閱讀 2969·2019-08-30 11:22
閱讀 1622·2019-08-30 10:52
閱讀 955·2019-08-29 13:24