剑指offer1~10题

4. 二维数组中的查找

题目描述:
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
在这里插入图片描述
解题思路:
我们知道这个二维数据的规律了,所以我们可以从右上角的那个数着手来,从右上角开始查找。矩阵中的一个数,它左边的数都比它小,下边的数都比它大。因此,从右上角开始查找,就可以根据 target 和当前元素的大小关系来缩小查找区间。
复杂度:O(M + N) + O(1)
代码:

public boolean Find(int target, int[][] matrix) {
    if (matrix == null || matrix.length == 0 || matrix[0].length == 0)
        return false;
    int rows = matrix.length, cols = matrix[0].length;
    int r = 0, c = cols - 1; // 从右上角开始
    while (r <= rows - 1 && c >= 0) {
        if (target == matrix[r][c])
            return true;
        else if (target > matrix[r][c])
    //如果target数大于最右边的数,肯定要换下一行,
  //因为l连最右边的数都小于target,所以左边的数肯定都小于target
  //先判断行,再判断列。从上到下,从右至左
            r++;
        else
            c--;
    }
    return false;
}

5. 替换空格

题目描述
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
在这里插入图片描述

6. 从尾到头打印链表

ListNode是由自己定义的java中的链表对象
类结构如下:
在这里插入图片描述
第一种解法:
递归思想:
在这里插入图片描述
在这里插入图片描述
第二种解法:
非递归:利用栈(利用栈的“先进后出”特性)
在这里插入图片描述

7. 重建二叉树(笔者对这个题还是有点小疑问)

题目描述
根据二叉树的前序遍历和中序遍历的结果,重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字
例如:
在这里插入图片描述
解题思路:
前序遍历的第一个值为根节点的值,使用这个值将中序遍历结果分成两部分,左部分为树的左子树中序遍历结果,右部分为树的右子树中序遍历的结果。

// 缓存中序遍历数组每个值对应的索引(这个数组贯穿全部过程)
private Map<Integer, Integer> indexForInOrders = new HashMap<>();

public TreeNode reConstructBinaryTree(int[] pre, int[] in) {//???那这个pre到底传中序还是前序呢????????
    for (int i = 0; i < in.length; i++)
        indexForInOrders.put(in[i], i);
    return reConstructBinaryTree(pre, 0, pre.length - 1, 0);
}

private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int inL) {
    if (preL > preR)
        return null;
    TreeNode root = new TreeNode(pre[preL]);//前序遍历的第一个值就是根节点
    int inIndex = indexForInOrders.get(root.val);
    int leftTreeSize = inIndex - inL;
    root.left = reConstructBinaryTree(pre, preL + 1, preL + leftTreeSize, inL);
    root.right = reConstructBinaryTree(pre, preL + leftTreeSize + 1, preR, inL + leftTreeSize + 1);
    return root;
}

8. 二叉树的下一个结点

题目描述:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针
节点的结构如下:
在这里插入图片描述
解题思路:
① 如果一个节点的右子树不为空,那么该节点的下一个节点是右子树的最左节点;
在这里插入图片描述
② 否则,向上找第一个左链接指向的树包含该节点的祖先节点。
在这里插入图片描述
代码如下:
在这里插入图片描述

9. 用两个栈实现队列

题目描述:
用两个栈来实现一个队列,完成队列的 Push 和 Pop 操作。

解题思路:
剑指offer的思路,用两个栈来实现队列,栈1的话用来入队,队列每进入一个元素就入栈1,栈2的话用来出队,队列如果要出队,首先判断栈2是不是空,是空,就把栈1弹出来进入栈2(因为栈是先入后出,两次先入后出就是先入先出了,负负得正嘛~),然后从栈2开始弹,如果栈2不为空,直接从栈2开始弹
源代码如下:
在这里插入图片描述

10.1 斐波那契数列

在这里插入图片描述
解题思路:
如果使用递归求解,会重复计算一些子问题。例如,计算 f(10) 需要递归计算 f(9) 和 f(8),计算 f(9) 需要递归计算 f(8) 和 f(7),可以看到 f(8) 被重复递归计算了。(解释:你想想,计算f(10)的时候f(8)已经被递归了,f(9)又要递归f(8)有必要吗?直接用刚才递归的结果就好啦)
在这里插入图片描述
解题思路:
递归是将一个问题划分成多个子问题求解,动态规划也是如此,但是动态规划会把子问题的解缓存起来,从而避免重复求解子问题。
在这里插入图片描述
优化方案:
考虑到第 i 项只与第 i-1 和第 i-2 项有关,因此只需要存储前两项的值就能求解第 i 项,从而将空间复杂度由 O(N) 降低为 O(1)。
在这里插入图片描述
由于题目中待求解的 n 小于 40,因此可以将前 40 项的结果先进行计算,之后就能以 O(1) 时间复杂度得到第 n 项的值了。
在这里插入图片描述

10.2 跳台阶

题目描述:
一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
解题思路:
解释:之所以return的是target-1和target-2是因为跳到第n阶台阶的最后一跳可能1步或者是2步,只有这两种可能,所以只需要把JumpFloor(target-1)+JumpFloor(target-2)算出来就可以得到总结果
在这里插入图片描述
从上面明显看出是斐波那契数列,所以还可以用下面的写法
在这里插入图片描述

10.3 矩形覆盖(小疑问:笔者也不是很明白这个题为什么跟斐波那契数列挂钩的)

题目描述:
我们可以用 21 的小矩形横着或者竖着去覆盖更大的矩形。请问用 n 个 21 的小矩形无重叠地覆盖一个 2*n 的大矩形,总共有多少种方法?
代码如下:
在这里插入图片描述

10.4 变态跳台阶

题目描述:
一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级… 它也可以跳上 n 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
解题思路:
跳到终点的最后一次跳可能是1级,也可能是2级,3,4,5…n
那么f(n)=f(n-1)+f(n-2)+f(n-3)+…+f(n-n),
按这个公式推出f(n-1)=f((n-1)-1)+f((n-1)-2)+…+f((n-1)-(n-1))=f(n-2)+f(n-3)+…f(n-n);
将上面两个式子相减得出f(n)=2*f(n-1),所以就有结论了
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40241957/article/details/84844582