JavaScript基础让前端飞Web前端之路

js刷林扣 lintcode(2017年3月)

2017-04-01  本文已影响255人  mytac

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

上一篇下一篇

猜你喜欢

热点阅读