3.10
69.給出一棵二叉樹,返回其節點值的層次遍歷(逐層從左往右訪問)
二叉樹的層次遍歷
樣例
給一棵二叉樹 {3,9,20,#,#,15,7} :
3
/ \
9 20
/ \
15 7
返回他的分層遍歷結果:
[
[3],
[9,20],
[15,7]
]
function levelOrder(arr){
var res=[]
var tempArr=[]
var levelNum=1 //每層的節點數
var levelTotal=1 //層的階乘
for(var i=0;i<arr.length+1;i++){
if(arr[i]=='#'){arr[i]=undefined}
if(i<levelTotal){
tempArr.push(arr[i])
}else if(i==levelTotal){ //等于的時候退出子數組,往res中push
res.push(tempArr)
tempArr=[] //清空子數組
tempArr.push(arr[i])
levelNum*=2
levelTotal+=levelNum
}
}
return res
}
80.給定一個未排序的整數數組,找到其中位數。
中位數
中位數是排序后數組的中間值,如果數組的個數是偶數個,則返回排序后數組的第N/2個數。
樣例
給出數組[4, 5, 1, 2, 3], 返回 3
function median(arr){
var i=arr.length%2==0? arr.length/2:(arr.length+1)/2
return arr.sort()[i]
}
82.落單的數
給出2*n + 1 個的數字,除其中一個數字之外其他每個數字均出現兩次,找到這個數字。
樣例
給出 [1,2,2,1,3,4,3],返回 4
function singleNumber(arr){
arr.sort()
var totalArr=[]
for(var i=0;i<arr.length+1;i+=2){
if(arr[i]!=arr[i+1]){
if(i==arr.length-1){return arr[i]}//如果arr[i]為最后一個自然數則返回他
if(arr[i+2]==arr[i+1]){return arr[i]}
}
}
}
看了下大多數的算法,都是用位操作符異或算的,既然js有sort()方法還是這樣寫好了,反正都得遍歷。
3.13
96.鏈表劃分
給定一個單鏈表和數值x,劃分鏈表使得所有小于x的節點排在大于等于x的節點之前。
你應該保留兩部分內鏈表節點原有的相對順序。
鏈接
樣例
給定鏈表 1->4->3->2->5->2->null,并且 x=3
返回 1->2->2->4->3->5->null
function partition(arr,num){
var pre=[],post=[]
for(var i in arr){
if(arr[i]>=num){
post.push(arr[i])
}else{
pre.push(arr[i])
}
}
return pre.concat(post)
}
3.14
97.二叉樹的最大深度
給定一個二叉樹,找出其最大深度。二叉樹的深度為根節點到最遠葉子節點的距離。
樣例
給出一棵如下的二叉樹:
1
/ \
2 3
/ \
4 5
這個二叉樹的最大深度為3.
function maxDepth(len){
if(len%2==0){
depth++
return maxDepth(len/2)
}
return depth
}
思路:深度為2的n次方-1,傳數組的長度+1,算幾次冪就好了
100.刪除排序數組中的重復數字
給定一個排序數組,在原數組中刪除重復出現的數字,使得每個元素只出現一次,并且返回新的數組的長度。
不要使用額外的數組空間,必須在原地沒有額外空間的條件下完成。
題目鏈接
樣例
給出數組A =[1,1,2],你的函數應該返回長度2,此時A=[1,2]。
function removeDuplicates(arr){
var i=0
while(i<arr.length){
if(arr[i+1]==arr[i]){
arr.splice(i+1,1)
}else{
i++
}
}
return arr
}
思路:遍歷數組,刪除一個元素后不需要改變i值
101.刪除排序數組中的重復數字 II
跟進“刪除重復數字”:
如果可以允許出現兩次重復將如何處理?
function removeDuplicates(arr){
var i=0
var duplicateTimes=0
while(i<arr.length){
if(arr[i+1]==arr[i]){
duplicateTimes++
if(duplicateTimes>2){
arr.splice(i+1,1)
}
}else{
duplicateTimes=0
i++
}
}
return arr
}
思路:和上題相比,多加一個判斷條件就ok了,但依舊是刪除一個元素后i不變
3.15
109.數字三角形
給定一個數字三角形,找到從頂部到底部的最小路徑和。每一步可以移動到下面一行的相鄰數字上。題目鏈接
樣例:
比如,給出下列數字三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
從頂到底部的最小路徑和為11 ( 2 + 3 + 5 + 1 = 11)。
function minimumTotal(arr){
var sum=0
arr.forEach(function(a){
a.sort()
sum+=a[0]
})
return sum
}
思路:遍歷數組,將每個子數組排序,取第零個相加
111. 爬樓梯
假設你正在爬樓梯,需要n步你才能到達頂部。但每次你只能爬一步或者兩步,你能有多少種不同的方法爬到樓頂部?
題目鏈接
樣例
比如n=3,1+1+1=1+2=2+1=3,共有3中不同的方法
返回 3
function climbStairs(n){
var mtd=0
if(n==0||n==1){
return 1
}
else{
mtd=climbStairs(n-1)+climbStairs(n-2)
}
return mtd
}
思路:爬到第幾層就是上一層在爬一層,也就是上上一層爬兩層···以此類推,遞歸
3.17
133.最長單詞
給一個詞典,找出其中所有最長的單詞。
題目鏈接
樣例
在詞典
{
"dog",
"google",
"facebook",
"internationalization",
"blabla"
}
中, 最長的單詞集合為 ["internationalization"]
挑戰
遍歷兩次的辦法很容易想到,如果只遍歷一次你有沒有什么好辦法?
function longestWords(arr){
let maxLen=0,res=[]
arr.forEach( (a) => {
if(a.length>=maxLen){
if(a.length>maxLen){
maxLen=a.length
res=[]
}
res.push(a)
}
})
return res
}
思路
遍歷數組,比之前的大就清空結果數組,重新push
138.子數組之和
給定一個整數數組,找到和為零的子數組。你的代碼應該返回滿足要求的子數組的起始位置和結束位置
題目鏈接
樣例
給出 [-3, 1, 2, -3, 4],返回[0, 2] 或者 [1, 3].
function subarraySum(arr){
let res=[],startIndex=0,sum=0,posArr=[]
for(j=0;j<arr.length;j++){
for(let i=startIndex;i<arr.length;i++){
posArr.push(i)
sum+=arr[i]
if(sum==0){
res.push(posArr)
posArr=[]
startIndex++
break;
}
}
}
return res
}
function startAndEnd(arr){
let res=[]
arr.forEach((a) => {
let subArr=[]
subArr.push(a[0])
subArr.push(a[a.length-1])
res.push(subArr)
})
return res
}
let result=startAndEnd(subarraySum([-3, 1, 2, -3, 4]))
思路:有多少個元素就遍歷幾次,每次遍歷時從指針所指元素開始,找到sum為0的元素就退出循環,下次指針指向下一個元素
3.20(春分)
140.x的平方根
實現 int sqrt(int x) 函數,計算并返回 x 的平方根。
題目鏈接
樣例
sqrt(3) = 1
sqrt(4) = 2
sqrt(5) = 2
sqrt(10) = 3
let sqrtFn = (num) => Math.sqrt(num)
思路:沒有思路,內置方法LOL
142.O(1)時間檢測2的冪次
用 O(1) 時間檢測整數 n 是否是 2 的冪次。
題目鏈接
樣例
n=4,返回 true;
n=5,返回 false.
let checkPowerOf2 = (num) => {
let decimalRes=num.toString(2)&(num-1).toString(2)
return num>0&&decimalRes==0
}
思路:位操作,當前數并上他的上一個數,如為0則是2的冪數
3.21
156. 合并區間
給出若干閉合區間,合并所有重疊的部分。
題目鏈接
樣例
給出的區間列表 => 合并后的區間列表:
[ [
[1, 3], [1, 6],
[2, 6], => [8, 10],
[8, 10], [15, 18]
[15, 18] ]
]
let merge=(intervals) => {
intervals.sort((a,b)=>{
//先排序
if(a[0]!=b[0]){return a[0]-b[0]}
return a[1]-b[1]
})
let len=intervals.length
let res=[],start,end
for(let i=0;i<len;i++){
let s=intervals[i][0],e=intervals[i][1]
if(!start) {start=s,end=e}
else if(s<=end){end=Math.max(end,e)}
else{
let part=[start,end]
res.push(part)
start=s
end=e
}
}
if(start){
let part=[start,end]
res.push(part)
}
return res
}
let arr=[
[1,3],[2,6],[8,10],[9,11]]
console.log(merge(arr)) //[1,6],[8,11]
思路:將區間從大到小排序,遍歷找下個區間中的重合部分,push進新數組
157.判斷字符串是否沒有重復字符
實現一個算法確定字符串中的字符是否均唯一出現
題目鏈接
樣例
給出"abc",返回 true
給出"aab",返回 false
挑戰
如果不使用額外的存儲空間,你的算法該如何改變?
let isUnique=(str) => {
for(let i=0;i<str.length;i++){
for(let j=i+1;j<str.length;j++){
if(str.charAt(i)==str.charAt(j)){
return false
}
}
}
return true
}
console.log(isUnique('abcd')) //true
思路:不占用存儲空間,只能延長運行時間。遍歷兩層,找到相同的元素就返回false。
3.22
158.兩個字符串是變位詞
寫出一個函數 anagram(s, t) 判斷兩個字符串是否可以通過改變字母的順序變成一樣的字符串。題目鏈接
樣例
給出 s = "abcd",t="dcab",返回 true.
給出 s = "ab", t = "ab", 返回 true.
給出 s = "ab", t = "ac", 返回 false.
挑戰
O(n) time, O(1) extra space
let anagram = (str1,str2)=>{
if(str1.length!=str2.length) return false
for(let i=0;i<str1.length;i++){
if(str1.charAt(i)!=str2.charAt(str1.length-1-i)) return false
}
return true
}
let str1='abcd',str2='cdba'
console.log(anagram(str1,str2)) //true
思路:找對應的位置元素是否相同,不同則return false
165.合并兩個排序鏈表
合并兩個排序鏈表題目鏈接
樣例
給出 1->3->8->11->15->null,2->null, 返回 1->2->3->8->11->15->null。
let mergeTwoLists=(arr1,arr2)=>{
let res=[].concat(arr1).concat(arr2)
res.sort((a,b)=>a-b)
return res
}
let arr1=[1,3,8,11,15]
let arr2=[2]
console.log(mergeTwoLists(arr1,arr2))
思路:連接兩個數組,之后排序
166.鏈表倒數第n個節點
找到單鏈表倒數第n個節點,保證鏈表中節點的最少數量為n。題目鏈接
樣例
給出鏈表 3->2->1->5->null和n = 2,返回倒數第二個節點的值1.
let nthToLast=(arr,p)=>{
if(p>arr.length) return 'error position'
return arr[arr.length-p]
}
let arr=[5,4,3,2,1]
console.log(nthToLast(arr,5)) //5
思路:js中沒有鏈表的概念,數組很好取
3.23
172.刪除元素
給定一個數組和一個值,在原地刪除與值相同的數字,返回新數組的長度。
元素的順序可以改變,并且對新的數組不會有影響
樣例
給出一個數組 [0,4,4,0,0,2,4,4],和值 4
返回 4 并且4個元素的新數組為[0,0,0,2]
let removeElement=(arr,num)=>{
let newArr=[]
arr.forEach((a)=>{
if(a==num){
newArr.push(a)
}
})
return newArr.length
}
let arr= [0,4,4,0,0,2,4,4]
console.log(removeElement(arr,4))//4
思路:遍歷數組,找到一個符合條件的就push到新數組
3.24
181.將整數A轉換為B
如果要將整數A轉換為B,需要改變多少個bit位?題目鏈接
樣例
如把31轉換為14,需要改變2個bit位。
(31)10=(11111)2
(14)10=(01110)2
let bitSwapRequired=(n1,n2)=>{
let res=0
let num1=n1.toString(2)
let num2=n2.toString(2)
let maxL=Math.max(num1.length,num2.length)
let maxN=Math.max(num1,num2),minN=Math.min(num1,num2)
for(let i=maxL;i>0;i--){
//maxN和minN都是數字,先轉化為字符串再遍歷每個位置
if((''+maxN).charAt(i)!=(''+minN).charAt(i)){res++}
}
return res;
}
console.log(bitSwapRequired(19,31)) //2
思路:轉化為2進制之后,按照字符串的類型遍歷。注意一定是從尾部開始遍歷。
185.矩陣的之字型遍歷
給你一個包含 m x n 個元素的矩陣 (m 行, n 列), 求該矩陣的之字型遍歷。
給你一個包含 m x n 個元素的矩陣 (m 行, n 列), 求該矩陣的之字型遍歷。題目鏈接
樣例
對于如下矩陣:
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10, 11, 12]
]
返回 [1, 2, 5, 9, 6, 3, 4, 7, 10, 11, 8, 12]
let permutationIndex=(arr)=>{
let res=[arr[0][0]]
let r=0,c=0
let LEN=arr[0].length*arr.length
for(let i=0;i<LEN;i++){
while(i<LEN&&r>=1&&c<arr[0].length-1){
res.push(arr[--r][++c])
}
if(i<LEN&&c<arr[0].length-1){
res.push(arr[r][++c])
}else if(i<LEN&&r<arr.length-1){
res.push(arr[++r][c])
}
while(i<LEN&&r<arr.length-1&&c>=1){
res.push(arr[++r][--c])
}
if(i<LEN&&r<arr.length-1){
res.push(arr[++r][c])
}else if(i<LEN&&c<arr[0].length-1){
res.push(arr[r][++c])
}
}
return res
}
思路:這個邏輯比之前的復雜多了,而且不好找規律,為啥要放簡單題里!!我也是網上搜的java代碼改成js了。。真心笨
3.27
211.字符串置換
具體不說了,和158變位詞一個意思題目鏈接
212.空格替換
設計一種方法,將一個字符串中的所有空格替換成 %20 。你可以假設該字符串有足夠的空間來加入新的字符,且你得到的是“真實的”字符長度。
你的程序還需要返回被替換后的字符串的長度。題目鏈接
let replaceBlank=(str)=>{
str=str.replace(/ /g,'%20')
console.log(str)
return str.length
}
console.log(replaceBlank("Mr John Smith")) //17
思路:這道題原意是讓你遍歷字符串,然后挪遍歷位置。因為js有現有方法就直接用了,that's why i love JavaScript deeply~~
365.二進制中有多少個1
計算在一個 32 位的整數的二進制表式中有多少個 1 題目鏈接
let countOnes=(num)=>{
let str=num.toString(2)
let i=0,res=0
for(;i<str.length;i++){
if(str.charAt(i)==1){res+=1}
}
return res
}
console.log(countOnes(7))//3
思路:轉換為二進制,遍歷
373.奇偶分割數組
分割一個整數數組,使得奇數在前偶數在后。題目鏈接
let partitionArray=(arr)=>{
let i=0,j=arr.length-1
while(i<j){
while(arr[i]%2==1){
i++;
}
while(arr[j]%2==0){
j--;
}
if(i<j){
arr[i]=arr[i]+arr[j]
arr[j]=arr[i]-arr[j]
arr[i]=arr[i]-arr[j]
}
}
return arr
}
思路:指針一個在頭部,一個在尾部,當兩個指針將要重合的時候,停止遍歷。
372.在O(1)時間復雜度刪除鏈表節點
給定一個單鏈表中的一個等待被刪除的節點(非表頭或表尾)。請在在O(1)時間復雜度刪除該鏈表節點題目鏈接
樣例
給定 1->2->3->4,和節點 3,刪除 3 之后,鏈表應該變為 1->2->4。
let deleteNode=(arr,n)=>{
let pos=arr.indexOf(n)
arr.splice(pos,1)
return arr
}
思路:因為js中沒有指針和鏈表這兩個概念,就當做數組來寫,但復雜度不可能是o1。所以解題思路是找到索引,然后刪除那個元素。
3.29
397.最長上升連續子序列
給定一個整數數組(下標從 0 到 n-1, n 表示整個數組的規模),請找出該數組中的最長上升連續子序列。(最長上升連續子序列可以定義為從右到左或從左到右的序列。)題目鏈接
let res=[],temp=[]
let longestIncreasingContinuousSubsequenc=function(arr,pos){
if(pos==arr.length-1) {
if(arr[pos]<arr[pos-1]){res.push(arr[pos])}
return res
}
for(let i=pos;i<arr.length;i++){
if(temp.length==0){
temp.push(arr[i])
return longestIncreasingContinuousSubsequenc(arr,i+1)
}
if(i>0&&i<arr.length-1&&arr[i-1]>arr[i]){
temp.push(arr[i])
}else{
if(temp.length>res.length){
res=temp
temp=[]
return longestIncreasingContinuousSubsequenc(arr,i)
}
}
}
return res
}
let arr=[5, 4, 2, 1, 9,8,7,6,5,4,3,2,9,5,2] // 9,8,7,6,5,4,3,2
console.log(longestIncreasingContinuousSubsequenc(arr,0))
思路:遞歸。存兩個全局變量,比較數組長度,返回長度大的那個
3.30
407.加一
給定一個非負數,表示一個數字數組,在該數的基礎上+1,返回一個新的數組。
該數字按照大小進行排列,最大的數在列表的最前面。題目鏈接
let temp=[]
let plusOne=(arr,pos)=>{
if(arr[pos]+1>=10){
arr[pos]=0
return plusOne(arr,pos-1)
}else{
if(pos<0){
arr.unshift(1)
}else{
arr[pos]+=1
}
return arr
}
}
let arr=[1,9,9,9]
console.log(plusOne(arr,arr.length-1)) //2000
思路:怎么想都是用遞歸邏輯比較清晰,值得注意的一點是,當pos小于0的時候,需要在數組頭部unshift(1)。其實這道題可以偷個懶,就是先把數組變成數字加一再轉換為數組lol。
3.31
408.二進制求和
給定兩個二進制字符串,返回他們的和(用二進制表示)。相關鏈接
樣例
a = 11
b = 1
返回 100
let addBinary=(a,b)=>{
let sum=(a+b+'').split('')
const len=sum.length
let i=len-1
while(i>0){
if(sum[i]>1){
if(sum[i]%2==0){
if(i>=1){
sum[i-1]=parseInt(sum[i-1])+1
}
sum[i]=0
}else{ //%2==1
sum[i-1]=parseInt(sum[i-1])+Math.floor(sum[i])
sum[i]=1
}
}
i--
}
if(sum[0]>1){
sum.unshift(Math.floor(sum[0]/2))
sum[1]=sum[1]%2
}
return sum.join('')
}
console.log(addBinary(111,10)) //1001
思路:先按照10進制相加,然后再遍歷每位是否大于1,大于1則往前面一位加1,以此類推。