剑指offer - 知识迁移能力
1.数字在排序数组中出现的次数
问题描述:
统计一个数字在排序数组中出现的次数。
function GetNumberOfK(data, k) {
// write code here
var count = 0;
data.forEach((ele) => {
if (ele == k) {
count++;
}
});
return count;
}
2.二叉树的深度
问题描述:
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
/* function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
} */
function TreeDepth(pRoot) {
// write code here
if (pRoot === null) {
return 0;
}
var left = TreeDepth(pRoot.left);
var right = TreeDepth(pRoot.right);
return Math.max(left, right) + 1;
}
3.平衡二叉树
问题描述:
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
平衡二叉树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过 1,并且左右两个子树都是一棵平衡二叉树。
function IsBalanced_Solution(pRoot) {
return depth(pRoot) !== -1;
}
// 用递归来判断root是不是平衡二叉树,如果不是则返回最大的深度,如果不是则返回-1
function depth(root) {
if (root === null) return 0;
var left = depth(root.left);
if (left === -1) return -1;
var right = depth(root.right);
if (right === -1) return -1;
if (Math.abs(left - right) > 1) {
return -1;
} else {
return 1 + Math.max(left, right);
}
}
4.数组中只出现一次的数字
问题描述:
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
function FindNumsAppearOnce(array) {
// write code here
// return list, 比如[a,b],其中ab是出现一次的两个数字
var list = [];
array.forEach((item) => {
if (array.indexOf(item) === array.lastIndexOf(item)) {
list.push(item);
}
});
return list;
}
5.和为 S 的连续正数序列
问题描述:
小明很喜欢数学,有一天他在做数学作业时,要求计算出 9~16 的和,他马上就写出了正确答案是 100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为 100(至少包括两个数)。没多久,他就得到另一组连续正数和为 100 的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为 S 的连续正数序列? Good Luck!
输出描述:
输出所有和为 S 的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
解题思路:
因为要求连续的数列和,所以这是一个等差数列,并且我们想到用双指针来做,slow,fast。
等差数列:current(当前值)=(fast-slow+1)(fast+slow)/2
初始化 slow=1 和 fast=2.(因为考虑要覆盖到所有情况,所以赋值为两个较小的数)
只要满足 slow<fast,循环就可进行。
将 current 和 sum 进行比较
- 若 current==sum,即 slow 和 fast 之间的数满足序列要求,所以遍历 slow 和 fast 之间的所有数,存入一个数组。之后 slow++(因为要求的所有的连续正数序列,所以要不断的右移,这步不能少)。
- current<slow,则表明当前值小于 sum,需要 fast++,
- current>slow,则表明当前值大于 sum,需要减小当前值,即 slow++;
function FindContinuousSequence(sum) {
// write code here
var res = [];
var slow = 1;
var fast = 2; //快慢指针
while (slow < fast) {
var current = ((fast - slow + 1) * (fast + slow)) / 2;
if (current === sum) {
var temp = [];
for (let i = slow; i <= fast; i++) {
temp.push(i);
}
res.push(temp);
slow++;
} else if (current < sum) {
fast++;
} else {
slow++;
}
}
return res;
}
6.和为 S 的两个数字
问题描述:
输入一个递增排序的数组和一个数字 S,在数组中查找两个数,使得他们的和正好是 S,如果有多对数字的和等于 S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出。
方法一:
解题思路:
千万不要被题目误导了,因为数组是递增的,所有两个数乘积最小一定是两端的数,不会是中间的数,那只要用两个指针 low 和 high,初始,low 指向首部,high 指向尾部,判断:
当这两个指针对应的数相加和不为 sum 而且 low 比 high 小的时后,继续判断:
- 如果和大于 sum,说明 high 指针对应的数太大了,high--,往前找
- 如果和小于 sum,说明 low 指针对应的数太小了,low++,往后找
当这两个指针对应的数相加和为 sum 时,直接返回这两个数
否则返回空数组,表示不存在
function FindNumbersWithSum(array, sum) {
// write code here
var low = 0; //此指针指向第一个数
var high = array.length - 1; //此指针指向第二个数
while (array[low] + array[high] !== sum && low < high) {
if (array[low] + array[high] > sum) {
high--;
} else {
low++;
}
}
if (array[low] + array[high] === sum) {
return [array[low], array[high]];
}
return [];
}
方法二:
function FindNumbersWithSum(array, sum) {
// write code here
var res = [];
for (let i = 0; i < array.length; i++) {
var num = sum - array[i];
if (array.indexOf(num) !== -1) {
res.push(array[i], num);
break;
}
}
return res;
}
7.左旋转字符串
问题描述:
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列 S,请你把其循环左移 K 位后的序列输出。例如,字符序列 S=”abcXYZdef”,要求输出循环左移 3 位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
解题思路:
主要是注意当 str 不存在返回空字符串即可
function LeftRotateString(str, n) {
// write code here
if (!str) return "";
var n = n % str.length;
return str.slice(n) + str.slice(0, n);
}
8.翻转单词顺序列
问题描述:
牛客最近来了一个新员工 Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事 Cat 对 Fish 写的内容颇感兴趣,有一天他向 Fish 借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat 对一一的翻转这些单词顺序可不在行,你能帮助他么?
function ReverseSentence(str) {
// write code here
return str.split(" ").reverse().join(" ");
}