如你需要掌握三种核心的能力:编程、写作、设计??
前言
这个活动是从2019年7月中旬开始的,人数不算多,也就几个好友和好友的好友,过程中也会有人因为工作的缘故或其他原因放弃,或许未来还会有人离开。
活动的主要形式就是在leetcode刷题,每个工作日一道题,每周做总结,目前已经是第十四期,接下来我会把每期的题做一个总结,由于我是侧重javascript,所以活动中的每道题都是以js语言来实现解题方法。
活动的规则比较严谨,群里每天早上10点之前发题,晚上10点审核,审核有管理员专门审核,称为打卡,没有打卡的人,需要发红包给管理员作为每天统计费用。
活动的目的就是培养算法思维,了解常见的算法,比如分治算法、贪心算法、动态优化等等。
微信公众号惊天码盗同步每天一道算法题(第四期)

本期题目
1、数组形式的整数加法
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
注意:
你可以假设胃口值为正。
一个小朋友最多只能拥有一块饼干。
示例 1:
输入: [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
}
2、二叉树的层平均值
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组.
示例 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;
}
3、整数反转
给出一个 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));
}
4、回文数
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 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;
}
5、实现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
}
四期结束,希望有更多的小伙伴加入。

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