文章目录
37、数字在排序数组中出现的次数
题目描述
统计一个数字在排序数组中出现的次数。
思路一
我最喜欢的暴力解决法,遍历
代码
function GetNumberOfK(data, k)
{
var count=0;
data.forEach(function(a){
if(a==k) count++;
if(a>k) return count;
})
return count
}
思路二
二分查找方法:先看中间元素与k相比,小于则在左半部分,大于则在右半部分
代码
function GetNumberOfK(data, k)
{
var l = 0, r = data.length, mid;
while(l < r){
mid = (l + r) >> 1; //除以2取中间位置
if(k > data[mid]){
//数据定位在后半部分
while(data[mid] == data[mid + 1]){
mid++;
}
l = ++mid;
}else if(k < data[mid]){
//数据定位在前半部分
while(data[mid] == data[mid - 1]){
mid--;
}
r = --mid;
}//前面是为了定指针,相同数据的前后指针
else{
//这是k=data[mid]
var sign1 = mid, sign2 = mid;
//判断邻近的几个元素
while(sign1 > l && data[sign1] == data[sign1 + 1]){
sign1++;
}
while(sign2 < r && data[sign2] == data[sign2 - 1]){
sign2--;
}
//sign1、sign2是相等元素的前后元素指针
return sign1 - sign2 + 1
}
}
return 0;
}
38、二叉树的深度
题目描述
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
思路
递归求左子树和右子树深度,然后比较,最终返回最大值加1
代码
/* function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
} */
function TreeDepth(pRoot)
{
if(pRoot == null) return 0;
var left = TreeDepth(pRoot.left);
var right = TreeDepth(pRoot.right);
return (left > right) ? left+1 :right+1;
}
39、平衡二叉树
题目描述
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
思路
它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。遍历左子树和右子树的深度,然后比较二者差值。
代码
结合求子树深度来判断
function IsBalanced_Solution(pRoot)
{
if(pRoot == null) return true;
var left = TreeDepth(pRoot.left);
var right = TreeDepth(pRoot.right);
if(left - right > 1 || left - right < -1){
return false;
}
return IsBalanced_Solution(pRoot.left) && IsBalanced_Solution(pRoot.right)
}
function TreeDepth(root){
if(root == null) return 0;
var left = TreeDepth(root.left);
var right = TreeDepth(root.right);
return (left > right) ? left+1 : right+1;
}
40、数组中只出现一次的数字
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
思路
将数组同去重后的数组进行比较,求出数组中元素出现的次数。
代码
去重数组
- 创建一个新的数组存放结果
- 创建一个空对象
- for循环时,每次取出一个元素与对象进行对比,如果这个元素不重复,则把它存放到结果数组中,同时把这个元素的内容作为对象的一个属性,并赋值为1,存入到第2步建立的对象中。
说明:至于如何对比,就是每次从原数组中取出一个元素,然后到对象中去访问这个属性,如果能访问到值,则说明重复。
/* 自定义数组上的函数,这个是往数组原型上添加一个函数(属性)以后各个你定义的数组都可以直接使用这个函数(属性) */
Array.prototype.uniq = function(){
var res = [];
var json = {};
for(var i = 0 ; i < this.length ; i++){
//重复的this[i]是不会push进去res的
//之前是空对象,后来赋值为1
if(!json[this[i]]){
res.push(this[i]);
json[this[i]] = 1;
}
}
return res;
}
function FindNumsAppearOnce(array)
{
// return list, 比如[a,b],其中ab是出现一次的两个数字
var a = array;
var b = a.uniq(); //去掉重复元素剩下的数组
var result = [];
var k = 0;
//循环找出不一样的数组元素
for(var i = 0 ; i < b.length ; i++){
for(var j = 0 ; j < a.length ; j++){
if(b[i] == a[j]){
k++;
}
}
if(k == 1){
result.push(b[i])
}
k = 0; // 重新赋值0,继续下一次循环
}
return result;
}
数组去重另外两种方法
方法一
- 构建一个新的数组存放结果
- for循环中每次从原数组中取出一个元素,用这个元素循环与结果数组对比
- 若结果数组中没有该元素,则存到结果数组中
Array.prototype.unique1 = function(){
var res = [this[0]];
for(var i = 1; i < this.length; i++){
var repeat = false;
for(var j = 0; j < res.length; j++){
if(this[i] == res[j]){
repeat = true;
break;
}
}
if(!repeat){
res.push(this[i]);
}
}
return res;
}
方法二
- 先将原数组进行排序
- 检查原数组中的第i个元素 与 结果数组中的最后一个元素是否相同,因为已经排序,所以重复元素会在相邻位置
- 如果不相同,则将该元素存入结果数组中
Array.prototype.unique2 = function(){
this.sort(); //先排序
var res = [this[0]];
for(var i = 1; i < this.length; i++){
if(this[i] !== res[res.length - 1]){
res.push(this[i]);
}
}
return res;
}
第二种方法也会有一定的局限性,因为在去重前进行了排序,所以最后返回的去重结果也是排序后的。如果要求不改变数组的顺序去重,那这种方法便不可取了。
41、和为S的连续正数序列
题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
思路
设定两个指针,如果和大于sum,左指针向后移位,如果小于,右指针向后移位。如果两个指针碰在一起,则跳出,左指针一直小于sum的一半。
代码
function FindContinuousSequence(sum)
{
if(sum < 2) return [];
var result = [];
var a = 1, b = 2, s = 3;//最小的正数序列
while(a <= Math.floor(sum / 2)){
if(s < sum){
//加入大数
b++;
s += b;
}else if(s > sum){
//减少小数
s -= a;
a++;
}else{
//s=sum
var tem = [];
for(var i = a ; i <= b ; i++){
tem.push(i);
}
result.push(tem);
if(a + 1 < b){//保证左右指针不碰撞
s -= a;
a++
}else{
break;
}
}
}
return result;
}
42、和为S的两个数字
题目描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出。
思路一
暴力解决。
代码
function FindNumbersWithSum(array, sum)
{
if(array.length < 2) return [];
var res = [];
for(var i = 0 ; i < array.length ; i++){
for(var j = 0 ; j < array.length ; j++){
if(array[i] + array[j] == sum){
res.push(array[i],array[j]);
}
}
}
return res.slice(0,2);//输出最小的两个数
}
思路二
两头乘积最小,所以两个指针,一个从头,一个从尾分别遍历,当第一次出现和为S时,乘积最小
代码
function FindNumbersWithSum(array, sum)
{
if(array.length < 2) return [];
var start = 0, end = array.length - 1;
while(start < end){
//保证没遍历完
var s = array[start] + array[end];
if(s < sum){
start++;
}else if(s > sum){
end--;
}else{
//s=sum
return [array[start],array[end]];
}
}
return [];
}