剑指Offer刷题笔记——js版

本博客试题均使用javascript实现

  1. 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
    思路:从二维数组右上开始比较,若该数大于传入整数,则向左查找;若该数小于传入整数,则向下查找。
    代码
function Find(target, array){
    var row = 0;
    var col = array[0].length-1;
    while(row <= array.length-1 && col >= 0){
        if(array[row][col] > target){
            col--;
        }else if(array[row][col] < target){
            row++;
        }else{
            return true;
        }
    }
    return false;
}
  1. 请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
    思路:使用replace方法可以直接替换,这里使用split方法将原字符串每一项切割为数组并创建新数组,遍历原数组,若当前项为空格,则在新数组中添加新元素"%20";若当前项不为空格,则在新数组添加当前项,最后通过join方法将数组拼接成字符串。
    代码
function replaceSpace(str){
    var oldArr = str.split("");
    var newArr = [];
    for(index in oldArr){
        if(oldArr[index] === " "){
            newArr.push("%20");
        }else{
            newArr.push(oldArr[index]);
        }
    }
    return newArr.join("");
}
  1. 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
    思路:创建数组,遍历链表,将链表中的元素依次从尾部插入数组中,最后反转数组。
    代码
/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function printListFromTailToHead(head)
{
    var array = [];
    var node = head;
    while(node){
        array.push(node.val);
        node = node.next;
    }
    return array.reverse();
}
  1. 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{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;
} */
function reConstructBinaryTree(pre, vin){
    if(pre.length == 0 || vin.length == 0){
        return null;
    }else{
        var rootIndex = vin.indexOf(pre[0]);
        var vinLeft = vin.slice(0,rootIndex);
        var vinRight = vin.slice(rootIndex+1);
        var preLeft = pre.slice(1,vinLeft.length+1);
        var preRight = pre.slice(vinLeft.length+1);
        return {
            val: pre[0],
            left: reConstructBinaryTree(preLeft,vinLeft),
            right: reConstructBinaryTree(preRight,vinRight)
        };
    }
}
  1. 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
    思路:栈先进后出,队列先进先出,保证顺序即可,注意pop栈为空时的处理。
    代码
var inStack = [];
var outStack = [];
function push(node){
    inStack.push(node);
}
function pop(){
    if(outStack.length == 0){
        while(inStack.length != 0){
            outStack.push(inStack.pop());
        }
    }
    return outStack.pop();
}
  1. 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
    思路:采用二分法,mid>high,最小元素肯定在mid右边;mid 代码
function minNumberInRotateArray(rotateArray){
    let length = rotateArray.length;
    if(length == 0){
        return 0;
    }
    let low = 0;
    let high = length-1;
    while(low < high){
        let mid = low + Math.floor((high-low)/2);
        if(rotateArray[mid] > rotateArray[high]){
            low = mid+1;
        }else if (rotateArray[mid] < rotateArray[high]){
            high = mid;
        }else{
            high = high-1;
        }
    }
    return rotateArray[low];
}
  1. 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
    n<=39
    思路:先判断几种可以预料的情况,然后使用迭代法,数值从n迭代到预料数值之前,结果从预料数值之后迭代到n,最终输出结果。
    代码
function Fibonacci(n){
    if(n <= 0){
        return 0;
    }else if(n ==1 || n == 2){
        return 1
    }else{
        let fn1 = 1;
        let fn2 = 1;
        while(n > 2){
            fn2 = fn1 + fn2;
            fn1 = fn2 - fn1;
            n--;
        }
        return fn2;
    }
}
  1. 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
    思路:通过找规律发现此题为斐波那契数列,即f(n) = f(n-1) + f(n-2),因此可参照上一题解法。
    代码
function jumpFloor(number){
    if(number <= 0){
        return 0;
    }else if(number == 1){
        return 1;
    }else if(number == 2){
        return 2;
    }else{
        let fn1 = 1;
        let fn2 = 2;
        while(number > 2){
            fn2 = fn1 + fn2;
            fn1 = fn2 - fn1;
            number--;
        }
        return fn2;
    }
}
  1. 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
    思路:找规律发现f(n)=2*f(n-1)。
    代码
function jumpFloorII(number){
    if(number <= 0){
        return 0;
    }else if(number == 1){
        return 1;
    }else if(number == 2){
        return 2;
    }else{
        let fn = 2;
        while(number > 2){
            fn *= 2;
            number--;
        }
        return fn;
    }
}
  1. 我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
    思路:找规律发现依旧是斐波那契数列,f(n) = f(n-1) + f(n-2)。
    代码
function rectCover(number){
    if(number <= 0){
        return 0;
    }else if(number == 1){
        return 1;
    }else if(number == 2){
        return 2;
    }else{
        let fn1 = 1;
        let fn2 = 2;
        while(number > 2){
            fn2 = fn1 + fn2;
            fn1 = fn2 - fn1;
            number--;
        }
        return fn2;
    }
}
  1. 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
    思路:如果一个整数不为0,那么这个整数至少有一位是1。如果把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话),其余所有位将不会受到影响。这个时候如果把原来的整数和减去1之后的结果做与运算,会把原整数最右边一个1变成0。那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
    代码
function NumberOf1(n){
    if(n == 0){
        return 0;
    }else{
        let count = 0;
        while(n != 0){
            n = n & (n - 1);
            count++;
        }
        return count;
    }
}
  1. 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
    思路:情况考虑全面。
    代码
function Power(base, exponent){
    if(exponent == 0){
        return 1;
    }
    if(base == 0){
        return 0;
    }
    let result = 1;
    for(let i = 0;i < Math.abs(exponent);i++){
        result *= base;
    }
    if(exponent < 0){
        result=1/result;
    }
    return result;
}
  1. 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
    思路:类似冒泡排序,在前面是偶数后面是奇数的情况下交换两数位置。
    代码
function reOrderArray(array){
    for(let i = 0;i<array.length-1;i++){
        for(let j = 0;j<array.length-i-1;j++){
            if(array[j] % 2 == 0 && array[j+1] % 2 == 1){
                let temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
    }
    return array;
}
  1. 输入一个链表,输出该链表中倒数第k个结点。
    思路:创建数组,遍历链表,将链表的每一个元素依次插入数组中,输出第数组长度-k个元素。
    代码
/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function FindKthToTail(head, k){
    if (head == null || k <= 0) {
        return null;
    }
    var arr = [];
    while (head != null) {
        arr.push(head);
        head = head.next;
    }
    return arr[arr.length - k];
}
  1. 输入一个链表,反转链表后,输出新链表的表头。
    思路:改变链表指向。
    代码
/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function ReverseList(pHead){
    if(pHead == null){
        return null;
    }
    var head = pHead;
    var pre = null;
    var next = null;
    while(head != null){
        next = head.next;
        head.next = pre;
        pre = head;
        head = next;
    }
    return pre;
}
  1. 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
    思路:比较两个链表值的大小,另当前节点等于小的结点,当前节点的下个节点通过递归小的节点的下个节点和另一个链表的当前节点比较。
    代码
/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function Merge(pHead1, pHead2){
    if(pHead1 === null){
        return pHead2;
    }else if(pHead2 === null){
        return pHead1;
    }
    let 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;
}

未完待续~

你可能感兴趣的:(算法)