「LeetCode」剑指Offer数组算法题解

139 阅读1分钟

01、数组中重复的数字

  • 题目描述

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

  • 解题思路

遍历数组,每次遇到索引为 i 的新数字 nums[i] 时,将其交换至索引为 nums[i] 的 nums[nums[i]] 处。而当遍历遇到一个重复数字 x 时,一定有 nums[x] == x (因为第一次遇到 x 时已经将其交换至 nums[x] 处了)。利用以上方法,即可得到一组重复数字。

  • 代码实现
let findRepeatNumber = function(nums) {
    // 遍历数组 nums ,设索引初始值为 i = 0
    let i = 0;
    while(i < nums.length){
        //若 nums[i] == i 说明此数字已在对应索引位置,无需交换
        if(nums[i] == i) {
            i++;
            continue;
        }
        //若 nums[nums[i]] == nums[i] 说明索引 nums[i] 处的元素值也为 nums[i]
        if(nums[nums[i]] == nums[i]) return nums[i];
        //交换索引为 i 和 nums[i] 的元素值,将此数字交换至对应索引位置
        let tmp = nums[i];
        nums[i] = nums[tmp];
        nums[tmp] = tmp;
    }
    //若遍历完毕尚未返回,则返回 -1 ,代表数组中无相同值
    return -1;
};
// 时间复杂度为O(N),遍历数组使用 O(N),每轮遍历的判断和交换操作使用 O(1)。
// 空间复杂度为O(1),使用常数复杂度的额外空间。

02、二维数组中的查找

  • 题目描述

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

  • 解题思路

若使用暴力法遍历矩阵 matrix ,则时间复杂度为 O(MN) 。暴力法未利用矩阵 “从上到下递增、从左到右递增” 的特点,显然不是最优解法。 本题解利用矩阵特点引入标志数,并通过标志数性质降低算法时间复杂度。

  • 代码实现
let findNumberIn2DArray = function(matrix, target) {
    //从矩阵 matrix 左下角元素(索引设为 i、j )开始遍历,并与目标值对比
    let i = matrix.length - 1;
    let j = 0;
        while(i >= 0 && j < matrix[0].length){
        //当 matrix[i][j] > target 时,行索引向上移动一格,消去矩阵第 i 行元素
        if(matrix[i][j] > target) i--; 
        //当 matrix[i][j] < target 时,列索引向右移动一格,消去矩阵第 j 列元素
        else if(matrix[i][j] < target) j++; 
        //当 matrix[i][j] == target 时,返回 true
        else return true; 
    } 
    //若行索引或列索引越界,则代表矩阵中无目标值,返回 false
    return false; 
};
//时间复杂度 O(M+N),其中,N 和 M 分别为矩阵行数和列数,此算法最多循环 M+N 次。
//空间复杂度 O(1),指针i、j 使用常数大小额外空间。