剑指offer算法篇(javascript)(上)number[1-40]

实战

一.二维数组的查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
两种思路
一种是:
把每一行看成有序递增的数组,
利用二分查找,
通过遍历每一行得到答案,
时间复杂度是nlogn

function Find(target, array)
{
    // write code here
    for(let i = 0;i <= array.length;i++) {
        let low = 0
        let high = array[i].length - 1
        while(low <= high) {
            let mid = (high + low)/2
            if(target < array[i][mid]) 
                high = mid - 1
            else if(target > array[i][mid])
                low = mid + 1
            else 
                return true
            
        }
    }
    return false
}
另外一种思路是:
利用二维数组由上到下,由左到右递增的规律,
那么选取右上角或者左下角的元素a[row][col]与target进行比较,
当target小于元素a[row][col]时,那么target必定在元素a所在行的左边,
即col--;
当target大于元素a[row][col]时,那么target必定在元素a所在列的下边,
即row++;

```javascript
function Find(target, array)
{
    // write code here
    //简便方法
    let row = array.length - 1
    let col = 0
    while(col <= array[col].length - 1&&row >= 0) {
        if(target < array[row][col]) {
            row--
        }
        else if(target > array[row][col]) {
            col++
        }
        else{
           return true
        }
    }
    return false
}

二、替换空格

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

function replaceSpace(str)
{
    // write code here
     return str.split(" ").join("%20")}

三、从尾到头打印链表

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

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function printListFromTailToHead(head)
{
    // write code here
    let arr = []
    let me = head
    while(me) {
        arr.push(me.val)
        me = me.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;
} */
function reConstructBinaryTree(pre, vin)
{
    // write code here
    let result = null
    if(pre.length > 1) {
        let root = pre[0]
        let rootIndex = vin.indexOf(root)
        let vinLeft = vin.slice(0,rootIndex)
        let vinRight = vin.slice(rootIndex+1,vin.length)
        pre.shift()
        let preLeft = pre.slice(0,vinLeft.length)
        let 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
}

五、用两个栈实现队列

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

let inStack = []
let outStack = []
function push(node)
{
    // write code here
    inStack.push(node)
}
function pop()
{
    // write code here
    if(!outStack.length) {
        while(inStack.length){
            outStack.push(inStack.pop())
        }
    }
    return outStack.pop()
}

六、旋转数组最小数字

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

function minNumberInRotateArray(rotateArray) {
    if(rotateArray.length === 1) {
        return 0
    }
    else {
        rotateArrayl.sort((a,b) => a - b)
        return rotateArray[0]
    }
}

七、斐波那契数列

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

function Fibonacci(n) {
    if(n <= 0) {
        return 0
    }
   if(n == 1) {
        return 1
   }
    let temp1 = 0
   let temp2 = 1
    for(let i = 1; i <= n/2; i++) {
        temp1 += temp2
        temp2 += temp1
    }
    if(n%2 == 0) {
        return temp1
    }    else{
        return temp2
    }
}

2.递归实现:

function Fibonacci(n) {
    if(n <= 1) {
        return n
    }
    else{
        let f0 = 0,f1 = 1,f2 = undefined
        for(let i = 2;i<=n;i++) {
             f2 = f0 + f1
            f0 = f1
            f1 = f2
        }
        return f2
    }
    
}
console.log(Fibonacci(3))

八、跳台阶

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

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

九、变态跳台阶

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

function jumpFloorII(number)
{
    if(number === 0){
        return -1
    }
    else if(number === 1) {
        return 1
    }
    return 2 * jumpFloorII(number - 1)
}

十、矩形覆盖

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

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

十一、二进制中1的个数

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

//console.log(5 & 13); // 0101 & 1101 = 0101
// expected output: 5;
//console.log(parseInt('0101', 2) & parseInt('1101', 2));
// expected output: 5;
function NumberOf1(n)
{
    var count=0;
    while(n){
        count++;
        n=n&(n-1)
    }
    return count
}

十二、数值的整数次方

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
保证base和exponent不同时为0

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

大佬代码:

function Power(x,n){
    if(n < 0) {
        if(x <= 0) {
            throw new Error("分母不能小于等于0");
        }else {
            if(-n % 2 == 1) {
                return 1/(Power(x,-n-1) * x);
            }else {
                var r = 1/Power(x,-n/2);
            return r * r;
            }
        }
    }
    if(n == 0) {
        return 1;
    }
    else {
        if(n % 2 == 1) {
            return Power(x,n-1) * x;
        }else {
            var r = Power(x,n/2);
            return r * r;
        }
    }
    
}

十三、调整数组顺序使奇数位于偶数前

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

function reOrderArray(array){
    let arr1 = []
    let arr2 = []
    array.forEach((item,index) => {
        if(item%2 == 1) {
            arr1.push(item)
        }
        if(item%2 == 0) {
            arr2.push(item)
        }
    })
    return [].concat(arr1,arr2)
}

十四、链表中倒数第K个节点

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

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function FindKthToTail(head, k)
{
    // write code here
    
    let arr = []
    while(head != null) {
        arr.push(head)
        head = head.next
    }
    return arr[arr.length - k]
}

十五、反转链表

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

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function ReverseList(pHead)
{
    // write code here
    let arr = [];
    let current = pHead;
    while (current != null) {
        arr.push(current.val);
        current = current.next;
    }
    current = pHead;
    while (arr.length) {
        current.val = arr.pop();
        current = current.next;
    }
    return pHead;
}

空间复杂度低的:

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function ReverseList(pHead)
{
    // write code here
 
    var pre = null;
    var next = null;
    while (pHead != null) {
        next = pHead.next;
        pHead.next = pre;
        pre = pHead;
        pHead = next;
    }
    return pre;
}

十六、合并两个排序的链表

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

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function Merge(pHead1, pHead2)
{
    // write code here
    if(!pHead1) return pHead2
    if(!pHead2) return pHead1
    let pHead3 = null
    if(pHead1.val < pHead2.val) {
        pHead3 = pHead1
        pHead3.next = Merge(pHead1.next, pHead2)
    }
    else {
        pHead3 = pHead2
        pHead3.next = Merge(pHead1, pHead2.next)
    }
    return pHead3
}

十七、树的子结构

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

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function HasSubtree(pRoot1, pRoot2)
{
    // write code here
    if(!pRoot1 || !pRoot2) {
        return false
    }
    return hasTree(pRoot1, pRoot2) || HasSubtree(pRoot1.left,pRoot2) || HasSubtree(pRoot1.right,pRoot2)
}
function hasTree(pRoot1, pRoot2) {
    if(!pRoot2) {//必须先判断子树
        return true
    }
    else if(!pRoot1) {
        return false
    }
    else if(pRoot1.val == pRoot2.val) {
        return hasTree(pRoot1.left, pRoot2.left) && hasTree(pRoot1.right, pRoot2.right)
    }
    else {
        return false
    }
}

十八、二叉树镜像

操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:

二叉树的镜像定义:源二叉树 
    	    8
    	   /  \
    	  6   10
    	 / \  / \
    	5  7 9 11
    	镜像二叉树
    	    8
    	   /  \
    	  10   6
    	 / \  / \
    	11 9 7  5
/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function Mirror(root)
{
    // write code here
    if(!root){
        return
    }
    let temp = root.left
    root.left = root.right
    root.right = temp
    Mirror(root.left)
    Mirror(root.right)
    
 }

十九、顺时针打印矩阵

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

二十、包含main函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

let stack = []
function push(node)
{
    // write code here
    stack.push(node)
}
function pop()
{
    // write code here
    return stack.length == 0 ? null : stack.pop()
}
function top()
{
    // write code here
    return stack.length == 0 ? null : stack[0]
}
function min()
{
    // write code here
    return Math.min.apply(this,stack)
}

二十一、栈的压入,弹出序列

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

function IsPopOrder(pushV, popV)
{
    // write code here
    let stack = []
    let inx = 0
    for(let i = 0; i <= pushV.length; i++) {
        stack.push(pushV[i])
        while(stack.length&&stack[stack.length - 1] == popV[inx]) {
            stack.pop()
            inx++
        }
    }
    return stack.length == 0
}

二十二、从上往下,从左往右打印二叉树

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function PrintFromTopToBottom(root)
{
 // write code here
    let arr=[]
    let arr1=[]
    if(root!=null){
        arr.push(root)
    }
    while(arr.length!=0){
        let node=arr.shift()
        if(node.left!=null){
            arr.push(node.left)
        }
        if(node.right!=null){
            arr.push(node.right)
        }
        arr1.push(node.val)
    }
    return arr1

}

二十三、二叉树的后序遍历

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

function VerifySquenceOfBST(sequence)
{
    // write code here
    if(!sequence.length) return false
    return fn(sequence, 0, sequence.length-1)
}

function fn(sequence, start, end) {
    if(start >= end) return true
    let i = start
    while(sequence[i]<sequence[end] && i<end) {
        i++
    }
    for(let j = i;j<end;j++) {
        if(sequence[j] < sequence[end]) {
            return false
        }
    }
    return fn(sequence, 0, i-1)&&fn(sequence, i, end-1)
} 

二十四、二叉树中为某一只的路径

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

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function FindPath(root, expectNumber) {
    let result = []
    if (root === null) {
        return result
    }
    fn(root, expectNumber, [], 0, result)
    return result
 
}
function fn(root, expectNumber, path, currentSum, result) {
    currentSum += root.val
 
    path.push(root.val)
 
    if (currentSum == expectNumber && root.left == null && root.right == null) {
        result.push(path.slice(0))
    }
    if (root.left != null) {
        fn(root.left, expectNumber, path, currentSum, result)
    }
 
    if (root.right != null) {
        fn(root.right, expectNumber, path, currentSum, result)
    }
 
    path.pop()
}

二十五、复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

/*function RandomListNode(x){
    this.label = x;
    this.next = null;
    this.random = null;
}*/
function Clone(pHead)
{
    // write code here
    if(!pHead) return null
    let newHead = new RandomListNode(pHead.label)
    newHead.random = pHead.random
    newHead.next = Clone(pHead.next)
    return newHead
}

二十六、二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function Convert(pRootOfTree)
{
    // write code here
    if(!pRootOfTree) {
        return null
    }
    let arr = []
    ftoe(pRootOfTree,arr)
    arr[0].left = null
    arr[0].right = arr[1]
    for(let i=1;i<arr.length-1;i++) {
        arr[i].left = arr[i-1]
        arr[i].right = arr[i+1]
    }
    arr[arr.length - 1].left = arr[arr.length -2]
    arr[arr.length - 1].right = null
    return arr[0]
}
function ftoe(node,arr) {
    if(!node) return
    ftoe(node.left,arr)
    arr.push(node)
    ftoe(node.right,arr)
}

二十七、字符串的排列

题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
1、递归算法;

function Permutation(str)
{
    // write code here
    let result = []
    if(str.length <= 0) return result
    let sortOne = ""
    let arr = str.split("")
    result = sortString(arr,sortOne)
    return result
}
sortString(arr, sortOne) {
    if(arr.length == 0) {
        result.push(sortOne)
    }else{
        let logo = {}
        for(let i=0;i<arr.length;i++) {
            if(!logo[arr[i]]){
                let p = arr.splice(i,1)
                sortOne.concat(p)
                sortString(arr, sortOne)
                sortOne.splice(i,0,p)
                sortOne = sortOne.slice(0,sortOne.length-1)
                logo[p] = true
            }
        }
    }
    return result
}

2、另一种递归

function Permutation(str)
{
    // write code here
    let res = [];
    let len = str.length;
    if (len === 0) {
        res.push();
    } else if (len === 1) {
        res.push(str);
    } else {
        let obj = {};
        for (let i = 0; i < len; i++) {
            let c = str[i];
            if (!obj[c]) {
                let newStr = str.slice(0,i) + str.slice(i+1, len);
                let l = Permutation(newStr);
                for (let j = 0, lenL = l.length; j < lenL; j++) {
                    res.push(c+l[j]);
                }
                obj[c] = true;
            }
        }
    }
    return res;
}

二十八、数组中出现次数超过一半的数字

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

function MoreThanHalfNum_Solution(numbers)
{
    // write code here
    let arr = [],
        len = numbers.length,
        a;
    for(let i=0;i<len;i++) {
        a = numbers[i]
        if(arr[a]) {
            arr[a]++
        }
        else{
            arr[a] = 1
        }
    }
    for(let i = 0;i<arr.length;i++) {
        if(arr[i]>len/2) {
            return i
        }
    }
    return 0
}

二十九、最小的K个数

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

function GetLeastNumbers_Solution(input, k)
{
    // write code here
    if(!input || k>input.length) return []
    let a
    for(let i=0;i<k;i++) {
        for(let j=i+1;j<input.length;j++) {
            if(input[i]>input[j]) {
                a = input[i]
                input[i] = input[j]
                input[j] = a
            }
        }
    }
    return input.slice(0,k)
}

三十、连续子数组的最大和

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

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

三十一、整数中1出现的次数

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

function NumberOf1Between1AndN_Solution(n)
{
    // write code here
    if(n<=0) return 0
    let count = 0
    for(let i=1;i<=n;i++) {
        let num = i
        while(num>0) {
            if(num%10 == 1) {
                count++
            }
            num = Math.floor(num/10)
        }
    }
    return count
}

三十二、把数组排成最小的数

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

function PrintMinNumber(numbers)
{
    // write code here
    let results = numbers.sort(function(a, b) {
        return [a,b].join("") - [b,a].join("")
    })
    return results.join("")
}

三十三、丑数

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

function GetUglyNumber_Solution(index)
{
    // write code here
    if(index<=0) return 0
    let num2 = 0,
        num3 = 0,
        num5 = 0,
        arr = [1]
    for(let i=1;i<index;i++) {
        arr[i] = Math.min(arr[num2]*2,arr[num3]*3,arr[num5]*5)
        if(arr[i] == arr[num2]*2) num2++
        if(arr[i] == arr[num3]*3) num3++
        if(arr[i] == arr[num5]*5) num5++
    }
    return arr[index-1]
}

三十四、第一次只出现一次的字符

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

function FirstNotRepeatingChar(str)
{
    // write code here
    for(let i=0;i<str.length;i++) {
        if(str.lastIndexOf(str[i]) == str.indexOf(str[i])){
            return i
            break
        }

    }
    return -1
}

三十五、数组中的逆序对

题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字

数据范围:

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

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

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

示例1
输入
1,2,3,4,5,6,7,0
输出
7

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

三十六、两个链表的第一个公共节点

题目描述
输入两个链表,找出它们的第一个公共结点。

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function FindFirstCommonNode(pHead1, pHead2)
{
    // write code here
    let p1 = pHead1,
        p2 = pHead2
    while(p1!==p2) {
        p1 = p1==null ? pHead2 : p1.next
        p2 = p2==null ? pHead1 : p2.next
    }
    return p1
}

长度相同有公共结点,第一次就遍历到;没有公共结点,走到尾部NULL相遇,返回NULL
长度不同有公共结点,第一遍差值就出来了,第二遍一起到公共结点;没有公共,一起到结尾NULL。`剑指offer算法篇(javascript)(上)number[1-40]_第1张图片

三十七、数字在排序数组中出现的次数

题目描述
统计一个数字在排序数组中出现的次数。

function GetNumberOfK(data, k)
{
    // write code here
    let count = 0
    for(let i=0;i<data.length;i++) {
        if(data[i] == k) {
            count++
        }
    }
    return count
}

三十八、二叉树的深度

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

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function TreeDepth(pRoot)
{
    // write code here
    let left,
        right,
        max
    if(!pRoot) return 0
        left = 1 + TreeDepth(pRoot.left)
        right = 1 + TreeDepth(pRoot.right)
        max = Math.max(left, right)
        return max
}

三十九、平衡二叉树

题目描述
输入一棵二叉树,判断该二叉树是否是平衡二叉树
平衡二叉树:

  • 可以是空树
  • 假如不是空树,任何一个结点的左子树与右子树都是平衡二叉树,并且高度之差的绝对值不超过 1

剑指offer算法篇(javascript)(上)number[1-40]_第2张图片

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function IsBalanced_Solution(pRoot)
{
    // write code here
     if(!pRoot) return true;
    return Math.abs(height(pRoot.left)-height(pRoot.right))<=1;
}
function height(node) {
    if(!node) return 0
    if(!node.left && !node.right) return 1
    return Math.max(height(node.left), height(node.right)) + 1
}

四十、数组中只出现一次的数字

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

function FindNumsAppearOnce(array)
{
    // write code here
    // return list, 比如[a,b],其中ab是出现一次的两个数字
    if(!array) return null
    let arr = []
    for(let i=0;i<array.length;i++) {
        if(array.lastIndexOf(array[i]) == array.indexOf(array[i])){
            arr.push(array[i])
        }
    }
    return arr
}

你可能感兴趣的:(前端技术笔记,js,javascript,算法)