剑指offer

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

function Find(target, array)
{
    // write code here
    var arr=array.toString().split(",").map((item)=>{return parseInt(item)})//扁平化
    var norepeatArr=Array.from(new Set(arr));
    if(norepeatArr.indexOf(target)!=-1){
        return true;
    }
    else
        return false;
}

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

function replaceSpace(str)
{
  var reg=/\s/g;
  return str.replace(reg,"%20");
}

3.输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

function printListFromTailToHead(head)
{
    // write code here
    var ArrayList=[];
    while(head){
        ArrayList.push(head.val);
        head=head.next;
    }
    return ArrayList.reverse();
}

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

function reConstructBinaryTree(pre, vin)
{
    // write code here
 
    if(pre.length>0){
        var result=null;
        var root=pre[0];
        var vinIndex=vin.indexOf(root);
        var vinLeft=vin.slice(0,vinIndex);
        var vinRight=vin.slice(vinIndex+1);
        pre.shift();
        var preLeft=pre.slice(0,vinLeft.length);
        var preRight=pre.slice(vinLeft.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;
}

5.用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

function push(node)
{
    // write code here
    //栈是后入先出(LIFO),队列是先入先出(FIFO)
    //模拟队列的push操作,直接往栈中推入即可
    //但是要考虑辅助栈中还存在值的情况,需要先将辅助栈中的值推回存储栈中
    while(stack2.length!=0){
        stack1.push(stack2.shift())
    }
    return stack1.push(node)
}
function pop()
{
    // write code here
    //模拟队列的pop操作则要考虑栈的后入先出特性,需要先将存储栈中的数组,推入辅助栈,然后辅助栈弹出
    while(stack1.length!=0){
        stack2.push(stack1.pop())
    }
    return stack2.pop()
}

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

function Fibonacci(n)
{  
  if(n==0) return 0;
  if(n==1) return 1;
    if(n>=2){
        var f1=0;
        var f2=1;
        for(var i=2;i<=n;i++){
            fn=f1+f2;
            f1=f2;
            f2=fn;
        }
        return fn;
    }

7.一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

function jumpFloor(number)
{
    if(number==1) return 1;
    if(number==2) return 2;
    if(number>2) return jumpFloor(number-1)+jumpFloor(number-2)
}

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

function jumpFloorII(number)
{
   return a=Math.pow(2,number-1)
}

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

function rectCover(number)
{
    // write code here
    if(number==0)
    {
        return 0
    }
    else if(number==1){
        return 1
    }
    else if(number==2){
        return 2        
    }
    else{
        return (rectCover(number-1)+rectCover(number-2))
    }
}

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

//一个整数位与1相与之后,如果是1则该位1,否则为0,然后将1往左移动继续循环判断
function NumberOf1(n)
{
    // write code here
    var count = 0,flag=1;
    while(flag){
        if(n&flag)count++;
        flag=flag<<1;
    }
    return count;
}

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

function Power(base, exponent)
{
    // write code here
    return Math.pow(base,exponent)
}

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

function reOrderArray(array)
{
    // write code here
    var len=array.length;
    var resultleft=[];
    var resultright=[];
    for(var i=1;i<=len;i++){
        if(array[i-1]%2==0){
            resultright.push(array[i-1]);
        }
        else
            resultleft.push(array[i-1]);
    }
    return resultleft.concat(resultright)
}

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

function FindKthToTail(head, k)
{
 if (head == null || k <= 0) {
                    return null;
    }
    var count=0;
    var value=head;
    var result=head;
    while(value){
        count=count+1;
        value=value.next;
    }
    if(count<k){return null;}
    for(var i=0;i<count-k;i++){
        result=result.next;
    }
    return result
}

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

function ReverseList(pHead)
{
    var value=pHead;
    var value02=pHead;
    var arr=[];
    while(value!=null){
        arr.unshift(value.val);
        value=value.next;
    }//转换为数组,并不是链表
    while(value02){
        value02.val=arr.shift();
        value02=value02.next;
    }
    return pHead;
}

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

function Merge(pHead1, pHead2)
{
   if(!pHead1) return pHead2;
   if(!pHead2) return pHead1;
   var result=new ListNode();
   var cur=result;
    while(pHead1&&pHead2){
        if(pHead1.val<pHead2.val){
            cur.next=pHead1;
            pHead1=pHead1.next;
            cur=cur.next;
        }
        else{
            cur.next=pHead2;
            pHead2=pHead2.next;
            cur=cur.next;
        }
        
    }
    if(pHead1)
        cur.next=pHead1
    if(pHead2)
        cur.next=pHead2
    return result.next
}

16.输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

function isSubtree(root1, root2) {
    if(root2==null) return true;
    if(root1==null) return false;
    if(root1.val==root2.val){
        return isSubtree(root1.left, root2.left) &&
            isSubtree(root1.right, root2.right);
    }
    else
    {return false}
}

function HasSubtree(pRoot1, pRoot2)
{
  if(pRoot1==null) return false;
  if(pRoot2==null) return false;
    return isSubtree(pRoot1, pRoot2) ||
        HasSubtree(pRoot1.left, pRoot2) ||
        HasSubtree(pRoot1.right, pRoot2);
}

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

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

18.输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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)
{
    // write code here
    var row=matrix.length;
    var col=matrix[0].length;
    var res=[];
    if(row==0||col==0){
        return res;
    }
    var left=0,
        top=0,
        right=col-1,
        bottom=row-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++,top++,right--,bottom--;
    }
    return res;
}

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

function IsPopOrder(pushV, popV)
{
    var stack=[];
    var index=0;
    for(var i=0;i<pushV.length;i++){
        stack.push(pushV[i]);
        while(stack.length&&stack[stack.length-1]===popV[index])
        {
            stack.pop();
            index++;
        }
    }
    return stack.length===0;
}

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

function PrintFromTopToBottom(root)
{
    // write code here
    var arr=[];
    var data=[];
    if(root){
        arr.push(root)
    }
    while(arr.length){
        var node=arr.shift();
        if(node.left){
            arr.push(node.left)
        }
        if(node.right){
            arr.push(node.right)
        }
        data.push(node.val)
    }
    return data;
}

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

//解题思路就是因为二叉搜索树的左子树的值都是小于根的,右子树的值都是大于根的,可以通过这个特点来进行求解
function VerifySquenceOfBST(sequence){
    if(!sequence.length){
        return false
    }
    return adjustSequence(sequence,0,sequence.length)
}
function adjustSequence(sequence,start,end){
    if(start>end){
        return true
    }
    var i = start;
    while(i<end && sequence[i]<sequence[end]){
        i++
    }
    for(var j=i;j<end;j++){
        if(sequence[j]<sequence[end]){
            return false
        }
    }
    return adjustSequence(sequence,0,i-1) && adjustSequence(sequence,i,end-1)
}

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

const FindPath = (root, expectNumber) => {
    if(!root) return [];
    const result = [];
    const temp = [];
    calSum(root, 0, temp);
    function calSum(data,total,output){
        total += data.val;
        temp.push(data.val);
        if(total == expectNumber && data.left == null && data.right == null) result.push(temp.slice(0));
        if(data.left!=null) calSum(data.left, total, output);
        if(data.right!=null) calSum(data.right, total, output);
        temp.pop();
    }
    return result;
};

23.HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

function FindGreatestSumOfSubArray(array)
{
    // write code here
    if(array.length <= 0) return 0;
    var max = array[0];
    var pre = array[0];
    for(var i = 1;i<array.length;i++){
        if(pre < 0)
        pre = 0;
        max = Math.max(max, pre+array[i]);
        pre = pre+array[i];
    }
    return max;
}

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

function NumberOf1Between1AndN_Solution(n)
{
    var arr=[];
    if(n==0) return 0;
    if(n==1) return 1;
    for(var i=2;i<=n;i++){
        arr.push(i);
    }
    var arrString=arr.join("");
    if(arrString.indexOf("1")==-1) return 1;
    var onearr=arrString.split("1");
    return onearr.length;
}

25.输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

function PrintMinNumber(numbers)
{
    // write code here
    numbers.sort(compare);
    var result = "";
    for(var i = 0; i < numbers.length; i++){
        result += numbers[i];
    }
    return result;
     
}
 
function compare(a, b){
    var str1 = a + "" + b;
    var str2 = b + "" + a;
    for(var i = 0; i < str1.length; i++){
        if(str1.charAt(i) > str2.charAt(i)){
            return 1;
        }
        if(str1.charAt(i) < str2.charAt(i)){
            return -1;
        }
    }
    return 1;
}

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

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;
}

27.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。

function IsContinuous(numbers)
{
    // write code here
    if(numbers.length==0)
        return false;
    var arr=numbers.sort();
    var zero=[];
    var value=[];
    for(var i=0;i<arr.length;i++){
        if(arr[i]==0){
            zero.push(0);
        }
        else{
            value.push(arr[i]);
        }
    }
    var len=zero.length;
    var i=1;
    for(var j=0;j<value.length-1;j++){
        while(value[j]+i!=value[j+1])
        {
            if(len>0){len=len-1;i=i+1}
            else
            return false;
        }
    }
    return true;
}

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

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

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

function Sum_Solution(n)
{
    // write code here
    return n*(n+1)/2
}

如果只求最后一个报数胜利者的话,我们可以用数学归纳法解决该问题,为了讨 论方便,先把问题稍微改变一下,并不影响原意:
问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人 继续从0开始报数。求胜利者的编号。
我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新 的约瑟夫环(以编号为k=m%n的人开始):
k k+1 k+2 … n-2, n-1, 0, 1, 2, … k-2并且从k开始报0。
现在我们把他们的编号做一下转换:
k --> 0
k+1 --> 1
k+2 --> 2


k-2 --> n-2
k-1 --> n-1
变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解: 例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情 况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x’=(x+k)%n。
令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]。
递推公式
f[1]=0;
f[i]=(f[i-1]+m)%i; (i>1)
有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。 因为实际生活中编号总是从1开始,我们输出f[n]+1。
30.写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

function Add(num1, num2)
{
    // write code here
    while(num2!=0){
         var temp=num1^num2
         num2=(num1&num2)<<1
         num1=temp
    }
    return num1
}

31.将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0

function StrToInt(str)
{
    // write code here
    var reg_1=/[a-z]/g;
    if(reg_1.test(str))return 0;
    var reg_2=/[A-Z]/g;
    if(reg_2.test(str))return 0;
    var reg_3=/\s/g;
    if(reg_3.test(str))return 0;
    if(str==""||str=="+"||str=="-")return 0;
    if(parseInt(str)<=-2147483649||parseInt(str)>=2147483648) return 0;
    return parseInt(str);
}

**32.给定一个数组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]。不能使用除法。

function multiply(array)
{
    // write code here
    var result=[];
    var mult=1;
    for(var i=0;i<array.length;i++){
        var changeArray=array.slice(0,i).concat(array.slice(i+1));
        for(var j=0;j<changeArray.length;j++)
            mult=mult*changeArray[j];
            result.push(mult);
            mult=1;
    }
    return result;
}

33.请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配

function match(s, pattern)
{
    // write code here
    var reg=new RegExp("^" + pattern + "$");
    return reg.test(s);
}

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

function isNumeric(s)
{
    // write code here
    return s.match(/[+-]?\d*(\.\d*)?([eE][+-]?\d+)?/g)[0] === s
}

35.给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

function EntryNodeOfLoop(pHead)
{
    // write code here
    if(pHead == null || pHead.next == null) return null
    var p1 = pHead;
    var p2 = pHead;
    var flag = true;
    while(flag) {
        p1 = p1.next;
        p2 = p2.next.next;
        if(p1 === p2) {
            flag = false;
        }
    }
    p2 = pHead
    flag = true;
    while (flag) {
        if (p2 === p1) {
            return p2
        } else {
            p1 = p1.next;
            p2 = p2.next;
        }
    }
}
设置快慢指针,都从链表头出发,快指针每次走两步,慢指针一次走一步,假如有环,一定相遇于环中某点(结论1)。接着让两个指针分别从相遇点和链表头出发,两者都改为每次走一步,最终相遇于环入口(结论2)。以下是两个结论证明:
两个结论:
1、设置快慢指针,假如有环,他们最后一定相遇。
2、两个指针分别从链表头和相遇点继续出发,每次走一步,最后一定相遇与环入口。
证明结论1:设置快慢指针fast和low,fast每次走两步,low每次走一步。假如有环,两者一定会相遇(因为low一旦进环,可看作fast在后面追赶low的过程,每次两者都接近一步,最后一定能追上)。
证明结论2:
设:
链表头到环入口长度为--a
环入口到相遇点长度为--b
相遇点到环入口长度为--c

在这里插入图片描述
36.在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

function deleteDuplication(pHead)
{
    // write code here
    var newHead = new ListNode('head');
    newHead.next = pHead;
    var pHead = newHead;
    var qHead = pHead.next;
    while(qHead) {
        while((qHead.next!=null) && (qHead.val == qHead.next.val)) {
            qHead = qHead.next;
        }
        //没移动
        if(pHead.next == qHead) {
            pHead = qHead;
            qHead = qHead.next;
             
        }
        //移动了
        else {
            qHead = qHead.next;
            pHead.next = qHead;
             
        }
         
    }
    return newHead.next;
}

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

function isSymmetrical(pRoot)
{
    // write code here
    if(pRoot==null){
        return true
    }
    return judge(pRoot.left,pRoot.right)
}
function judge(left,right){
    if(left==null){return right==null}
    if(right==null){return false}
    if(left.val!=right.val){return false}
    return judge(left.left,right.right)&&judge(left.right,right.left)
}

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

function Print(pRoot)
{
    // write code here
    if(!pRoot){
        return [];
    }
    var queue = [],
        result = [],
        flag=true;
    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);
            if(temp.left){
                queue.push(temp.left);
            }
            if(temp.right){
                queue.push(temp.right);
            }
        }
        if(!flag){
            tempArr.reverse();
        }
        flag = !flag;
        result.push(tempArr);
    }
    return result;
}

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

function Print(pRoot)
{
    // write code here
     if(!pRoot){
        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);
            if(temp.left){
                queue.push(temp.left);
            }
            if(temp.right){
                queue.push(temp.right);
            }
        }
        result.push(tempArr);
    }
    return result;
}

40.给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。

function KthNode(pRoot, k) 
{
    // write code here
    if(k<=0){
        return null;
    }
    var count=0;
    function Knodes(pRoot, k){
        if(pRoot!==null){
            var node = Knodes(pRoot.left, k);
            if(node!==null){return node;}
            count++;
            if(count==k){return pRoot;}
            node = Knodes(pRoot.right, k)
            if(node!==null){return node;}
        }
        return null;
    }
    return Knodes(pRoot,k);
}

41.地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

function movingCount(threshold, rows, cols)
{
    // write code here
    var visited = [];
      for (var i = 0; i < rows; i++) {
        visited.push([]);
        for (var j = 0; j < cols; j++) {
          visited[i][j] = false;
        }
      }
      return moveCount(threshold, rows, cols, 0, 0, visited);
}
 
    function moveCount(threshold, rows, cols, row, col, visited) {
      if (row < 0 || row == rows || col < 0 || col == cols || visited[row][col]) {
        return 0;
      }
      var sum = 0;
      var temp = row + "" + col;
      for (var i = 0; i < temp.length; i++) {
        sum += temp.charAt(i) / 1;
      }
      if (sum > threshold) {
        return 0
      }
      visited[row][col] = true;
      return 1 + moveCount(threshold, rows, cols, row, col - 1, visited) +
        moveCount(threshold, rows, cols, row, col + 1, visited) +
        moveCount(threshold, rows, cols, row - 1, col, visited) +
        moveCount(threshold, rows, cols, row + 1, col, visited);
    
}

42.给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

function cutRope(number)
{
    // write code here
    var result=1;
    if(number==2)
        return 1
    if(number==3)
        return 2
    if(number==4)
        return 4
    while(number){
            if(number>=3)
            {
             result=result*3;
             number=number-3;
            }
        else if(number==2){
             result=result*2;
             number=number-2;
        }
        else{
            number=number-1;
        }
            
        }
    return result;
}

43.小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!

1)由于我们要找的是和为S的连续正数序列,因此这个序列是个公差为1的等差数列,而这个序列的中间值代表了平均值的大小。假设序列长度为n,那么这个序列的中间值可以通过(S / n)得到,知道序列的中间值和长度,也就不难求出这段序列了。
2)满足条件的n分两种情况:
n为奇数时,序列中间的数正好是序列的平均值,所以条件为:(n & 1) == 1 && sum % n == 0;
n为偶数时,序列中间两个数的平均值是序列的平均值,而这个平均值的小数部分为0.5,所以条件为:(sum % n) * 2 == n.
3)由题可知n >= 2,那么n的最大值是多少呢?我们完全可以将n从2S全部遍历一次,但是大部分遍历是不必要的。为了让n尽可能大,我们让序列从1开始,
根据等差数列的求和公式:S = (1 + n) * n / 2,得到。
for (int n = (int) Math.sqrt(2 * sum); n >= 2; n--) {
            if ((n & 1) == 1 && sum % n == 0 || (sum % n) * 2 == n) {
                ArrayList<Integer> list = new ArrayList<>();
                for (int j = 0, k = (sum / n) - (n - 1) / 2; j < n; j++, k++) {
                    list.add(k);
                }
                ans.add(list);
            }
        }
        return ans;

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

function TreeDepth(node) {
    if(node == null) {
        return 0;
    }
    let left = TreeDepth(node.left);
    let right = TreeDepth(node.right);
    //return left > right ? left+1 : right+1; // 不要写成left++,  right++
    if(left>right){left=left+1;
                  return left;}
    else{right=right+1;
        return right;
        }
}

在这里插入图片描述
43.平衡二叉树

	var isBalanced = function(root) {
	    if (!root) return true;
	    if (Math.abs(depth(root.left)-depth(root.right))>1) return false; 
	    return isBalanced(root.left) && isBalanced(root.right);  
	    function depth(node){
	        if (!node) return 0;
	        var left = depth(node.left);
	        var right = depth(node.right);
	        return Math.max(left, right)+1;
	    }
	};

在这里插入图片描述
44.和为S的连续正数序列
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!

function FindContinuousSequence(sum)
{
    // write code here
    let low=1;
    let hight=2;
    let list=[];
    let result=[];
    while(hight>low){
        //由于是连续的,差为1的一个序列,那么求和公式(a0+an)*n/2
        let cur=(low+hight)*(hight-low+1)/2;
        if(cur==sum){
            for(let i=low;i<=hight;i++){
                list.push(i);
            }
            result.push(list);
            list=[];
            low=low+1;
        }
        //如果当前窗口内的值之和小于sum,那么右边窗口右移一下
        else if(cur<sum){
            hight=hight+1;
        }
        //如果当前窗口内的值之和大于sum,那么左边窗口右移一下
        else if(cur>sum){
            low=low+1;
        }
    }
    return result
}

45.不用加减乘除做加法
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

function Add(num1, num2)
{
    // write code here
    while(num2!=0){
         var temp=num1^num2//各位相加但不计进位,异或
         num2=(num1&num2)<<1//记下进位
         num1=temp
    }
    return num1
}

46.二叉搜索树中第k小的元素

var kthSmallest=function(root,k){
    let res=[];
    const inorder=function(root){
        if(root){
            inorder(root.left);
            res.push(root.val);
            inorder(root.right);
         }
    }
    inorder(root);
    return res[k-1];
}

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

function deleteDuplication(pHead)
{
    if(pHead===null||pHead.next===null){
        return pHead;
    }
    const Head=new ListNode(0);
    Head.next=pHead;
    let pre=Head;
    let cur=Head.next;
    while(cur!==null){
        if(cur.next!==null && cur.val===cur.next.val){
            while(cur.next!==null&&cur.val===cur.next.val){
                cur=cur.next;
            }
            pre.next=cur.next;
            cur=cur.next;
        }
        else{
            pre=pre.next;
            cur=cur.next;
        }
    }
    return Head.next;
}

48.真分数分解为埃及分数
分子为1的分数称为埃及分数。现输入一个真分数(分子比分母小的分数,叫做真分数),请将该分数分解为埃及分数。如:8/11 = 1/2+1/5+1/55+1/110。

var readline=require("readline");
const rl=readline.createInterface({
    input:process.stdin,
    output:process.stdout
});
 
rl.on('line',function(line){
    var arr = line.trim().split('\/');
    var a = parseInt(arr[0]);//分子
    var b = parseInt(arr[1]);//分母
    var res = [];
     while (a!=1){
        if(b%(a-1)==0){
            res.push("1/"+parseInt(b/(a-1)));
            a = 1;
        }else{
            var c = parseInt(b/a)+1;
            a = a - b%a;
            b = b * c;
            res.push("1/"+c);
            if(b%a == 0){
                b = b/a;
                a = 1;
            }
        }
 
    }
    res.push("1/"+b);
    console.log(res.join("+"));
});

49.Shopee物流会有很多个中转站。在选址的过程中,会选择离用户最近的地方建一个物流中转站。
假设给你一个二维平面网格,每个格子是房子则为1,或者是空地则为0。找到一个空地修建一个物流中转站,使得这个物流中转站到所有的房子的距离之和最小。 能修建,则返回最小的距离和。如果无法修建,则返回 -1。

let readline=require("readline");
rl=readline.createInterface({
    input:process.stdin,
    output:process.stdout
})
let inputs=[];
let count=0;
let num=0;
rl.on("line",function(data){
    if(count==0)
    {num=parseInt(data);}
     count=count+1;
     if(count>1)
     {inputs.push(data.split(" ").map((item)=>{return parseInt(item)}))}
    if(inputs.length==num){
        main(num,inputs)
    }   
})
function main(num,inputs){
     let zeroxy=[];
     let zero=[];
     let onexy=[];
     let one=[];
     let result=[];
     let x=0;
     let y=0;
     let sum=0;
    /*
    //分开空地和建筑
    */
    for(let i=0;i<num;i++){
        for(let j=0;j<num;j++){
            if(inputs[i][j]==0){
                zeroxy.push(i);
                zeroxy.push(j);
                zero.push(zeroxy);
                zeroxy=[];
            }
            else{
                onexy.push(i);
                onexy.push(j);
                one.push(onexy);
                onexy=[];
            }
        }
    }
    /*每个建筑到空地路径放到result*/
    for(let i=0;i<zero.length;i++){
        for(let j=0;j<one.length;j++){
            x=Math.abs(zero[i][0]-one[j][0]);
            y=Math.abs(zero[i][1]-one[j][1]);
            sum=sum+x+y;
        }
        result.push(sum);
        sum=0;
    }
   console.log(Math.min(...result));//求出最小的。
}

50.在Linux Shell命令下通配符’‘表示0个或多个字符, 现编写一段代码实现通配符’‘的功能,注意只需要实现’’, 不用实现其他通配符。
第一行输入通配字符串
第二行输入要匹配查找的字符串
输出所有匹配的字串起始位置和长度,每行一个匹配输出
如果不匹配,则输出 -1 0
如果有多个按照起始位置和长度的正序输出。
shopee
.com
shopeemobile.com
0 16

let readline=require("readline");
rl=readline.createInterface({
    input:process.stdin,
    output:process.stdout
})
let inputs=[];
var arr_01=[];
var arr_02=[];
var result=[];
rl.on("line",function(data){
    inputs.push(data);
    if(inputs.length==2){
        main(inputs)
    }
})
function DFS(i,j){
    if(j==arr_01.length){
        result.push(i);
    }
    if(i==arr_02.length){
        return;
    }
    if(arr_02[i]==arr_01[j]){
        DFS(i+1,j+1);
    }
    else if(arr_01[j]=="*"){
        DFS(i,j+1);
        DFS(i+1,j);
    }
    return;
}
function main(inputs){
    arr_01=inputs[0];
    arr_02=inputs[1];
    let flag=true;
    for(let i=0;i<arr_02.length;i++){
        if(arr_02[i]==arr_01[0]||arr_01[0]=="*"){
            DFS(i,0);
            if(result.length){
                flag=false;
                for(let j=0;j<result.length;j++){
                    if(arr_01[0]=="*"&&arr_01.length==1)
                        console.log(i,result[j]-i+1);
                    else{
                        console.log(i,result[j]-i);}
                }
            }
            result=[];
        }
    }
    if(flag)
    console.log(-1,0);
}

将后缀表达式转为中缀表达式

function calculate(RPolishArray){
    var result = 0;
    var tempArray = new Array(100);
    var tempNum = -1;
    for(i = 0;i < RPolishArray.length;i++){
        if(RPolishArray[i].match(/\d/)){
            tempNum++;
            tempArray[tempNum] = RPolishArray[i];
        }else{
            switch(RPolishArray[i]){
                case '+':
                    result = "("+(tempArray[tempNum-1]) +"+"+ (tempArray[tempNum])+")";
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
                case '-':
                    result = "("+(tempArray[tempNum-1] )+"-"+(tempArray[tempNum] )+")";
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
                case '*':
                    result = "("+(tempArray[tempNum-1]) +"*"+ (tempArray[tempNum])+")";
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
                case '/':
                    result = "("+(tempArray[tempNum-1])+" /"+ (tempArray[tempNum])+")";
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
            }
        }
    }
    result = tempArray[tempNum];    
    return result.substring(1,result.length-1);  
}
console.log(calculate("1,2,3,4,-,*,+"))

将后缀表达式转为中缀表达式将结果计算出来

function calculate(RPolishArray){
    var result = 0;
    var tempArray = new Array(100);
    var tempNum = -1;
    for(i = 0;i < RPolishArray.length;i++){
        if(RPolishArray[i].match(/\d/)){
            tempNum++;
            tempArray[tempNum] = RPolishArray[i];
        }else{
            switch(RPolishArray[i]){
                case '+':
                    result = (tempArray[tempNum-1] *1) + (tempArray[tempNum] * 1);
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
                case '-':
                    result = (tempArray[tempNum-1] *1) - (tempArray[tempNum] * 1);
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
                case '*':
                    result = (tempArray[tempNum-1] *1) * (tempArray[tempNum] * 1);
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
                case '/':
                    result = (tempArray[tempNum-1] *1) / (tempArray[tempNum] * 1);
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
            }
        }
    }
    result = tempArray[tempNum];    
    return result;  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值