剑指offer——javascript编程

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

//indexOf()和lastIndexOf()这两个位置方法,indexOf()从头开始向后查找,并返回查找元素的位置,若没有
//则返回-1,lastIndexOf()从后往前查找,同样返回查找元素在数组中的位置。
 
function FindNumsAppearOnce(array)
{
    var len = array.length;
    var list = [];
    for(var i=0;i<len;i++){
        if(array.indexOf(array[i]) == array.lastIndexOf(array[i])){
            list.push(array[i]);
        }
    }
    return list;
}

2、输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

     例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

//join():把数组中的所有元素放入一个字符串,内可指定连接符,比如:join('#');
//toString():把数字转换为字符串
//parseInt():解析一个字符串,并把其转换为整数
//sort():对数组元素进行排序,并返回排序好的数组。
//如果 compareFunction(a, b) (返回的值)小于0,那么a会被排列到b之前,即参数a,b的顺序保持原样;
//如果 compareFunction(a, b) (返回的值) 等于0,a和b的相对位置不变;
//如果 compareFunction(a, b) (返回的值)大于0,b会被排列到a之前,即交换参数a,b的顺序。

function PrintMinNumber(numers)
{
    // write code here
    numbers.sort(function(num1,num2){
        var a=num1.toString();
        var b=num2.toString();
        if(parseInt(a+b)>parseInt(b+a)){
            return 1;
        }else{
            return -1;
        }
    });
    return numbers.join('');
}

3、输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

//递归思想
function reConstructBinaryTree(pre, vin)
{
    var result = null;
    if(pre.length>1){
        var root = pre[0];
        var vinRootIndex = vin.indexOf(root);
        var vinLeft = vin.slice(0,vinRootIndex);
        var vinRight = vin.slice(vinRootIndex+1,vin.length);
        pre.shift();
        var preLeft = pre.slice(0,vinLeft.length);
        var preRight = pre.slice(vinLeft.length,pre.length);
        result = {
            val:root,
            left:reConstructBinaryTree(preLeft,vinLeft),
            right:reConstructBinaryTree(preRight,vinRight),
        }   
    }else if(pre.length == 1){
        result = {
            val:pre[0],
            left:null,
            right:null,
        }
    }
    return result;
}

4、在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

//从数组的左下角开始比较查询
function Find(target,array){
    let lenX = array.length;
    let lenY = array[0].length;
    for(let i=lenX-1, j=0; i>=0 && j<lenY;){
        if(target > array[i][j]){
           j++;
        }else if(target < array[i][j]){
           i--; 
        }else{
            return true;
        }
    }
}

5、请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

//使用正则表达式,结合数组的replace方法
function replaceSpace(str)
{
    var reg = new RegExp(" ","g");
    var newstr = str.replace(reg,"%20");
    return newstr;
}

6、输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

//从头到尾依次将链表中的值插入数组中,以反序输出result数组即可
function printListFromTailToHead(head)
{
    var result = [];
    var n = head;
    while(n){
        result.push(n.val);
        n = n.next;
    }
    return result.reverse();
}

7、大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。

     n<=39

function Fibonacci(n)
{
    if(n==0){
        return 0;
    }
    if(n==1){
        return 1;
    }
    var Fibonacci = [0,1];
    for(var i=2;i<=n;i++){
        Fibonacci.push(Fibonacci[i-1]+Fibonacci[i-2]);
    }
    return Fibonacci.pop();
}

8、一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

//解题前一定要分析清楚!
//因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级
//跳1级,剩下n-1级,则剩下跳法是f(n-1)
//跳2级,剩下n-2级,则剩下跳法是f(n-2)
//所以f(n)=f(n-1)+f(n-2)+...+f(1)
//因为f(n-1)=f(n-2)+f(n-3)+...+f(1)
//所以f(n)=2*f(n-1)

function jumpFloorII(number)
{
    if(number<=1) return 1;
    return 2*jumpFloorII(number-1);
}

9、我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

//一种斐波那契数列的变形,可以通过枚举的方式寻找规律

function rectCover(number)
{
    if(number<=1) return number;
    var result = [1,1];
    for(var i=2;i<=number;i++){
        result[i] = result[i-1] + result[i-2];
    }
    return result[number];
}

10、输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

function reOrderArray(array)
{
    var oushu = [];
    var jishu = [];
    for(var i=0;i<array.length;i++){
        if(array[i]%2!==0){
            jishu.push(array[i]);
        }else{
            oushu.push(array[i]);
        }
    }
    return jishu.concat(oushu);
}

11、给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

function Power(base, exponent)
{
    return Math.pow(base,exponent);
}

12、输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

分析一下代码: 这段小小的代码,很是巧妙。

如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。

举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。

function NumberOf1(n)
{
    var count = 0;
    while(n != 0){
        count++;
        n = n&(n-1);
    }
    return count;
}

13、输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

function Merge(pHead1, pHead2)
{
    if(pHead1 == null){
        return pHead2;
    }else if(pHead2 == null){
        return pHead1;
    }
    var result = {};  //对象
    if(pHead1.val < pHead2.val){
        result = pHead1;//节点
        result.next = Merge(pHead1.next, pHead2);
    }else{
        result = pHead2;//节点
        result.next = Merge(pHead1, pHead2.next);
    }
    return result;
}

14、输入一个链表,反转链表后,输出新链表的表头。

function ReverseList(pHead)
{
    var curNode = pHead;
    var arr = [];
    while(curNode != null){
        arr.push(curNode.val);
        curNode = curNode.next;
    }
    curNode = pHead;   //反转
    while(curNode != null){
        curNode.val = arr.pop();
        curNode = curNode.next;
    }
   return pHead;
}

15、输入一个链表,输出该链表中倒数第k个结点。

function FindKthToTail(head, k)
{
    if(head == null){
        return false;
    }
    var curNode = head;
    var arr = [];
    while(curNode != null){
        arr.push(curNode);
        curNode = curNode.next;
    }
    return arr[arr.length-k];
}

16、操作给定的二叉树,将其变换为源二叉树的镜像。 

//使用递归的思想,依次交换左右子树

function Mirror(root)
{
    if(root == null){
        return root;
    }else{
        var temp;
        temp = root.left;
        root.left = root.right;
        root.right = temp;
        Mirror(root.left);
        Mirror(root.right);
    }
}

17、输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

function printMatrix(matrix)
{
    var m=matrix.length;
    var n=matrix[0].length;
    if(m==0||n==0){
        return res;
    }
    var res=[];
    var left=0,top=0,right=n-1,bottom=m-1;
    while(left<=right&&top<=bottom){
        for(var i=left;i<=right;i++){
            res.push(matrix[top][i]);
        }
        for(var i=top+1;i<=bottom;i++){
            res.push(matrix[i][right]);
        }
        if(top!=bottom){
            for(var i=right-1;i>=left;i--){
                res.push(matrix[bottom][i])
            }
        }
        if(left!=right){
            for(var i=bottom-1;i>top;i--){
                res.push(matrix[i][left])
            }
        }
        left++;
        right--;
        top++;
        bottom--;   
    }
    return res;
}

18、输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

【思路】借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。

举例:

入栈1,2,3,4,5

出栈4,5,3,2,1

首先1入辅助栈,此时栈顶1≠4,继续入栈2

此时栈顶2≠4,继续入栈3

此时栈顶3≠4,继续入栈4

此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3

此时栈顶3≠5,继续入栈5

此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3

….

依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。

function IsPopOrder(pushV, popV)
{
    var stack = [];  //辅助栈
    var idx = 0;
    for(var i=0;i<pushV.length;i++){ //遍历压入栈
        stack.push(pushV[i]);
        while(stack.length&&stack[stack.length-1]==popV[idx]){//当辅助栈不为空并且辅助栈的栈顶元素等于弹出栈的第idx个元素
            stack.pop();
            idx++;
        }
    }
    if(stack.length == 0){
        return true;
    }else{
        return false;
    }
}

19、从上往下打印出二叉树的每个节点,同层节点从左至右打印。

function PrintFromTopToBottom(root)
{
    var result = [];
    var arr = [];
    if(root!=null) {
        arr.push(root);
    }
    while(arr.length!=0){
        var node = arr.shift();
        if(node.left!=null){
            arr.push(node.left);
        }
        if(node.right!=null){
            arr.push(node.right);
        }
        result.push(node.val);
    }
    return result;
}

20、输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

//看了这么多,这种递归的思路虽说麻烦点,但是容易理解

function VerifySquenceOfBST(sequence)
{
    if( sequence.length == 0){
        return false;
    }
    var len = sequence.length;
    var root = sequence[len - 1];
    var left = [];
    var right = [];
    for(var i = 0; i < len - 1; i++){
        if( sequence[i] < root ){
            left.push( sequence[i] );
        }else{
            break;
        }
    }
    var j = i;
    for(; j < len - 1; j++){
        right.push( sequence[j] );
        if( sequence[j] < root ){
            return false;
        }
    }
    var isLeft = true;
    if( i > 0 ){
        isLeft = VerifySquenceOfBST(left);
    }
    var isRight = true;
    if( i < len - 1){
        isRight = VerifySquenceOfBST(right);
    }
    return (isLeft && isRight);
}

21、输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

var path = [];
var stack = [];
function FindPath(root, expectNumber)
{
    if (root == null) return [];
    stack = [];
    path = [];
    cal(root,expectNumber);
    return path ;
}
 
function cal(root,expectNumber) {
    stack.push(root.val);
    if (root.val == expectNumber && root.left == null   && root.right == null){
        path.push(stack.slice());
    }else{
        if(root.left!=null){
            cal(root.left,expectNumber-root.val);
        }
        if(root.right != null){
            cal(root.right,expectNumber-root.val);
        }
    }
    stack.pop(); /*这一步很关键,把所有push进去的每一个元素在递归执行完成之时都弹出来,使得stack每次都是重头来过。。*/
}

22、数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

function MoreThanHalfNum_Solution(numbers)
{
   //遍历arr,统计每个字母出现次数且记录位置
    var count = {};
    numbers.forEach(function(value, index){
        if(count[value]){
            count[value]++;
        }else {
            count[value] = 1;
        }
    });
    var max = 0;
    var letter;
    for(i in count){
        if(count[i] > max){
            max = count[i];
            letter = i;
        }
    }
    if(max>Math.floor(numbers.length/2)){
        return letter;
    } else{
        return 0;
    }
}

23、输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

function GetLeastNumbers_Solution(input, k)
{
    var result = [];
    //从小到大排序
    input.sort(function(x,y){
        return x-y;
    })
    //如果k大于数组长度,返回空数组
    if(k>input.length){
        return result;
    }
    //返回input数组的前k项
    return input.splice(0,k);
}

24、求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

function NumberOf1Between1AndN_Solution(n)
{
    var counts,num;
    counts = 0;
    if(n<1){
        return 0;
    }
    for(var i=1;i<=n;i++){
        num = i;
        while(num>0){
            if(num%10 == 1){
                counts++;
            }
            num = Math.floor(num/10);
        }
    }
    return counts;
}

25、把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

function GetUglyNumber_Solution(index)
{
    if(index == 0){
        return 0;
    }
    var uglyArr = [1], two = 0, three = 0, five = 0;
    for(var i=1;i<index;i++){
        uglyArr[i] = Math.min(uglyArr[two]*2,uglyArr[three]*3,uglyArr[five]*5);
        if(uglyArr[i]==uglyArr[two]*2){
            two++;
        }
        if(uglyArr[i]==uglyArr[three]*3){
            three++;
        }
        if(uglyArr[i]==uglyArr[five]*5){
            five++;
        }
    }
    return uglyArr[index-1];
}

26、在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).

function FirstNotRepeatingChar(str)
{
    for(let i=0;i<str.length;i++){
        if(str.indexOf(str[i]) == str.lastIndexOf(str[i])){
            return i;
        }
    }
    return -1;
}

27、在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

输入描述:

题目保证输入的数组中没有的相同的数字

数据范围:

对于%50的数据,size<=10^4

对于%75的数据,size<=10^5

对于%100的数据,size<=2*10^5

function InversePairs(data)
{
    if(!data||data.length<2) return 0;
  
    var copy = data.slice(),
        count = 0;
    count = mergeSort(data,copy,0,data.length-1);
    return count%1000000007;
}
  
function mergeSort(data,copy,start,end){
    if(end===start) return 0;
    var mid = (end-start)>>1,
        left = mergeSort(copy,data,start,start+mid),
        right = mergeSort(copy,data,start+mid+1,end),
        count = 0,
        p = start+mid,//前一个数组的最后一个下标
        q = end,//后一个数组的下标
        copyIndex = end;//辅助数组下标,从最后一个算起
  
    while(p>=start&&q>=start+mid+1){
        if(data[p]>data[q]){
            count+=q-start-mid;
            copy[copyIndex--] = data[p--];
        }else{
            copy[copyIndex--] = data[q--];
        }
    }
  
    while(p>=start){
        copy[copyIndex--] = data[p--];
    }
  
    while(q>=start+mid+1){
        copy[copyIndex--] = data[q--];
    }
    return left+right+count;
}

28、输入两个链表,找出它们的第一个公共结点。

function FindFirstCommonNode(pHead1, pHead2)
{
    var p1 = pHead1;
    var p2 = pHead2;
    while(p1!=p2){
        p1 = (p1 == null ? pHead2 : p1.next);
        p2 = (p2 == null ? pHead1 : p2.next);
    }
    return p1;
}

29、统计一个数字在排序数组中出现的次数。


//遍历数组,寻找与k相等的值,使得计数加1
function GetNumberOfK(data, k)
{
    var count = 0;
    for(var i=0;i<data.length;i++){
        if(data[i] == k){
            ++count;
        }
    }
    return count;
}

30、输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。


//递归思想,最后返回左子树和右子树中深度最大的值
function TreeDepth(pRoot)
{
    if(pRoot == null){
        return 0;
    }
    var left = TreeDepth(pRoot.left) + 1;
    var right = TreeDepth(pRoot.right) + 1;
    return Math.max(left,right);
}

31、输入一棵二叉树,判断该二叉树是否是平衡二叉树。

//平衡二叉树的性质:它是一棵空树或它的左右子树的高度差的绝对值不超过1,并且左右子树都是一棵平衡二叉树。
​//利用前边学习的二叉树的深度算法,运用递归的思想,运算左右两个子树
​
​function IsBalanced_Solution(pRoot)
{
    if(pRoot == null){
        return true;
    }
    if(Math.abs(TreeDepth(pRoot.left)-TreeDepth(pRoot.right))>1){
        return false;
    }else{
        return IsBalanced_Solution(pRoot.left)&&IsBalanced_Solution(pRoot.right);
    }
}
function TreeDepth(pRoot)
{
    if(pRoot == null){
        return 0;
    }
    var left = TreeDepth(pRoot.left) + 1;
    var right = TreeDepth(pRoot.right) + 1;
    return Math.max(left,right);
}

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

function FindNumsAppearOnce(array)
{
    var len = array.length;
    var list = [];
    for(var i=0;i<len;i++){
        if(array.indexOf(array[i]) == array.lastIndexOf(array[i])){
            list.push(array[i]);
        }
    }
    return list;
}
 

33、求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

function Sum_Solution(n)
{
    var result = n;
    result && (result += Sum_Solution(n-1));
    return result;
}

34、输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

输出描述:

对应每个测试案例,输出两个数,小的先输出。
//开始还在纠结乘积最小,后来转念一想,a+b=sum,a和b越远乘积越小,而一头一尾两个指针往内靠近的方法找到的就是乘积最小的情况。
//如果是乘积最大的情况就是一直找到两个指针重合,每次找到一个就将之前返回的结果向量清空然后更新为新找到的。

function FindNumbersWithSum(array, sum)
{
    if(array.length < 2){
        return [];
    }
    var start = 0,
        end = array.length-1; 
    while(start < end){
        if(array[start]+array[end] < sum){
            start++;
        }else if(array[start]+array[end] > sum){
            end--;
        }else{
            return [array[start],array[end]];
        }
    }
    return [];
}

35、汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

function LeftRotateString(str, n)
{ 
    if(str==null||str.length==0){
        return "";
    }
    n = n%str.length;
    return str.slice(n)+str.slice(0,n);
}

36、牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

function ReverseSentence(str)
{
    return str.split(" ").reverse().join(" ");
}

37、LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

//1、排序
//2、计算所有相邻数字间隔总数 
//3、计算0的个数 
//4、如果2、3相等,就是顺子 
//5、如果出现对子,则不是顺子
function IsContinuous(numbers)
{
    if(numbers.length==0){
        return false;
    }
    numbers.sort((a,b)=>{
        return a-b;
    });
    var zeroCount = 0;//0的个数
    var sum = 0;//所有相邻数字间隔总数 
    for(var i=0; i<numbers.length-1; i++){
        if(numbers[i] == 0){
            zeroCount++;
        }else if(numbers[i] == numbers[i+1]){
            return false;
        }else{
            sum += numbers[i+1]-numbers[i]-1; //相邻数字间隔数
        }
    }
    if(zeroCount>=sum){
        return true;
    }
    return false;
}

38、每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

function LastRemaining_Solution(n, m)
{
    if(n==0)
        return -1;
    if(n==1)
        return 0;
    else
        return (LastRemaining_Solution(n-1,m)+m)%n;
}

39、在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

function duplicate(numbers, duplication)
{
    // write code here
    //这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    //函数返回True/False
    if(numbers.length<=1){
        return false;
    }
    numbers.sort();
    for(var i=0;i<numbers.length;i++){
        if(numbers[i] == numbers[i+1]){
            duplication[0] = numbers[i];
            return true;
        }
    }
    return false;
    
}

40、给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。

//用两个for循环来实现外层数组对内层数组的遍历乘法
function multiply(array)
{
    if(array.length == 0){
        return false;
    }
    var list = [];
    for(var j=0;j<array.length;j++){
        list[j] = 1;
        for(var i=0;i<array.length;i++){
            if(i!=j){
                list[j] *= array[i];
            }
        }
    }
    return list;
}

41、请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

function isNumeric(s)
{
      return !isNaN(Number(s));
}

42、在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function deleteDuplication(pHead)
{
    if(pHead == null || pHead.next == null){
        return pHead; //只有0个或1个结点,则返回
    }
    if(pHead.val == pHead.next.val){//当前结点是重复结点
        var pNode = pHead.next;
        while(pNode!=null && pNode.val==pHead.val){
            //跳过值与当前结点相同的全部结点,找到第一个与当前结点不同的结点
            pNode = pNode.next;
        }
        return deleteDuplication(pNode);//从第一个与当前结点不同的结点开始递归
    }else{//当前结点不是重复结点
        pHead.next = deleteDuplication(pHead.next);//保留当前结点,从下一个结点开始递归
        return pHead;
    }
}
    
   

43、请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function isSymmetrical2(root1, root2){
    if(root1 == null && root2 == null){
        return true;
    }
    if(root1 == null || root2 == null){
        return false;
    }
    if(root1.val != root2.val){
        return false;
    }
    return isSymmetrical2(root1.left, root2.right) && isSymmetrical2(root1.right, root2.left);
}

function isSymmetrical(pRoot)
{
    // write code here
    return isSymmetrical2(pRoot, pRoot);
}

44、请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function Print(pRoot)
{
    var lists = [];
    if(pRoot==null){
        return lists;
    }
    var stack1 = [];//奇数行,行数从0开始
    var stack2 = [];//偶数行
    stack2.push(pRoot);
    var i=1;
    while(stack1.length!=0 || stack2.length!=0){
        var list = [];
        //为奇数层
        if((i & 1) == 1){
            while(stack2.length!=0){
                var tmp = stack2[stack2.length-1];
                stack2.pop();
                list.push(tmp.val);
                if(tmp.left!=null)
                    stack1.push(tmp.left);
                if(tmp.right != null)
                    stack1.push(tmp.right);
            }
        }
        //为偶数层
        else{
            while(stack1.length!=0){
                var tmp = stack1[stack1.length-1];
                stack1.pop();
                list.push(tmp.val);
                if(tmp.right != null)
                    stack2.push(tmp.right);
                if(tmp.left != null)
                    stack2.push(tmp.left);
            }
        }
        ++i;
        lists.push(list);
    }
    return lists;
}

45、从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function Print(pRoot)
{
    if(pRoot==null){
        return [];
    }
    var queue = [],
        result = [];
    queue.push(pRoot);
    while(queue.length){//如果根节点不为空
        var len = queue.length;
        var tempArr = [];
        for(var i=0;i<len;i++){
            var temp = queue.shift();
            tempArr.push(temp.val);//tempArr暂时存放结点序列
            if(temp.left){//一层一层的递归实现当前根节点的左子树
                queue.push(temp.left);
            }
            if(temp.right){//一层一层的递归实现当前根节点的右子树
                queue.push(temp.right);
            }
        }
        result.push(tempArr);
    }
    return result;
}

46、请实现两个函数,分别用来序列化和反序列化二叉树

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
var arr=[];
function Serialize(pRoot)
{
    // write code here
    if(pRoot==null){
        arr.push("$");
    }else{
        arr.push(pRoot.val);
        Serialize(pRoot.left);
        Serialize(pRoot.right)
    }
 
}
function Deserialize(s)
{
    // write code here
    var node=null;
    if(arr.length<1){
        return null
    }
    var number=arr.shift()//获取根节点
    if(typeof number=='number'){
        node = new TreeNode(number);
        node.left = Deserialize(arr);
        node.right = Deserialize(arr);
    }
    return node
}

47、如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

var arr = [];
function Insert(num)
{
    arr.push(num);
    return arr;
}
function GetMedian(){
    arr.sort();
    var midIndex = parseInt(arr.length/2);
    if(arr.length%2==0){
        return (arr[midIndex-1]+arr[midIndex])/2;
    }else{
        return arr[midIndex];
    }
}

48、给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

function maxInWindows(num, size)
{
    if(size==0){
        return [];
    }
    var count = num.length - size;
    var result = [];
    for(var i=0;i<=count;i++){
        var temp = num.slice(i,i+size);
        result.push(Math.max.apply(this,temp));
    }
    return result;
}

每日一练,后续积累哦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值