20天 hot 100 速通计划-day04

发布时间 2023-08-08 11:58:07作者: Ba11ooner

普通数组

238. 除自身以外数组的乘积

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。

不要使用除法,且在 O(*n*) 时间复杂度内完成此题。

示例 1:

输入: nums = [1,2,3,4]
输出: [24,12,8,6]

示例 2:

输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

提示:

  • 2 <= nums.length <= 105
  • -30 <= nums[i] <= 30
  • 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内
class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
      int n = nums.size();
      vector<int> output(n, 1); // 初始化一个大小为n的输出数组,全部赋值为1

      int left = 1; // 从左边累积乘积
      int right = 1; // 从右边累积乘积

      // 计算左边乘积
      for (int i = 0; i < n; i++) {
          output[i] *= left;
          left *= nums[i];
      }

      // 计算右边乘积
      for (int i = n - 1; i >= 0; i--) {
          output[i] *= right;
          right *= nums[i];
      }

      return output;
    }
};

41. 缺失的第一个正数

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

示例 1:

输入:nums = [1,2,0]
输出:3

示例 2:

输入:nums = [3,4,-1,1]
输出:2

示例 3:

输入:nums = [7,8,9,11,12]
输出:1

提示:

  • 1 <= nums.length <= 5 * 105
  • -231 <= nums[i] <= 231 - 1

代码参考力扣官方题解

标记法

我们对数组进行遍历,对于遍历到的数 x,如果它在 [1,N] 的范围内,那么就将数组中的第 x−1 个位置(注意:数组下标从 0 开始)打上「标记」。在遍历结束之后,如果所有的位置都被打上了标记,那么答案是 N+1,否则答案是最小的没有打上标记的位置加 1

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();

        // 将所有非正整数置为n+1
        for (int& num : nums) {
            if (num <= 0) {
                num = n + 1;
            }
        }

        // 将出现过的正整数标记为负数
        for (int i = 0; i < n; ++i) {
            int num = abs(nums[i]);
            if (num <= n) {
                nums[num - 1] = -abs(nums[num - 1]);
            }
        }

        // 第一个未标记为负数的位置即为答案
        for (int i = 0; i < n; ++i) {
            if (nums[i] > 0) {
                return i + 1;
            }
        }

        return n + 1;  // 如果所有位置都标记为负数,则返回n+1
    }
};

个人认为更易于理解的方法:交换法

通过交换实现原地哈希(数值为 i 的数映射到下标为 i - 1 的位置)

除了打标记以外,我们还可以使用置换的方法,将给定的数组「恢复」成下面的形式:

如果数组中包含 x∈[1,N],那么恢复后,数组的第 x−1 个元素为 x。

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            while (nums[i] > 0 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) {
                // 将nums[i] 放置到对应位置上
              	// nums[i]=1 → 将 nums[i] 的值放到 nums[0]
              	// nums[i]=2 → 将 nums[i] 的值放到 nums[1]
              	// 即交换 nums[i] 和 num[nums[i] - 1]
                swap(nums[nums[i] - 1], nums[i]);
            }
        }
      	//交换完成后,理论上所有应该出现的正整数 i 会出现在下标为 i - 1 的位置
      	//换句话说,即理论上所有应该出现的正整数 i + 1 会出现在下标为 i  的位置
      	//漏了的就是缺失的第一个正数
        for (int i = 0; i < n; ++i) {
            if (nums[i] != i + 1) {
                return i + 1;
            }
        }
      	//都没漏,证明缺失的正整数是 n + 1
        return n + 1;
    }
};

矩阵

73. 矩阵置零

给定一个 *m* x *n* 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法

示例 1:

img

输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]

示例 2:

img

输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]

提示:

  • m == matrix.length
  • n == matrix[0].length
  • 1 <= m, n <= 200
  • -231 <= matrix[i][j] <= 231 - 1
class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        vector<int> column, row;
        for(int i = 0; i < matrix.size(); i++){
            for(int j = 0; j < matrix[0].size(); j++){
                if(matrix[i][j] == 0){
                    //第i行要清零
                    row.push_back(i);
                    //第j列要清零
                    column.push_back(j);
                }
            }
        }

        //清零列
        //遍历要清零的列
        for(int i = 0; i < column.size(); i++){
            //遍历行 ↓ ,遇到要清零的列置零
            for(int j = 0; j < matrix.size(); j++){
                matrix[j][column[i]] = 0;
            }
        }

        //清零行
        //遍历要清零的行
        for(int i = 0; i < row.size(); i++){
            //遍历列 → ,遇到要清零的行置零
            for(int j = 0; j < matrix[0].size(); j++){
                matrix[row[i]][j] = 0;
            }
        }
    }
};

54. 螺旋矩阵

给你一个 mn 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:

img

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

img

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 10
  • -100 <= matrix[i][j] <= 100

IMG_0900(20230808-105016)

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> result;
        if (matrix.empty()) {
            return result;
        }

      	//行数
        int m = matrix.size();
      	//列数
        int n = matrix[0].size();
      	//左右游标 [左闭右开)
        int left = 0, right = n;
      	//上下游标 [左闭右开)
        int top = 0, bottom = m;
      
        while (result.size() < m * n) {
            // 从左到右
            for (int i = left; i < right; i++) {
                result.push_back(matrix[top][i]);
            }
            top++;

            // 从上到下
            for (int i = top; i < bottom; i++) {
                result.push_back(matrix[i][right - 1]);
            }
            right--;

            // 从右到左
            if (top < bottom) {
                for (int i = right - 1; i >= left; i--) {
                    result.push_back(matrix[bottom - 1][i]);
                }
                bottom--;
            }

            // 从下到上
            if (left < right) {
                for (int i = bottom - 1; i >= top; i--) {
                    result.push_back(matrix[i][left]);
                }
                left++;
            }
        }

        return result;
    }
};

48. 旋转图像

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 1:

img

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

示例 2:

img

输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]

提示:

  • n == matrix.length == matrix[i].length
  • 1 <= n <= 20
  • -1000 <= matrix[i][j] <= 1000
class Solution {
public:
    // 旋转图像
  	// 纯技巧题,先主对角线翻转,再水平翻转,就是顺时针旋转 90 度
    void rotate(vector<vector<int>>& matrix) {
        int n = matrix.size();
        // 先进行主对角线翻转
      	// 对角线不用动,故起点为[i,i+1]
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                swap(matrix[i][j], matrix[j][i]);
            }
        }
        // 再进行水平翻转
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n / 2; j++) {
                swap(matrix[i][j], matrix[i][n - 1 - j]);
            }
        }
    }
};