zoukankan      html  css  js  c++  java
  • 剑指offer

    1.链表中倒数第 k 个结点

    问题描述:

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

    解题思路 1:

    因为要求链表倒数第 k 个节点,也就是求正数第 length - k 个节点。整体过程如下:

    • 链表又是个单链表,并且没有保存长度信息。所以需要循环一次计算 length。
    • 第二次循环找到第 length - k 个节点。

    时间复杂度是 O(N),需要 2 次循环。

    /*function ListNode(x){
        this.val = x;
        this.next = null;
    }*/
    
    function FindKthToTail(head, k) {
      // write code here
      let length = 0;
      let node = head;
      while (node) {
        length++;
        node = node.next;
      }
      if (k > length) {
        return null;
      }
      let offset = length - k;
      node = head;
      for (let i = 0; i < offset; i++) {
        node = node.next;
      }
      return node;
    }
    

    解题思路 2:

    准备两个指针:left(慢)和 right(快)。整体过程如下:

    • right 先向右移动 k 位,此时 index(right) - index(left) = k
    • left 和 right 一起向右移动,直到 right 抵达边界
    • 由于 index(right) - index(left) = k,所以 index(left) = index(right) - k = length - k。也就是 left 指针移动到了倒数第 k 个位置

    时间复杂度是 O(N),但仅需要遍历一次。空间复杂度是 O(1)

    /*function ListNode(x){
        this.val = x;
        this.next = null;
    }*/
    
    function FindKthToTail(head, k) {
      let right = head;
      for (let i = 0; i < k; ++i) {
        if (right === null) {
          // 链表长度小于k
          return null;
        }
        right = right.next;
      }
    
      let left = head;
      while (right) {
        left = left.next;
        right = right.next;
      }
    
      return left;
    }
    

    2.反转链表

    问题描述:

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

    /*function ListNode(x){
        this.val = x;
        this.next = null;
    }*/
    function ReverseList(pHead) {
      // write code here
      let prev = null; // 上一个节点
      var curr;
      while (pHead) {
        curr = pHead; // 当前节点
        pHead = pHead.next;
        curr.next = prev;
        prev = curr;
      }
      return prev;
    }
    

    3.合并两个排序的链表

    问题描述:

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

    解题思路:
    设置一个“哨兵节点”叫 pHead,整体流程如下:

    • 如果 pHead1 和 pHead2,均没遍历完:

      • 如果 pHead1.val <= pHead2.val,那么当前 node 的 next 指向 pHead1。并且移动 pHead1 指针。
      • 否则,当前 node 的 next 指向 pHead2,移动 pHead2 指针。
      • 移动 node 指针
      • 继续循环
    • 否则,结束循环:

      • 如果 pHead1 未遍历完,node 的 next 指向 pHead1
      • 如果 pHead2 未遍历玩,node 的 next 指向 pHead2

    时间复杂度是 O(N),空间复杂度是 O(1)。代码如下:

    /*function ListNode(x){
        this.val = x;
        this.next = null;
    }*/
    function Merge(pHead1, pHead2) {
      // write code here
      if (!pHead1) {
        // 如果pHead1链表不存在,就返回pHead2
        return pHead2;
      }
      if (!pHead2) {
        // 如果pHead2链表不存在,就返回pHead1
        return pHead1;
      }
    
      let pHead = new ListNode(-1); // 新建一个‘哨兵节点’
      let node = pHead; // 头节点的指针
    
      while (pHead1 && pHead2) {
        // pHead1 和 pHead2 都存在时
        if (pHead1.val <= pHead2.val) {
          node.next = pHead1;
          pHead1 = pHead1.next;
        } else {
          node.next = pHead2;
          pHead2 = pHead2.next;
        }
        node = node.next;
      }
    
      if (pHead1) {
        // pHead1 链表长度大于 pHead2
        node.next = pHead1;
      }
      if (pHead2) {
        // pHead2 链表长度大于 pHead1
        node.next = pHead2;
      }
      return pHead.next; // pHead是-1,所以是pHead.next
    }
    

    4.树的子结构

    问题描述:

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

    /* function TreeNode(x) {
        this.val = x;
        this.left = null;
        this.right = null;
    } */
    
    function HasSubtree(pRoot1, pRoot2) {
      // 当pRoot2的根节点与pRoot1的根节点不同时就需要对pRoot1的左右子树进行遍历
      // write code here
      if (pRoot1 == null || pRoot2 == null) {
        // pRoot1 pRoot2 有一个为null,结构就为false
        return false;
      }
      return (
        judgeSubtree(pRoot1, pRoot2) || // pRoot2是不是pRoot1的子结构
        HasSubtree(pRoot1.left, pRoot2) || // pRoot1的左子树中有没有pRoot2
        HasSubtree(pRoot1.right, pRoot2) // pRoot1的右子树中有没有pRoot2
      );
    }
    function judgeSubtree(root1, root2) {
      // 对root2进行遍历判断root2 是不是root1 的子结构
      if (!root2) {
        return true;
      }
      if (!root1) {
        return false;
      }
      if (root1.val !== root2.val) {
        return judgeSubtree(root1.left, root2) || judgeSubtree(root1.right, root2);
      }
      return (
        judgeSubtree(root1.left, root2.left) &&
        judgeSubtree(root1.right, root2.right)
      );
    }
    
  • 相关阅读:
    chartControl ViewType.Bar 用法测试
    DevExpress ChartControl ViewType.Line
    全角半角转换
    万能打印 下载
    小程序-登陆
    ASPxGridView 选中主表一行数据,从表自动选中(勾选)对应的行
    ASPxGridView 添加勾选列--全选 和 后端获取勾的行ID
    ASPxGridView 用法
    JS动态创建元素
    年会抽奖 抽奖系统 抽奖软件 C# Winform
  • 原文地址:https://www.cnblogs.com/muzidaitou/p/12716100.html
Copyright © 2011-2022 走看看