[剑指Offer学习记录]

℡╲_俬逩灬. 提交于 2020-01-20 07:22:23
复习次数
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
        1                                                                                                                              

面试题4:二维数组中的查找

题目描述

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

思路:通过将target与数组右上角的数组进行判断来逐步缩小查询数组的范围。

function Find(target, array)
{
    const n = array.length,
          m = array[0].length;
    let row = 0,
        col = m-1;

    while(row < n && col >= 0){
        if(target < array[row][col]){
            col--;
        }else if(target > array[row][col]){
            row++;
        }else{
            return true
        }
    }
    return false;
}
//牛客报错
function Find(target, array)
{
    let res = false;
    let i = array.length,
        j = array[0].length;
    let row = 0,
        col = j-1;
    while(row < i && col >= 0){
        while((target < array[row][col]) && (col >= 0)){
            col--;
        }
        while((target > array[row][col]) && (row < i)){
            row++;
        }
        if(target === array[row][col]){res = true;break;}
    }
    return res;
}

 

面试题5:替换空格

题目描述

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

思路:用正则式

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

面试题6:从尾到头打印链表

题目描述

输入一个链表,按链表从尾到头反过来打印出每个节点的值。

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function printListFromTailToHead(head)
{
    // 使用push和reverse
    let res = [];
    let pNode = head;
    while(pNode != null){
        res.push(pNode.val);
        pNode = pNode.next;
    }
    return res.reverse();
    
    //使用unshift
    let res = [];
    let pNode = head;
    while(pNode != null){
        res.unshift(pNode.val);
        pNode = pNode.next;
    }
    return res;
}

面试题7:重建二叉树

题目描述

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

思路

一直抓住数组pre和vin就好了

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function reConstructBinaryTree(pre, vin)
{
// write code here
  if (pre.length === 0 || vin.length === 0) {
    return null;
  }
  // 前序第一个是根节点,也是中序左右子树的分割点
  const index = vin.indexOf(pre[0]),
        // left,right对应的是数组vin的左子树和右子树
        left = vin.slice(0, index),
        right = vin.slice(index + 1),
        rootVal = pre[0],
        node = new TreeNode(rootVal);
  node.left = reConstructBinaryTree(pre.slice(1, index + 1), left);
  node.right = reConstructBinaryTree(pre.slice(index + 1), right);
  return node;
}
// 方法二:返回的是一个对象。对象就是一个节点啊!神奇吧!
/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function reConstructBinaryTree(pre, vin) {
  // write code here
  if (pre.length === 0 || vin.length === 0) {
    return null;
  }
  // 前序第一个是根节点,也是中序左右子树的分割点
  const index = vin.indexOf(pre[0]),
    left = vin.slice(0, index),
    right = vin.slice(index + 1);
  return {
    val: pre[0],
    // 递归左右子树的前序、中序
    left: reConstructBinaryTree(pre.slice(1, index + 1), left),
    right: reConstructBinaryTree(pre.slice(index + 1), right)
  };
}

面试题9:用两个栈实现队列

题目描述

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

思路(来源

栈的特性:先入后出,队列的特性:先入先出。

算法分为入队和出队过程。

入队过程:将元素放入 inStack 中。

出队过程

  • outStack 不为空:弹出元素(巧妙地方在于就算此时又有新的数字传入到inStack,但将要弹出的不会是这个先进的数字,而是先入的,先入的在outStack里。)
  • outStack 为空:将 inStack 元素依次弹出,放入到 outStack 中(在数据转移过程中,顺序已经从后入先出变成了先入先出)
const outStack = [],
      inStack = [];
function push(node) {
  inStack.push(node);
}
function pop() {
  if (!outStack.length) {// 有点巧妙。
    while (inStack.length) {
      outStack.push(inStack.pop());
    }
  }
  return outStack.pop();
}

拓展:用两个队列实现一个栈

思路(来源

栈的特性:先入后出,队列的特性:先入先出。

准备两个队列q1q2。算法过程分为入栈和出栈。

入栈过程

  • q1 为空,放入 q2
  • q2 为空,放入 q1
  • 均为空,默认放入 q1

出栈过程

  • q1 为空:
    • 依次取出 q2 中的元素(除了最后一个),并且放入 q1 中
    • 取出 q2 中的最后一个元素,返回结果
  • q2 为空:
    • 依次取出 q1 中的元素(除了最后一个),并且放入 q2 中
    • 取出 q1 中的最后一个元素,返回结果

面试题10:斐波那契数列

题目描述

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

思路

方法一:递归;方法二:循环,从下到上

function Fibonacci(n)
{
    var one = 0,
        two = 1;
    //写法一
    //if(n === 0)return 0;
    //写法二
    var result = [0,1];
    if(n<2)return result[n];
    
    for(let i = 2; i <= n; i++){
        let temp = one + two;
        one = two;
        two = temp;
    }
    return two;
}

拓展1:跳台阶

题目描述

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

思路

级数 跳法
1级 1种
2级 2种:1,2
3级 3种:1+1+1, 1+2, 2+1
4级 5种:1+1+1+1, 1+1+2, 1+2+1, 2+1+1, 2+2

摘自《剑指Offer》P78:我们把n级台阶时的跳法看成n的函数,记为f(n)。当n>2时,第一次跳的时候就有两种不同的选择:一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);二是第一次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为f(n-2)。因此,n级台阶的不同跳法的总数f(n)=f(n-1)+f(n-2)。

function jumpFloor(number)
{
    //递归
    /*if(number <= 1)return 1;
    else if(number === 2)return 2;
    else return jumpFloor(number-1) + jumpFloor(number-2);*/
    
    //循环
    var result = [1,2];
    if(number < 3)return result[number-1];
    var one = 1,
        two = 2;
    for(let i = 3; i <=number; i++){//如果易懂一点就像上一个代码新增一个变量。
        two = one + two;
        one = two - one;
    }
    return two;
}

拓展2:变态跳台阶

题目描述

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

思路(来源

根据上一个题目可以知道,青蛙只跳1或2可以得出是一个斐波那契问题,即a[n]=a[n-1]+a[n-2],那么能跳1,2,3个台阶时a[n]=a[n-1]+a[n-2]+a[n-3],......

那么有:

a[n]=a[n-1]+a[n-2]+......+a[1];..........................①

a[n-1]=        a[n-2]+......+a[1];..........................②

两式相减可知:a[n]=2*a[n-1];

所以其实是一个等比数列。f(n) = 

function jumpFloorII(number)
{
    var result = 1;
    if(number === 0)return 0;
    while(--number){
        result *= 2;
    }
    return result;
}

拓展3:矩形覆盖

题目描述

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

思路(来源

注意:比如当上面出现了横着放,那对应的下面其实已经确定了,只能横着放,不会有其他的放法。

n个2*1的矩形 方法
1个 1种
2个 2种:竖着放,横着放
3个 3种:竖上横(下横),竖竖竖,上横(下横)竖
4个 5种:1+1+1+1, 1+1+2, 1+2+1, 2+1+1, 2+2

面试题11:旋转数组的最小数字

题目描述

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

思路

Step1:用两个指针(i,j)分别指向数组的第一个元素(第一个指针i)和最后一个元素(第二个指针j)。判断大小,两种情况:

  1. 第一个元素小于最后一个元素:说明旋转数组等于原数组本身,如{1,2,3,4,5}是{1,2,3,4,5}的一个旋转。此时最小值为第一个元素(可以直接return)
  2. 第一个元素大于等于最后一个元素,进入Step2

Step2:找到数组中间元素Arr[mid],将中间元素与第一个元素和最后一个元素比较。有三种情况:

  1. Arr[mid]大于等于Arr[i]:说明中间元素处于前一个递增子数组。最小值会在 mid~j 这部分,因此:i = mid,缩小寻找范围
  2. Arr[mid]小于等于Arr[j]:说明中间元素处于后一个递增子数组。最小值会在 i~mid 这部分,因此:j = mid,缩小寻找范围
  3. (特例)当Arr[i] == Arr[mid] == Arr[j],无法判断中间的数字是位于前面的子数组还是后面的子数组,因此要采用顺序查找的方法来实现

Step3:因为第一个指针总是指向前面递增数组的元素,第二个指针总是指向后面递增数组的元素。最终第一个指针将指向前面子数组的最后一个元素,而第二个指针将指向后面子数组的第一个元素。因此,循环结束条件为这两个指针的距离为1。

function minNumberInRotateArray(rotateArray)
{
    var len = rotateArray.length;
    if(len === 0)return 0;
    var i = 0,
        j = len-1;
    while(j - i > 1){
        let middle = Math.floor((i+j)/2);
        if(rotateArray[i] === rotateArray[j] && rotateArray[i] === rotateArray[middle]){//三个数相同时
            let min = a[i];
            for(let k = 0; k < len; k++){
                if(rotateArray[k] < min)min = rotateArray[k];
            }
            return min;
        }else if(rotateArray[i] < rotateArray[j]){
            return rotateArray[i];
        }else{
            if(rotateArray[i] <= rotateArray[middle]){
                i = middle;
            }else if(rotateArray[middle] <= rotateArray[j]){
                j = middle;
            }
        }
    }
    return rotateArray[j];
}

面试题15:二进制中1的个数

题目描述

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

思路

书P101-102,https://www.cnblogs.com/wuguanglin/p/NumberOf1.html

常用技巧

  1. 把一个整数减去1之后再和原来的整数做与运算,得到的结果相当于把整数的二进制表示中最右边的1变成0。
  2. 把整数右移一位和把整数除以2在数学上是等价的,但因为除法的效率比移位运算要低得多,在实际编程中尽可能地用移位运算符替代乘除法。
function NumberOf1(n)
{
    //方法一(居然不用先将整数转换成二进制!
    /*var flag = 1,
        count= 0;
    while(flag){
        if(n & flag){
            count++;
        }    
        flag = flag << 1;
    }
    return count;*/
    
    //方法二
    var count = 0;
    while(n){
        count++;
        n = n & n-1;
    }
    return count;
}

面试题16:数值的整数次方

题目描述

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

保证base和exponent不同时为0

思路(两个方法)

方法一:

 n & 0x1 = 0:n为偶数, n & 0x1 = 1:n为奇数
function Power(base, exponent)
{
    var result = 1;
    if(exponent < 0){
        if(base !== 0) PowerWithExponent(base, -exponent);
        else throw new Error('分母不能为0');
    }else if(base == 0){
        return 0;
    }else{
        PowerWithExponent(base, exponent);
    }
    
    function PowerWithExponent(base, exponent){
        if(exponent == 0)return 1;
        if(exponent == 1)return base;
        
        result = PowerWithExponent(base, exponent>>1);//用右移运算符代替除以2
        result *= result;
        if(exponent & 0x1 == 1){//判断是奇数还是偶数
            result *= base;
        }
    }
    return (exponent > 0 ? result : (1/result));
}

方法二:快速求幂 参考

首先要明白:

然后:

function Power(base, exponent)
{
    var result = 1,
        n;
    if(exponent > 0)n = exponent;
    else{//exponent <= 0
        if(base == 0)throw new Error('分母不能为0');
        else n = -exponent;
    }
    
    while(n){
        if(n & 0x1){
            result *= base;
        }
        base *= base;
        n = n >> 1;
    }
    return exponent > 0 ? result : (1/result);
}

面试题18:删除链表中重复的节点

题目描述

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表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;
    }
    const head = new ListNode('x');
    head.next = pHead;
    let pre = head,
        cur = head.next;
    while(cur !== null){
        //注意!涉及到cur.next的值需要提前判断cur.next是否为空,否则会出错。
        //因为如果cur是尾节点,此时cur不为空,而cur.next为空,那cur.next的val值是未知的。
        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;
}

面试题20:表示数值的字符串

题目描述

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

思路(原博

运用js的正则式

//s字符串
function isNumeric(s)
{
    //方法一,search()返回的是正则表达式在字符串中首次匹配项的索引。这里不可以把^$去掉。
    //return s.search(/^[+-]?\d*(\.\d*)?$/) === 0 ||
        //s.search(/^[+-]?\d+(\.\d*)?[Ee][+-]?\d+$/) === 0;

    //方法二,match()返回的是一个数组。有点疑问,这个表达式内不可以同时加^$,否则牛客网会直接报错
    return s.match(/[+-]?\d*(\.\d+)?([Ee][+-]?\d+)?/g)[0] === s;
    
    //return s.search(/[+-]?\d*(\.\d+)?([Ee][+-]?\d+)?/ === 0); 这个是错的。比如12e会被识别为true,但正确答案是false
    //因为没有开始结尾符号,导致匹配了12就完事了,不会看e后面是否满足。
}

正则式

在 JavaScript中,正则表达式也是对象。这些模式被用于 RegExp 的 exec 和 test 方法, 以及 String 的 matchmatchAllreplacesearch 和 split 方法。

match、search的区别:match返回的是一个数组,search返回的是正则表达式在字符串中首次匹配项的索引

// match()
var str = 'For more information, see Chapter 3.4.5.1';
var re = /see (chapter \d+(\.\d)*)/i;
var found = str.match(re);

console.log(found);

// logs [ 'see Chapter 3.4.5.1',
//        'Chapter 3.4.5.1',
//        '.1',
//        index: 22,
//        input: 'For more information, see Chapter 3.4.5.1' ]

// 'see Chapter 3.4.5.1' 是整个匹配。
// 'Chapter 3.4.5.1' 被'(chapter \d+(\.\d)*)'捕获。
// '.1' 是被'(\.\d)'捕获的最后一个值。
// 'index' 属性(22) 是整个匹配从零开始的索引。
// 'input' 属性是被解析的原始字符串。
_______________________________________________________
//search
var str = "hey JudE";
var re = /[A-Z]/g;
var re2 = /[.]/g;
console.log(str.search(re)); // returns 4, which is the index of the first capital letter "J"
console.log(str.search(re2)); // returns -1 cannot find '.' dot punctuation

^$的重要性

如果使用了^和$,意味着输入的整个字符串都要用来和正则式匹配。如果不使用^和$,对于\d{5,12}而言,这个正则式只能保证字符串里包含5到12连续位数字,而使用^和$以为着整个字符串只能5到12位数字。上几张图





面试题21:调整数组顺序使奇数位于偶数前面

题目描述

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

思路

相对位置不变可以联想到稳定性,而冒泡具有稳定性,所以可以模拟冒泡实现。(方法2)

方法1和方法3都是用空间换时间,但方法3更巧妙。方法3:原博

有一个坑:位与运算符 和 等号 的优先级。等号 高于 位于运算符。如果我们利用位与运算符写一个判断array[j]是偶数的表达式为:array[j] & 0x1 === 0,则先进行右边0x1 === 0的判断,再进行位与运算,这整个表达式将一直是false,并不能判断是否为偶数。正确的写法是加一个括号:(array[j] & 0x1) === 0

// 方法1:最不好的代码
function reOrderArray(array)
{
    var odd = [],
        even = [];
    var len = array.length,
        i = 0;
    while(i < len){
        if((array[i] & 0x1) === 1)odd.push(array[i++]);
        else even.push(array[i++]);
    }
    return odd.concat(even);
}
// 方法2
function reOrderArray(array)
{
    var flag,
        len = array.length;

    for(var i = 0; i < len; i++){
        flag = 0;
        for(var j = 0; j < len-1; j++){//注意,这里和冒泡有点不同。j和i都是从0开始
            if((array[j] & 0x1) === 0 && (array[j+1] & 0x1) === 1){
                [array[j],array[j+1]] = [array[j+1],array[j]];
                flag = 1;
            }
        }
        if(flag == 0)break;//全程无交换
    }
    return array;
}
//方法3
function reOrderArray(array) {
    // oddBegin主要是用作奇数的索引,oddCount实际上是计算奇数个数,但可用作偶数的开头索引
    // newArray用来存储,以空间换时间,复杂度为O(n)
    let oddBegin = 0,
    oddCount = 0;
    const newArray = [];
    for (let i = 0; i < array.length; i++) {
        if (array[i] & 1) {
            oddCount++;
        }
    }
    for (let i = 0; i < array.length; i++) {
        if (array[i] & 1) {
            newArray[oddBegin++] = array[i];
        } else {
        newArray[oddCount++] = array[i];
        }
    }
    return newArray;
}
//不要求保持相对位置相同的话,这个也可以。
function reOrderArray(array)
{
    var len = array.length,
        i = 0,//奇数
        j = len-1;//偶数
    while(j >= i){
        while((array[i] & 0x1) === 1)i++;
        while((array[j] & 0x1) === 0)j--;
        if(i <= j){
            [array[i],array[j]] = [array[j],array[i]];
            i++;
            j--;
        }
    }
    return array;
}

面试题22:链表中倒数第k个节点

题目描述

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

思路

双指针。比如我要求倒数第3的节点,倒数第3是倒数第1(倒数第1相当于尾节点)的前两个节点,相差2,所以从头开始算时,指向倒数第3的指针要比指向尾节点的指针迟2个进场。

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function FindKthToTail(head, k)
{
    if(head == null || k <= 0)return null;
    var p1 = head, 
        p2;
    while(--k){// 注意这里是--k,不是k--。比如当k=1时
        if(p1.next != null){
            p1 = p1.next;
        }else{
            return null;
        }
    }
    p2 = head;
    while(p1.next != null){
        p1 = p1.next;
        p2 = p2.next;
    }
    return p2;
}
// 自己写的,写的很难看。为了通过而通过。主要是自己想的不够彻底
/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function FindKthToTail(head, k)
{
    var p1, p2,
        n = 0;//节点数
    p1 = head;
    p2 = null;
    if(head == null || k <= 0)return null;
    while(p1.next !== null){
        n++;
        if(n === k)p2 = head;
        if(p2 !== null)p2 = p2.next;
        p1 = p1.next;
    }
    n = n + 1;//指针指向尾节点时节点数是n-1,因此退出循环后要+1
    if(n < k)return null;
    else if(n == k)return head;
    else return p2;
}

面试题24:反转链表

题目描述

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

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function ReverseList(pHead)
{
    if(pHead === null)return null;
    let pNode, pPrev, res;
    pNode = pHead;
    pPrev = null;
    while(pNode != null){
        let pNext = pNode.next;
        pNode.next = pPrev;
        if(pNext == null)res = pNode;
        pPrev = pNode;
        pNode = pNext;
    }
    return res;
}

面试题25:合并两个排序的链表

题目描述

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

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
// 非递归,两个指针
function Merge(pHead1, pHead2)
{
    let pMergeHead = new ListNode(null),
        p = pMergeHead;
    while(pHead1 != null && pHead2 != null){
        if(pHead1.val > pHead2.val){
            p.next = pHead2;
            pHead2 = pHead2.next;
        }else{
            p.next = pHead1;
            pHead1 = pHead1.next;
        }
        p = p.next;
    }
    if(pHead1 == null)p.next = pHead2;
    else p.next = pHead1;
    return pMergeHead.next;
}
// 递归
function Merge(pHead1, pHead2)
{
    if(pHead1 == null)return pHead2;
    if(pHead2 == null)return pHead1;
    let pMergeHead = null;
    if(pHead1.val < pHead2.val){
        pMergeHead = pHead1;
        pMergeHead.next = Merge(pHead1.next, pHead2)
    }else{
        pMergeHead = pHead2;
        pMergeHead.next = Merge(pHead1, pHead2.next)
    }
    return pMergeHead;
}

面试题26:树的子结构

题目描述

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

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function HasSubtree(pRoot1, pRoot2)
{
    if(pRoot1 == null || pRoot2 == null)return false; //一开始把||写成了&&,牛客会报错
    let res = false;
    if(pRoot1.val === pRoot2.val)res = doesTree1HasTree2(pRoot1, pRoot2);
    if(!res)res = HasSubtree(pRoot1.left, pRoot2);
    if(!res)res = HasSubtree(pRoot1.right, pRoot2);
    return res;
}
function doesTree1HasTree2(pRoot1, pRoot2){
    if(pRoot2 == null)return true;
    if(pRoot1 == null)return false;
    if(pRoot1.val !== pRoot2.val)return false;
    return doesTree1HasTree2(pRoot1.left, pRoot2.left) && doesTree1HasTree2(pRoot1.right, pRoot2.right)
}

面试题27:二叉树的镜像

题目描述

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

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function Mirror(root)
{
    if(root == null)return;
    Mirror(root.left);
    Mirror(root.right);
    [root.left, root.right]=[root.right, root.left];
    return root;
}

 

 

 

 

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!