11天刷剑指offer——JavaScript版——第七天

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、数组中只出现一次的数字

题目描述

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

思路

将数组同去重后的数组进行比较,求出数组中元素出现的次数。

代码

去重数组
  1. 创建一个新的数组存放结果
  2. 创建一个空对象
  3. 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;
}
数组去重另外两种方法
方法一
  1. 构建一个新的数组存放结果
  2. for循环中每次从原数组中取出一个元素,用这个元素循环与结果数组对比
  3. 若结果数组中没有该元素,则存到结果数组中
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;
}
方法二
  1. 先将原数组进行排序
  2. 检查原数组中的第i个元素 与 结果数组中的最后一个元素是否相同,因为已经排序,所以重复元素会在相邻位置
  3. 如果不相同,则将该元素存入结果数组中
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 [];
}

猜你喜欢

转载自blog.csdn.net/jiuchabi7492/article/details/88226128
今日推荐