js刷林扣 lintcode(2017年3月)

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,以此類推。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容