剑指offer 第二章

面试题 4

题目描述

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

示例

现有矩阵 matrix 如下:

[

[1,   4,  7, 11, 15],

[2,   5,  8, 12, 19],

[3,   6,  9, 16, 22],

[10, 13, 14, 17, 24],

[18, 21, 23, 26, 30]

]

给定 target = 5,返回 true;给定 target = 20,返回 false。

限制:

  1. 0 <= n <= 1000
  2. 0 <= m <= 1000

链接:https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof

思路

每次用右上角的元素于目标值比较,那么就有3种可能

  1. target == 右上角元素,直接返回true;
  2. target > 右上角元素,说明目标值只可能在当前行的下方,因此可以舍弃当前行;
  3. target < 右上角元素,说明目标值只可能在当前列的左边,因此可以舍弃当前列;

Hit:也可以每次和左下角的元素对比,但是不能和左上角和右下角的元素对比

Code

class Solution {
   
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
   
        // 注意二维数组判定
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0)
            return false;
        int row = matrix.length - 1; // 二维数组行索引
        int col = matrix[0].length -1 ; // 二维数组列索引最大值
        int i = 0;// 从第一行开始遍历
        // 注意行列边界条件
        while ( i <= row && col >= 0){
   
            // 右上角值恰好等于 目标值 直接退出
           if (matrix[i][col] == target){
   
               return true;
           } else if (matrix[i][col] > target) {
    // 右上角值大于 目标值,则舍弃最后一列
               col = col -1;
           }else {
    // 右上角值 小于 目标值,则舍弃最上面一行
               i++;
           }
        }
        return false;
    }
}

复杂度分析

时间复杂度:O(m+n)

空间复杂度:O(1)

面试题 5

题目描述

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

示例

输入:s = "We are happy."
输出:"We%20are%20happy."

限制:
0 <= s 的长度 <= 10000

链接:https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof

思路

step 1:统计原字符串中空格的个数 space

step 2:新建一个字符数组,长度是原来字符串长度 加上 space*2

step 3:用两个指针分别指向原字符串和新建字符串的末尾,如果原来字符串中元素不是空格,那么就把这个元素复制到新字符串中,两个指针先前移动一格;如果原字符串中元素是空格,则新字符串从后往前依次赋值为 ‘0’ 、‘2’ 、’%’,并将新字符串指针先前移动3格,原字符串指针移动1格。直到遍历完原字符串所有元素。

Code

public class Solution {
   
    public  String replaceSpace(String s) {
   
        int space = 0;// 空格数
        char[] array = s.toCharArray();
        // 统计原字符串中空格个数
        for (int i = 0 ; i < array.length;i++){
   
            if (array[i] == ' ')
                space++;
        }
        // 新定义一个字符创数组 长度是原来长度加上替换空格后的长度
        char[] newString = new char[array.length + space * 2];
        int indexOfOld = array.length - 1; // 指向原字符串的末尾
        int indexOfNew = newString.length -1 ; // 指向新字符串的末尾
        while (indexOfOld >= 0 && 0 <= indexOfNew) {
   
            // 遍历原字符串 当前字符不是空格就从后往前复制到新字符创中
            if (array[indexOfOld] != ' '){
   
                newString[indexOfNew--] = array[indexOfOld];
            } else {
   
                // 否则,将原字符串的空格在新字符串中替换成 %20 新字符串的指针先前移动三个位置
                newString[indexOfNew--] = '0';
                newString[indexOfNew--] = '2';
                newString[indexOfNew--] = '%';
            }
            indexOfOld--;
        }
//        newString.toString(); // 这个方法返回的是 字符串的地址
//        return Arrays.toString(newString); // 不能用Arrays.toString()方法 该方法返回一个string 类型的 list 而题目要求字符串
        return String.valueOf(newString);
    }
}

复杂度分析

时间复杂度:O(n)

空间复杂度:O(n)

面试题 6

题目描述

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

示例 :

输入:head = [1,3,2]
输出:[2,3,1]

限制
0 <= 链表长度 <= 10000

链接:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof

思路

可以遍历一遍链表,依次把链表元素压入栈中,再依次弹出栈中元素到一个数组中即可

Code

class ListNode {
   
    int val;
    ListNode next;
    ListNode(int x) {
    val = x; }
}
public class Solution {
   
    public int[] reversePrint(ListNode head) {
   
        if (head == null)
            return new int[0] ; // 链表为空,则返回空数组
        Stack<Integer> stack = new Stack<>(); // 定义一个元素类型为整型的栈
        while (head != null) {
   
            // 将每个节点元素依次入栈
            stack.push(head.val);
            head = head.next;
        }
        int number = stack.size();// 获取链表节点个数
        int[] result = new int[number]; // 最终打印值
        for (int i = 0; i < number; i++){
   
            // 栈中元素依次存入 result中
            result[i] = stack.pop();
        }
        return result;
    }
}

复杂度分析

时间复杂度:O(n)

空间复杂度:O(n)

面试题 7

题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
    3
   / \
  9  20
    /  \
   15   7

限制:
0 <= 节点个数 <= 5000

链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof

思路

前序遍历的第一个节点是根节点,只要找到根节点在中序遍历中的位置,在根节点之前被访问的节点都位于左子树,在根节点之后被访问的节点都位于右子树,由此可知左子树和右子树分别有多少个节点。

由于树中的节点数量与遍历方式无关,通过中序遍历得知左子树和右子树的节点数量之后,可以根据节点数量得到前序遍历中的左子树和右子树的分界,因此可以进一步得到左子树和右子树各自的前序遍历和中序遍历,可以通过递归的方式,重建左子树和右子树,然后重建整个二叉树。

使用一个 Map 存储中序遍历的每个元素及其对应的下标,目的是为了快速获得一个元素在中序遍历中的位置。调用递归方法,对于前序遍历和中序遍历,下标范围都是从 0 到 n-1,其中 n 是二叉树节点个数。

递归方法的基准情形有两个:判断前序遍历的下标范围的开始和结束,若开始大于结束,则当前的二叉树中没有节点,返回空值 null。若开始等于结束,则当前的二叉树中恰好有一个节点,根据节点值创建该节点作为根节点并返回。

若开始小于结束,则当前的二叉树中有多个节点。在中序遍历中得到根节点的位置,从而得到左子树和右子树各自的下标范围和节点数量,知道节点数量后,在前序遍历中即可得到左子树和右子树各自的下标范围,然后递归重建左子树和右子树,并将左右子树的根节点分别作为当前根节点的左右子节点。

Code


                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值