【LeetCode Solutions】LeetCode 热题 100 题解(16 ~ 20)

发布于:2025-07-27 ⋅ 阅读:(17) ⋅ 点赞:(0)

普通数组 - LeetCode 238. 除自身以外数组的乘积(中等)

【题目描述】

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

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

不要使用除法,且在 O ( n ) O(n) 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 < = n u m s . l e n g t h < = 1 0 5 2 <= nums.length <= 10^5 2<=nums.length<=105
− 30 < = n u m s [ i ] < = 30 -30 <= nums[i] <= 30 30<=nums[i]<=30
输入保证数组 answer[i] 在 32 位整数范围内

进阶:你可以在 O ( 1 ) O(1) O(1) 的额外空间复杂度内完成这个题目吗?(出于对空间复杂度分析的目的,输出数组不被视为额外空间)


【分析】

本题是前缀和的思想,不考虑空间要求的情况下我们可以预处理出两个数组 p [ i ] p[i] p[i] s [ i ] s[i] s[i] 分别表示 i i i 之前所有数的乘积( n u m s [ 0 ] ∗ n u m s [ 1 ] ∗ ⋯ ∗ n u m s [ i − 1 ] nums[0] * nums[1] * \dots * nums[i - 1] nums[0]nums[1]nums[i1])以及 i i i 之后所有数的乘积( n u m s [ i + 1 ] ∗ n u m s [ i + 2 ] ∗ ⋯ ∗ n u m s [ n − 1 ] nums[i + 1] * nums[i + 2] * \dots * nums[n - 1] nums[i+1]nums[i+2]nums[n1])。

题目要求我们只能开一个额外的答案数组,那么我们可以将数组 s s s 省去,先在输出数组中预处理出前缀乘积 p p p,然后我们再倒序遍历数组,遍历的过程中用一个变量记录当前的后缀乘积即可。


【代码】

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n = nums.size();
        vector<int> res(n);
        res[0] = 1;  // 边界初始化
        for (int i = 1; i < n; i++)
            res[i] = res[i - 1] * nums[i - 1];  // res[i] 表示 [0, i - 1] 区间中所有元素的乘积
        for (int i = n - 1, mul = 1; ~i; i--)
            res[i] *= mul, mul *= nums[i];  // mul 表示 [i + 1, n - 1] 区间中所有元素的乘积
        return res;
    }
};

普通数组 - LeetCode 41. 缺失的第一个正数(困难)

【题目描述】

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

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

【示例 1】

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

【示例 2】

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

【示例 3】

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

【提示】

1 ≤ n u m s . l e n g t h ≤ 5 ∗ 1 0 5 1\le nums.length\le 5 * 10^5 1nums.length5105
− 2 31 ≤ n u m s [ i ] ≤ 2 31 − 1 -2^{31}\le nums[i]\le 2^{31} - 1 231nums[i]2311


【分析】

注意本题的时空复杂度,不能用排序以及哈希表之类的做法。

我们可以用置换的方法求解,我们记 n n n n u m s nums nums 的长度,因此答案一定在 1 ∼ n + 1 1\sim n+1 1n+1 之间(因为最完美的情况是 n u m num num 中有 1 ∼ n 1\sim n 1n)。

我们利用两两交换的方法将 n u m num num 中在 1 ∼ n 1\sim n 1n 范围内的数放置到其对应的位置上,也就是 nums[i] = i + 1。但其中有若干个位置上的数是错误的,每一个错误的位置就代表了一个缺失的正数。以 [3, 4, -1, 1] 为例,置换后的数组应当为 [1, -1, 3, 4],我们就可以知道缺失的数为 2 2 2

注意在交换的过程中应判断两数是否相等防止死循环。


【代码】

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        for (int i = 0; i < n; i++)
            // 将当前数置换到其对应的位置 num[i] - 1
            while (nums[i] > 0 && nums[i] <= n && nums[i] != nums[nums[i] - 1])
                swap(nums[i], nums[nums[i] - 1]);
        for (int i = 0; i < n; i++)
            if (nums[i] != i + 1) return i + 1;  // 该位置上没有对应的正整数说明缺失了
        return n + 1;  // 1 ~ n 全部没有缺失
    }
};

矩阵 - LeetCode 73. 矩阵置零(中等)

【题目描述】

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

【示例 1】

在这里插入图片描述

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

【示例 2】

在这里插入图片描述

输入: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 = = m a t r i x . l e n g t h m == matrix.length m==matrix.length
n = = m a t r i x [ 0 ] . l e n g t h n == matrix[0].length n==matrix[0].length
1 ≤ m , n ≤ 200 1\le m, n\le200 1m,n200
− 2 31 ≤ m a t r i x [ i ] [ j ] ≤ 2 31 − 1 -2^{31}\le matrix[i][j]\le 2^{31}-1 231matrix[i][j]2311


【分析】

我们需要用原矩阵的第一行来记录每一列是否有 0,用第一列来记录每一行是否有 0。但是第一行与第一列是否有 0 的信息无法保存,因此还需要使用两个额外的变量来记录第一行与第一列是否有 0。


【代码】

class Solution {
public:
    void setZeroes(vector<vector<int>>& g) {
        bool r0 = false, c0 = false;  // 第一行或者第一列是否有 0
        for (int i = 0; i < g[0].size(); i++)  // 判断第一行是否有 0
            if (!g[0][i]) { r0 = true; break; }
        for (int i = 0; i < g.size(); i++)  // 判断第一列是否有 0
            if (!g[i][0]) { c0 = true; break; }
        for (int i = 1; i < g.size(); i++)  // 判断其余行是否有 0
            for (int j = 1; j < g[0].size(); j++)
                if (!g[i][j]) { g[i][0] = 0; break; }
        for (int i = 1; i < g[0].size(); i++)  // 判断其余列是否有 0
            for (int j = 1; j < g.size(); j++)
                if (!g[j][i]) { g[0][i] = 0; break; }
        for (int i = 1; i < g[0].size(); i++)  // 遍历第一行,将为 0 的元素所在的列置零
            if (!g[0][i])
                for (int j = 1; j < g.size(); j++)
                    g[j][i] = 0;
        for (int i = 1; i < g.size(); i++)  // 遍历第一列,将为 0 的元素所在的行置零
            if (!g[i][0])
                for (int j = 1; j < g[0].size(); j++)
                    g[i][j] = 0;
        if (r0) for (int i = 0; i < g[0].size(); i++) g[0][i] = 0;  // 第一行置零
        if (c0) for (int i = 0; i < g.size(); i++) g[i][0] = 0;  // 第一列置零
    }
};

矩阵 - LeetCode 54. 螺旋矩阵(中等)

【题目描述】

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

【示例 1】

在这里插入图片描述

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

【示例 2】

在这里插入图片描述

输入: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 = = m a t r i x . l e n g t h m == matrix.length m==matrix.length
n = = m a t r i x [ i ] . l e n g t h n == matrix[i].length n==matrix[i].length
1 ≤ m , n ≤ 10 1\le m, n\le 10 1m,n10
− 100 ≤ m a t r i x [ i ] [ j ] ≤ 100 -100\le matrix[i][j]\le 100 100matrix[i][j]100


【分析】

分别设置向右、向下、向左、向上四个方向向量,然后模拟一遍即可,走出界或是已经遍历过了改变一下方向即可。


【代码】

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        int n = matrix.size(), m = matrix[0].size();
        int dx[] = { 0, 1, 0, -1 }, dy[] = { 1, 0, -1, 0 };  // 分别表示右、下、左、上的方向向量
        vector<int> res;
        for (int i = 0, x = 0, y = 0, d = 0; i < n * m; i++) {  // 总共遍历 n * m 个点
            res.push_back(matrix[x][y]);
            matrix[x][y] = INT_MIN;  // 遍历过的数修改为 INT_MIN
            int nx = x + dx[d], ny = y + dy[d];
            if (nx < 0 || nx >= n || ny < 0 || ny >= m || matrix[nx][ny] == INT_MIN) d = (d + 1) % 4;
            x += dx[d], y += dy[d];
        }
        return res;
    }
};

矩阵 - LeetCode 48. 旋转图像(中等)

【题目描述】

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

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

【示例 1】

在这里插入图片描述

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

【示例 2】

在这里插入图片描述

输入: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 = = m a t r i x . l e n g t h = = m a t r i x [ i ] . l e n g t h n == matrix.length == matrix[i].length n==matrix.length==matrix[i].length
1 ≤ n ≤ 20 1\le n\le 20 1n20
− 1000 ≤ m a t r i x [ i ] [ j ] ≤ 1000 -1000\le matrix[i][j]\le 1000 1000matrix[i][j]1000


【分析】

我们先给出一个变换过程的例子:

1 2 3      1 4 7      7 4 1
4 5 6  =>  2 5 8  =>  8 5 2
7 8 9      3 6 9      9 6 3

该过程很简单,但是没有接触过类似题目的话确实很难想出来,首先沿着主对角线进行翻转,然后沿着列的中轴进行翻转即可。


【代码】

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n = matrix.size();
        // 沿对角线翻转
        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 >> 1; j++)
                swap(matrix[i][j], matrix[i][n - 1 - j]);
    }
};

网站公告

今日签到

点亮在社区的每一天
去签到