天天一道算法题(第四期)

如你须要掌握三种核心的能力:编程、写做、设计??

前言

这个活动是从2019年7月中旬开始的,人数不算多,也就几个好友和好友的好友,过程当中也会有人由于工做的缘故或其余缘由放弃,或许将来还会有人离开。javascript

活动的主要形式就是在leetcode刷题,每一个工做日一道题,每周作总结,目前已是第十四期,接下来我会把每期的题作一个总结,因为我是侧重javascript,因此活动中的每道题都是以js语言来实现解题方法。java

活动的规则比较严谨,群里天天早上10点以前发题,晚上10点审核,审核有管理员专门审核,称为打卡,没有打卡的人,须要发红包给管理员做为天天统计费用。node

活动的目的就是培养算法思惟,了解常见的算法,好比分治算法、贪心算法、动态优化等等。面试

微信公众号惊天码盗同步天天一道算法题(第四期)​算法



上期回顾:
编程

本期题目

一、数组形式的整数加法

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。可是,每一个孩子最多只能给一块饼干。对每一个孩子 i ,都有一个胃口值 gi ,这是能让孩子们知足胃口的饼干的最小尺寸;而且每块饼干 j ,都有一个尺寸 sj 。若是 sj >= gi ,咱们能够将这个饼干 j 分配给孩子 i ,这个孩子会获得知足。你的目标是尽量知足越多数量的孩子,并输出这个最大数值。数组

注意:bash

你能够假设胃口值为正。
一个小朋友最多只能拥有一块饼干。微信

示例 1:app

输入: [1,2,3], [1,1]

输出: 1

解释:
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。虽然你有两块小饼干,因为他们的尺寸都是1,你只能让胃口值是1的孩子知足。因此你应该输出1。复制代码

示例 2:

输入: [1,2], [1,2,3]

输出: 2

解释: 
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。你拥有的饼干数量和尺寸都足以让全部孩子知足。因此你应该输出2.复制代码

题解:

思路1:逐位查找法

有一数组长为0,则返回为0,先排序,而后循环小孩胃口值,num用来存储返回值;ll用来存储饼干的索引(跟以前跳针法相似);当小孩的胃口值大于饼干的时候,须要在饼干中查找大于等于相应饼干尺寸,若是没找到返回最大值,若是找到则记录索引;而后进入下次循环。

执行用时:192ms;内存消耗:38.7MB;

var findContentChildren = function(g, s) {
    let {num=0,ll=0}={};
    if(!s.length||!g.length)return 0;
    let gArray=g.sort((a,b)=>a-b);
    let sArray=s.sort((a,b)=>a-b);
    for(let i=0;i<g.length;i++){
        if(sArray[ll]){
            if(gArray[i]>sArray[ll]){
                const cur=sArray.filter(a=>a>=gArray[i])[0]||null;
                if(cur){
                    ll=sArray.indexOf(cur)+1
                    num++
                }
            }else{
                ll++
                num++
            }
        }
        
    }
    return num
}
复制代码

思路2:倒序递减法

饼干尺寸和胃口值都从大到小排序,循环胃口值,逐一删除饼干尺寸。(经常从小到大排序,偶尔换个思路可能更方便)

执行用时:144ms;内存消耗:37.6MB;

var findContentChildren = function(g, s) {
    let num=0;
    let gArray=g.sort((a,b)=>b-a);
    let sArray=s.sort((a,b)=>b-a);
    gArray.forEach((item,i)=>{
        if(sArray[0]>=item){
            num++;
            sArray.shift()
        }
    })
    return num
}
复制代码

二、二叉树的层平均值

给定一个非空二叉树, 返回一个由每层节点平均值组成的数组.

示例 1:

输入:
    3
   / \
  9  20
    /  \
   15   7
输出: [3, 14.5, 11]
解释:第0层的平均值是 3,  第1层是 14.5, 第2层是 11. 所以返回 [3, 14.5, 11].复制代码

注意:

1.节点值的范围在32位有符号整数范围内。

题析:

关于图形算法,是比较复杂的,尤为是树的遍历,涉及到递归的逻辑。通常简单的状况下能够用条件语句while等来实现简单的递归。这道题一样能够,不管使用递归仍是while语句均可以实现。

这道题的结果是一数组,数组的每个值是当前层的节点值除以节点数;因此咱们要明确咱们须要获得的东西,层数,层数表示咱们数组的长度;当前层的节点值与当前层的节点数。

这道题的核心思路有两,一是层序遍历,一层一层推动只有当前层执行完才能够推动下一层;另外一种是不限制,不管当前层是否执行完,均可以执行下一层。这就会涉及到图形的两个概念:广度优先搜索和深度优先搜索。

题解:

思路1:广度优先遍历法

利用广度优先搜索的方法,逐层推动。利用queue的长度来限制是否向下推动,当所在层无值时向下推动。

执行用时:108ms;内存消耗:35.7MB;

var averageOfLevels = function(root) {
    let queue = [root], result = [], arr = [], sum = 0, length = 1
    while (queue.length) {
        let node = queue.shift()
        sum += node.val
        node.left && arr.push(node.left)
        node.right && arr.push(node.right)
        if (queue.length === 0) {
            result.push(sum/length)
            queue = arr
            length = queue.length
            arr = []
            sum = 0
        }
    }
    return result
}
复制代码

思路2:深度优先遍历法

经过每层的索引来肯定当前的值。同层相加。

执行用时:100ms;内存消耗:38.1MB;

var averageOfLevels = function(root) {
        let ans = [];
        let levelNum = [];//每一层的节点数
        let levelSum = [];//每一层的节点总数
        
        //递归函数
        let rescurse=(node, index, levelNum, levelSum)=>{
            if (node == null) {
                return;
            }

            if (levelNum.length <= index) {
                levelNum.push(1);
                levelSum.push(node.val);
            } else {
                levelNum[index]++;
                levelSum[index]+=node.val
            }

            rescurse(node.left, index + 1, levelNum, levelSum);
            rescurse(node.right, index + 1, levelNum, levelSum);

        }
    
        rescurse(root, 0, levelNum, levelSum);
    
        for (let i = 0; i < levelNum.length; i++) {
            ans.push(levelSum[i] / levelNum[i]);
        }
    

        return ans;
}
复制代码

三、整数反转

给出一个 32 位的有符号整数,你须要将这个整数中每位上的数字进行反转。

示例 1:

输入: 123
输出: 321复制代码

示例 2:

输入: -123
输出: -321复制代码

示例 3:

输入: 120
输出: 21复制代码

注意:

假设咱们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,若是反转后整数溢出那么就返回 0。

题解:

思路1:数组化

先转化为数组,反转后,再转化为字符串,须要逐一限制条件。

这个思路是数组思惟。

执行用时:108ms;内存消耗:35.7MB;

var reverse = function(x) {
    let num=String(Math.abs(x)).split('').reverse().join('');
    if(Math.pow(2,31)>=num&&x>0){
        return Number(num)
    }
    if(0-Math.pow(2,31)<0-num&&x<0){
         return 0-Number(num)
    }
    return 0
}
复制代码

思路2:分离取余法

先分离数字(123),取得余数(3)和剩余数(12),而后余数乘十(30)加剩余数的余数(2);记录每次相加后所得余数(32)与剩余数(1);依次循环,获得终数。

这个思路是利用的数学思惟。

执行用时:100ms;内存消耗:35.7MB;

var reverse = function (x) {
    let re = 0;
    while (parseInt(x / 10)) {
        re = 10 * re + x - 10 * parseInt(x / 10);
        x = parseInt(x / 10);
    }
    if (re > 214748364 || re < -214748364) return 0;
    if ((re == 214748364 && x > 7) || (re == 214748364 && x < -8)) return 0;
    re = 10 * re + x;
    return re
}
复制代码

思路3:字符倒序法

转化为字符串,反转字符串,而后在循环中逐一添加。须要注意的是,转的时候要绝对值化,转以后要取整。

这个思路是字符串思惟。

执行用时:112ms;内存消耗:35.7MB;

var reverse = function(x) {
    Math.abs(x)>(2**31-1)?x=0:x;
    if(x == 0) return 0
    let y = Math.abs(x).toString(),len='';
    for(var i =0;i<y.length;i++){len += y[y.length-i-1]}
    return parseInt(Math.abs(len)>(2**31-1)?len=0:(x<0?-len:len));
}
复制代码

四、回文数

判断一个整数是不是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是同样的整数。

示例 1:

输入: 121
输出: true复制代码

示例 2:

输入: -121
输出: false
解释: 从左向右读, 为 -121 。从右向左读, 为 121- 。所以它不是一个回文数。复制代码

示例 3:

输入: 10
输出: false
解释: 从右向左读, 为 01 。所以它不是一个回文数。复制代码

进阶:

你能不将整数转为字符串来解决这个问题吗?

题析:

这道题本质上和上面整数反转是一个题目,因此上面的思路下面都能用到,惟一的区别就是正负数。因此下面题解不会过多的介绍思路。

题解:

思路1:分离取余法

先转化为数组,反转后,再转化为字符串,须要逐一限制条件。

执行用时:360ms;内存消耗:42.5MB;

var isPalindrome = function(x) {
     if (x < 0) return false;
        let result = 0;
        let before = x;
        while (x > 0){
            result = result*10 + x%10;
            x = parseInt(x / 10);
        }
        return before == result?true:false;
}
复制代码

五、实现strStr()

实现 strStr() 函数。

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。若是不存在,则返回 -1。

示例 1:

输入: haystack = "hello", needle = "ll"
输出: 2复制代码

示例 2:

输入: haystack = "aaaaa", needle = "bba"
输出: -1复制代码

说明:

needle 是空字符串时,咱们应当返回什么值呢?这是一个在面试中很好的问题。

对于本题而言,当 needle 是空字符串时咱们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

题解:

思路1:字符串索引法

利用字符串方法一步到位。

执行用时:64ms;内存消耗:33.8MB;

var strStr = function(haystack, needle) {
    if(!needle)return 0;
    return haystack.indexOf(needle)
    
}
复制代码

执行用时:76ms;内存消耗:36MB;

var strStr = function (haystack, needle) {
    if (needle === "") return 0
    for (var i = 0; i < haystack.length; i++) {
        if (haystack[i] === needle[0]) {
            if (haystack.substring(i, i + needle.length) === needle) return i;
        }
    }
    return -1
}
复制代码

四期结束,但愿有更多的小伙伴加入。


关注公众号回复算法,一块儿学习吧。

相关文章
相关标签/搜索