1.路径总和 III
题目:
给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
思路:首先,要计算得到某两个父子节点路径上的值的总和,要明确一点,路径之和,等于根节点到子节点(包括子节点)的值的总和,与根节点到父节点(不含父节点)的值的总和的差。
然后,在遍历的时候,每遍历一个节点,则记录根节点到这个节点的值的和。
为了防止重复计算,我们可以在遍历节点的时候,只计算从以这个节点为结束节点的路径
/**
* @param {TreeNode} root
* @param {number} sum
* @return {number}
*/
var pathSum = function (root, sum) {
if (!root) return 0;
let res = 0;
const stack = [
{
val: [0],
node: root,
},
];
while (stack.length) {
const item = stack.shift();
const preVal = item.val[item.val.length - 1];
for (const val of item.val) {
if (preVal + item.node.val - val === sum) {
res++;
}
}
if (item.node.left) {
stack.push({
val: item.val.concat([preVal + item.node.val]),
node: item.node.left,
});
}
if (item.node.right) {
stack.push({
val: item.val.concat([preVal + item.node.val]),
node: item.node.right,
});
}
}
return res;
};
2.排列硬币
题目:
你总共有 n 枚硬币,你需要将它们摆成一个阶梯形状,第 k 行就必须正好有 k 枚硬币。
给定一个数字 n,找出可形成完整阶梯行的总行数。
n 是一个非负整数,并且在32位有符号整型的范围内。
思路:等差数列的和,n行的等差数列,和为(1+n)*n/2,所以直接数学计算
/**
* @param {number} n
* @return {number}
*/
var arrangeCoins = function(n) {
return ~~((Math.sqrt(1+8*n,2)-1)/2)
};
迭代也可
/**
* @param {number} n
* @return {number}
*/
var arrangeCoins = function(n) {
let i=0;
while(n>i){
i++
n-=i
}
return i
};
3.压缩字符串
题目:
给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
找到所有在 [1, n] 范围之间没有出现在数组中的数字。
您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
思路:原地算法,不使用额外的空间的话,我们可以遍历一个数字,就给这个数字的值-1下标上的值乘以-1,这样,通过下标,我们就知道有哪些值。第二次遍历,正数值的下标就是没出现过的数
/**
* @param {number[]} nums
* @return {number[]}
*/
var findDisappearedNumbers = function(nums) {
const l = nums.length;
const res = [];
if (!l) return res;
for (const item of nums) {
const v = Math.abs(item);
if (nums[v - 1] > 0) {
nums[v - 1] *= -1;
}
}
for (let i = 0; i < l; i++) {
if (nums[i] > 0) {
res.push(i + 1);
}
}
return res;
};
4.最小移动次数是数组元素相等
题目:给定一个长度为 n 的非空整数数组,找到让数组所有元素相等的最小移动次数。每次移动将会使 n - 1 个元素增加 1。
思路:移动一次,其他元素+1,自己不变,其实就是变相的自己-1.所以,只需要计算每个数和最小数的差即可
/**
* @param {number[]} nums
* @return {number}
*/
var minMoves = function(nums) {
const l = nums.length;
if (!l) return 0;
let res = 0;
let min = nums[0];
for (let i = 1; i < l; i++) {
res += nums[i] - nums[0];
min = min < nums[i] ? min : nums[i];
}
return res + (nums[0] - min) * l;
};
/**
* @param {number[]} nums
* @return {number}
*/
var minMoves = function(nums) {
const l = nums.length;
if (!l) return 0;
let res = 0;
nums.sort((a, b) => a - b);
for (let i = 1; i < l; i++) {
res += nums[i] - nums[0];
}
return res;
};
5.分发饼干
题目:
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
注意:
你可以假设胃口值为正。
一个小朋友最多只能拥有一块饼干。
思路:先排序,然后双指针。
/**
* @param {number[]} g
* @param {number[]} s
* @return {number}
*/
var findContentChildren = function(g, s) {
g.sort((a, b) => a - b);
s.sort((a, b) => a - b);
let i = 0;
let j = 0;
let l1 = g.length;
let l2 = s.length;
let res = 0;
while (i < l1 && j < l2) {
if (g[i] <= s[j]) {
res++;
i++
}
j++;
}
return res;
};