【剑指offer】算法题题解

剑指offer算法题(由易到难)

刷算法一直都是很痛苦,这里题主将牛客网算法题通过率由高到低的顺序进行排列,按由易到难的顺序进行刷题,希望能给大家带来信心!

1.二叉树的深度

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

题解:
1.递归方法

public int TreeDepth(TreeNode root) {
     
    return root == null ? 0 : 1 + Math.max(TreeDepth(root.left), TreeDepth(root.right));
}

2.非递归方法
采用层序遍历+队列存储的方法
思路:

  • 借助队列,对二叉树进行层次遍历;
  • 在层次遍历的过程中,每次当队列中某一层的节点出队完成后,高度+1;
  • 关键点:判别队列中某一层节点出队完成的标准是什么?
    在出队之前,此时队列中记录的只有某一层节点,所以队列的大小就是某一层节点的个数。当此个数减到0的时候,则说明该层节点全部出队完成
链接:https://www.nowcoder.com/questionTerminal/435fb86331474282a3499955f0a41e8b?answerType=1&f=discussion
来源:牛客网

public int TreeDepth2(TreeNode root) {
     
      if(root == null)
          return 0;
      Queue<TreeNode> queue = new LinkedList();
      queue.add(root);
      int high = 0;
      int size;//用size控制high增长的次数和时机(同一层的元素没有完全退出队列的时候high不可以增加)
      TreeNode node;
      while(queue.size() != 0){
     
          size = queue.size();//队列长度
          while(size != 0){
     
              node = queue.poll();
              if(node.left != null)
                  queue.add(node.left);
              if(node.right != null)
                  queue.add(node.right);
              size--;//当size==0时说明同一层的元素遍历完成
          }
          high++;
      }
      return high;
  }

2.不用加减乘除做加法

题目描述
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

题解:
用到进制运算
两个二进制的相加结果是用一个异或门实现的;
两个二进制的进位结果是用一个与门来实现的。
执行加法 x ^ y
进位操作 ( x & y ) << 1
将两个结果循环操作直至进位为0,得到的加法结果则为最终结果

链接:https://www.nowcoder.com/questionTerminal/59ac416b4b944300b617d4f7f111b215?answerType=1&f=discussion
来源:牛客网

public class Solution {
     
    public int Add(int num1,int num2) {
     
         while(num2!=0){
     //当进位为0时加法完成
             int temp = num1^num2;//先查看非进位值
             num2 = (num1&num2)<<1;//再查看进位值
             num1 = temp;
         }  
         return num1;
    }
}

3.二叉树的镜像

【剑指offer】算法题题解_第1张图片
题解:
1.递归方式

    pblic void Mirror(TreeNode root) {
     
        if(root == null){
     
            return;
        }
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
        Mirror(root.left);
        Mirror(root.right);
    }
}

2.非递归方式
a.深度优先搜索,利用栈

链接:https://www.nowcoder.com/questionTerminal/564f4c26aa584921bc75623e48ca3011?answerType=1&f=discussion
来源:牛客网

import java.util.Stack;
public class Solution {
     
  public void Mirror(TreeNode root) {
     
 
    // 空树
    if (root == null) {
     
      return;
    }
    // 左右均为空
    if (root.left == null && root.right == null) {
     
      return;
    }
 
    // 用来遍历的栈
    Stack<TreeNode> stack = new Stack<TreeNode>();
 
    stack.push(root);
 
    TreeNode curNode;
    TreeNode tempNode;
 
    // 深度优先
    while (!stack.isEmpty()) {
     
      curNode = stack.pop();
      if(curNode == null) {
     
        continue;
      }
	if(curNode.left == null && curNode.right==null) {
     
        continue;
      }
      // 交换
      tempNode = curNode.left;
      curNode.left = curNode.right;
      curNode.right = tempNode;
      stack.push(curNode.left);
      stack.push(curNode.right);
    }
  }
}

b.广度优先,利用队列

import java.util.LinkedList;
import java.util.Queue;
public class Solution{
     
public void Mirror(TreeNode root) {
     
        if(root == null) return;
        Queue<TreeNode> nodes = new LinkedList<>();
        TreeNode curr, temp;
        nodes.offer(root);
        while(!nodes.isEmpty()){
     
            int len = nodes.size();
            for(int i = 0; i < len; i++){
     
                curr = nodes.poll();
                temp = curr.left;
                curr.left = curr.right;
                curr.right = temp;
                if(curr.left != null) nodes.offer(curr.left);
                if(curr.right != null) nodes.offer(curr.right);
            }
        }
    }
}

4.变态跳台阶

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

题解:
设 n 级台阶有f(n) 种跳法,根据最后一次跳台阶的数目可以分解为最后一次一级,则前面需要跳n-1 级,有f(n-1) 种跳法;最后一次跳两级,则前面需要跳n- 2 级,有f(n-2) 种跳法。以此类推 易知,
f(n)=f(n-1)+f(n-2)+……f(0)
f(n-1)=f(n-2)+……f(0)
两式相减得,
f(n)=2f(n-1) f(n)=2f(n−1)

链接:https://www.nowcoder.com/questionTerminal/22243d016f6b47f2a6928b4313c85387?f=discussion
来源:牛客网

public class Solution {
     
    public int JumpFloorII(int target) {
     
        if (target <= 0) {
     
            return -1;
        } else if (target == 1) {
     
            return 1;
        } else {
     
            return 2 * JumpFloorII(target - 1);
        }
    }
}

5.减绳子

题目描述
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

题解:
1.数学方法
4 : 2x2
5 : 2x3
6 : 3x3
7 : 2x2x3 或者4x3
8 : 2x3x3
9 : 3x3x3
10:2x2x3x3 或者4x3x3

可以看出剪出尽可能多的长度为3的片段,乘积最大。

public class Solution {
     
    public int cutRope(int target) {
     
      if(target==2)return 1;
      else if(target==3)return 2;
      else{
     
          int x=target/3;
          int y=target%3;
          if(y==1){
     
              return (int)Math.pow(3,x-1)*2*2;
          }else{
     
              return (int)Math.pow(3,x)*2;
          }
      }
    }
}

你可能感兴趣的:(知识总结,算法,数据结构,java)