JS版剑指Offer

旧城冷巷雨未停 提交于 2020-01-16 08:43:34
这篇是整理了一部分刷的算法题的大概解题思路,怕自己以后忘记,后续还会更新。

其中解题思路也会在代码中的注释有体现
二维数组中的查找
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

//因为每一行从左到右递增,从上到下递增,所以右上角的数是整个二维数组最大的数
//所以从右上角的数开始比较比target大就行数减一,比target小就列数加一
function Find(target, array)
{
    if(array.length==0||array==undefined||array[0].length==0)
      return false;
      let rows=array.length;
      let cols=array[0].length;
      let row=0;
      let col=cols-1;
      while(row<rows&&col>=0){
        if(array[row][col]==target)
           return true;
        if(array[row][col]>target)
           col--;
        if(array[row][col]<target)
           row++;
      }
}

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

function replaceSpace(str)
{
    return str.replace(/ /g,'%20')
}

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

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function printListFromTailToHead(head)
{
    if(head==undefined) {   //判断链表是否为空
        return 0;
    } else{
        var arr=new Array();  // 新建一个数组,用于存放链表中的数值
        var curr=head;        // 创立一个指针,遍历链表
        while(curr){
            arr.push(curr.val);
            curr=curr.next;
        }
        return arr.reverse();
    }
}

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

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
// 前序是根 左 右   在前序中找根
// 中序是左 根 右   在中序中找左右子树
// 在左右子树中以同样的方法找根和左右子树
// 知道遍历到某个子树的左右子树长度为0停止
function reConstructBinaryTree(pre, vin)
{
    // write code here
    if(pre.length==0&&vin.length==0) {
        return null;
    }
    var index = vin.indexOf(pre[0]);  // 返回根节点在中序遍历中的位置
    var left = vin.slice(0,index);    // 以根节点为界限找出左子树
    var right = vin.slice(index+1);   // 以根节点为界限找出右子树
    var root=new TreeNode(pre[0]);    // 新建二叉树
    root.left=reConstructBinaryTree(pre.slice(1,index+1),left);   // 运用递归
    root.right=reConstructBinaryTree(pre.slice(index+1),right);
    return root;
}

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

var stack1=new Array();
var stack2=new Array();
//栈的特点是后进先出,队列的特点是先进先出
function push(node)  
{
    stack1.push(node);  // 先进
}
function pop()
{
    var temp=stack1.pop();
    while(temp){           // stack1中先入的的数在stack2中的顶部
        stack2.push(temp);
        temp=stack1.pop();
    }
    var result=stack2.pop();   // 此时Stack2中顶部的数已经弹出
    temp=stack2.pop();         
    while(temp){              // 将Stack2 中的数再依次压入stack1中
        stack1.push(temp);
        temp=stack2.pop();
    }
    return result;
}

旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

function minNumberInRotateArray(rotateArray)
{
    if(rotateArray.length==0){
        return 0
    }
    //其中第一个参数null,这个是因为没有对象去调用这个方法,所以直接传递null过去
    return Math.min.apply(null,rotateArray);
}

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

// 斐波那契数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144........
// 从第3项开始,每一项都等于前两项之和

function Fibonacci(n)
{
    if(n<0||n>39){
        return;
    }
    if(n==0){
        return 0;
    }
    if(n==1){
        return 1;
    }
    var fone=0;
    var ftwo=1;
    var fn=0;
    for(var i=2;i<=n;i++){
        fn=fone+ftwo;
        fone=ftwo;
        ftwo=fn;
    }
    return fn;
}

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

// 如果只有1级台阶,那显然只有一种跳法。
// 如果有2级台阶,那就有两种跳法:一种是分两次跳,每次跳1级;另一种就是一次跳2级。
// f(1)=1  f(2)=2  f(3)=3  f(4)=5  f(n)=f(n-1)+f(n-2)
// 用到递归
function jumpFloor(number)
{
    // write code here
    if(number==1){
        return 1;
    }
    if(number==2){
        return 2;
    }
    if(number<0){
        return 0;
    }
    var jn=jumpFloor(number-1)+jumpFloor(number-2);
    return jn;
}

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

// 如果只有一层台阶,有一种跳法
// 如果有两层台阶,有两种跳法
// 如果有三层台阶,有四种跳法
// 当n>1时,第一次跳有n种选择,第二次跳有n-1种选择
// f(n)=f(n-1)+f(n-2)+...+f(0) 
// f(n-1)=f(n-2)+f(n-3)+...+f(0)
// 两式相减f(n)=2*f(n-1)
function jumpFloorII(number)
{
    // write code here
    if(number == 0){
        return 0;
    }
    if(number == 1){
        return 1;
    }
    var fn=jumpFloorII(number-1)*2
    return fn;
}

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

// 类似菲波那切数列
function rectCover(number)
{
    // write code here
    if(number==0){
        return 0;
    }
    if(number==1){
        return 1;
    }
    if(number==2){
        return 2;
    }
    var f=rectCover(number-1)+rectCover(number-2);
    return f;
}

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

function NumberOf1(n)
{
    // write code here
    var num=0;
    var target=1;
    if(n==0){
        return 0;
    }
    if(n!=0){
        // console.log(target);
        for(var i=0;i<32;i++){    //计算机中将整数按32位二进制存储
            if((n>>>i&1)==1){    //因为分为正负数  所以采用无符号右移与1相与
                num++;
            }
        }
        return num;
        // console.log(num);
    }
}

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

保证base和exponent不同时为0

//将指数转换成二进制 按位进行运算
function Power(base, exponent)
{
    // write code here
    var res=1.0;
    var n;
    if(exponent>0){   //指数大于0
        n=exponent;
    }else if(exponent<0){    //指数小于0
        if (!base) throw new Error('分母不能为0');
        n=-exponent;
    } else{
        return 1;     //指数等于0时结果永远是1
    }
   while(n){
       if(n&1)    //将指数转换成二进制数
        res=res*base;
        base=base*base;
        n>>=1;        //右移 以便判断指数相应位数是否为1  n=n>>1;
   } 
   return exponent>0?res:1/res;   //指数为正直接返回结果  指数为负返回结果的倒数
}

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

// 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,
// 所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
function reOrderArray(array)
{
    // write code here
    var newarray=[];
    var ji=0;     //奇数索引
    var ou=0;     //偶数索引
    for(var i=0;i<array.length;i++){    //因为奇数位于前半部分,所以第一遍遍历数组找出数组中奇数的个数
        if(array[i]%2==1){
            ou++;                      //第一个偶数的位置
        }
    }
    for(var j=0;j<array.length;j++){
        if(array[j]%2==1){
            newarray[ji]=array[j];
            ji++;
        }
        else{
            newarray[ou]=array[j];
            ou++;
        }
    }
    return newarray;
}

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

/* function ListNode(x){
 this.val = x;
 this.next = null;
 }*/
// 设置两个指针 pNode1 和 pNode2 两个指针相距 k-1 个距离
// pNode2先跑k个结点 pNode1跑到第一个结点
// 当pNode2的下一个节点为空 此时的pNode1指向倒数第k个结点
function FindKthToTail(head, k) {
  if (head === null || k <= 0) return null;
  let pNode1 = head,
    pNode2 = head;
    //先让pNode2跑k个结点
  while (--k) {
    if (pNode2.next !== null) {
      pNode2 = pNode2.next;
    } else {
      return null;
    }
  }
     // 判断pNode2下一个节点是否为空
  while (pNode2.next !== null) {
    pNode1 = pNode1.next;
    pNode2 = pNode2.next;
  }
  return pNode1;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!