408相关算法刷题【数组篇】

LeetCode 1. 两数之和

题目链接

https://leetcode.cn/problems/two-sum/

思路1 暴力枚举

  1. 两重循环枚举下标 i,ji,j,然后判断 nums[i]+nums[j] 是否等于 target。

  2. 复杂度O(n^2)

AC代码1

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) &#123;
        vector<int> res;
        for(int i = 0; i < nums.size(); i ++)
        &#123;
            for(int j = 0; j < i; j ++)
            &#123;
                if(nums[i] + nums[j] == target)
                &#123;
                    res = vector<int> &#123;i, j&#125;;
                &#125;
            &#125;
            if(res.size() > 0) break;
        &#125;
        return res;
    &#125;
&#125;;

思路2 哈希表优化

  1. 使用哈希表边查找边存储

    查找target - num[i]是否在哈希表中 存在则返回
    将num[i]插入

  2. 哈希表的插入和查询操作的复杂度O(1),总复杂度O(n)

AC代码2

class Solution &#123;
public:
    vector<int> twoSum(vector<int>& nums, int target) &#123;
        vector<int> res;
        unordered_map<int, int> hash;
        // 边找边插入
        for(int i = 0; i < nums.size(); i ++)
        &#123;
            int another = target - nums[i];
            if(hash.count(another))
            &#123;
                res = vector<int> &#123;hash[another], i&#125;;
                break;
            &#125;
            hash[nums[i]] = i;
        &#125;
        return res;
    &#125;
&#125;;

LeetCode 31. 下一个排列

题目类型

  1. 数组
  2. 找规律题

题目链接

https://leetcode.cn/problems/next-permutation/

思路

建议画图用例子模拟

[2 3 5 4 1] => [2 4 1 3 5]

  1. 先用指针k从后往前找,找到第一个不满足nums[k - 1]>nums[k]的位置,即k即往后的都为降序
  2. 如果k在nums起始位置,则将整个数组反转,否则执行3
  3. 用指针t从指针k所在位置往右寻找,找到第一个大于nums[k-1]的数,此时整个数为nums[t - 1]
  4. 并且将nums[k-1]和nums[t - 1]互换
  5. 将k后面的序列反转

AC代码

class Solution &#123;
public:
    void nextPermutation(vector<int>& nums) &#123;
        int k = nums.size() - 1;
        // 2 3 5 4 1
        // 此时处于5这个位置
        while (k > 0 && nums[k - 1] >= nums[k]) k --;
        // 整个序列都是降序
        if (k <= 0) 
        &#123;
            reverse(nums.begin(), nums.end());
        &#125;
        else
        &#123;
            int t = k;
            while (t <= nums.size() - 1 && nums[t] > nums[k - 1]) t ++;
            swap(nums[k - 1], nums[t - 1]);
            reverse(nums.begin() + k, nums.end());
        &#125;
    &#125;
&#125;;

LeetCode 33. 搜索旋转排序数组

题目类型

  1. 双指针
  2. 二分(最优解)

题目链接

https://leetcode.cn/problems/search-in-rotated-sorted-array

思路

朴素做法和双指针算法比较简单,但是都没有利用旋转这个前提

二分做法:

  1. 利用二分寻找分界点位置
  2. 两个有序序列的分界点画图很容易知道是nums[0]
  3. 如果target大于nums[0]说明在第一个区间 如果小于nums[0]说明在第二个区间
  4. 在target所在区间再进行一次二分

AC代码1

// 朴素做法
class Solution &#123;
public:
    int search(vector<int>& nums, int target) &#123;
        for (int i = 0; i < nums.size(); i ++)
        &#123;
            if (nums[i] == target) return i;
        &#125;
        return -1;
    &#125;
&#125;;

AC代码2

// 双指针做法
class Solution &#123;
public:
    int search(vector<int>& nums, int target) &#123;
        int n = nums.size() - 1;
        int i = 0, j = n;
        while (i <= j)
        &#123;
            if (nums[i] != target) i ++;
            else return i;
            if (nums[j] != target) j --;
            else return j;
        &#125;
        return -1;
    &#125;
&#125;;

AC代码3(最优解)

class Solution &#123;
public:
    int search(vector<int>& nums, int target) &#123;
        if (nums.empty()) return -1;
        // 用二分先找到两个有序序列的分段点位置
        int l = 0, r = nums.size() - 1;
        while (l < r)
        &#123;
            int mid = l + r + 1 >> 1;
            if (nums[mid] >= nums[0]) l = mid;
            else r = mid - 1;
        &#125;

        // 这里两个序列有个分界点 Nums[0]
        if (target >= nums[0]) l = 0; // 在第一个区间
        else l = r + 1, r = nums.size() - 1; // 在第二个区间

        while (l < r)
        &#123;
            int mid = l + r >> 1;
            if (nums[mid] >= target) r = mid;
            else l = mid + 1;
        &#125;

        if (nums[r] == target) return r;
        else return -1;
    &#125;
&#125;;

LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置

题目类型

  1. 双指针
  2. 二分(最优解,代码简单)

题目链接

https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array

思路

使用双指针前后扫描定位,注意边界问题即可

使用二分最容易,也是最优解,代码最简洁

AC代码1

// 双指针
class Solution &#123;
public:
    vector<int> searchRange(vector<int>& nums, int target) &#123;
        vector<int> res;
        if (nums.size() == 0)
        &#123;
            res.push_back(-1), res.push_back(-1);
            return res;
        &#125;
        int i = 0, j = nums.size() - 1;
        if (i < j)
        &#123;
            while (i < nums.size() - 1 && nums[i] < target) i ++;
            while (j > 0 &&nums[j] > target) j --;
        &#125;

        if (nums[i] != target && nums[j] != target)
        &#123;
            res.push_back(-1); res.push_back(-1);
            return res;
        &#125;
        else if (i <= j && nums[i] == target && nums[j] == target)
        &#123;
            res.push_back(i); res.push_back(j);
        &#125;
        return res;
    &#125;
&#125;;

AC代码2

// 二分
class Solution &#123;
public:
    vector<int> searchRange(vector<int>& nums, int target) &#123;
        if (nums.empty()) return &#123;-1, -1&#125;;
        int n = nums.size();
        // 寻找左边界
        int l = 0, r = n - 1;
        while (l < r)
        &#123;
            int mid = l + r >> 1;
            if (nums[mid] >= target) r = mid;
            else l = mid + 1;
        &#125;
        // 存储好左边界l
        int L = l;
        if (nums[l] != target) return &#123;-1, -1&#125;;

        // 寻找右边界
        l = 0, r = n - 1;
        while (l < r)
        &#123;
            int mid = l + r + 1>> 1;
            if (nums[mid] <= target) l = mid;
            else r = mid - 1;
        &#125;
        return &#123;L, r&#125;;
    &#125;
&#125;;

LeetCode 35. 搜索插入位置

题目类型

二分

题目链接

https://leetcode.cn/problems/search-insert-position

思路

使用二分搜素比较简单 直接AC,这里只讲搜索左边界的思路(对应是AC代码1),右边界的思路(对应AC代码2)

  1. 使用二分搜索≤target数的位置l
  2. 如果target > nums[l],则插入位置为l+1,否则为l

AC代码1

// 二分写法一:
class Solution &#123;
public:
    int searchInsert(vector<int>& nums, int target) &#123;
        int n = nums.size();
        int l = 0, r = n - 1;
        while (l < r)
        &#123;
            int mid = l + r >> 1;
            if (nums[mid] >= target) r = mid;
            else l = mid + 1;
        &#125;
        if (target > nums[l]) return l + 1;
        else return l;
    &#125;
&#125;;

AC代码2

// 二分写法二
class Solution &#123;
public:
    int searchInsert(vector<int>& nums, int target) &#123;
        int n = nums.size();
        int l = 0, r = n - 1;
        while (l < r)
        &#123;
            int mid = l + r + 1 >> 1;
            if (nums[mid] <= target) l = mid;
            else r = mid - 1;
        &#125;
        if (target <= nums[r]) return r;
        else return r + 1;
    &#125;
&#125;;

LeetCode 41. 缺失的第一个正数

题目类型

  1. 哈希表
  2. 技巧法

题目链接

https://leetcode.cn/problems/first-missing-positive/

思路

方法一(哈希表):

  1. nums 中每个元素放入哈希表中
  2. 从res = 1开始,每次查询一次hash.count(res)
  3. 如果存在,则res++
  4. 如果不存在,返回res,res为所求结果

方法二:

  1. 如果满足条件nums[i] >= 0 && nums[i] < n && nums[i] != i && nums[i] != nums[nums[i]]
  2. 遍历nums数组,每次将nums[i]元素放到相应的i位置

AC代码1

class Solution &#123;
public:
    int firstMissingPositive(vector<int>& nums) &#123;
        unordered_set<int> hash;
        for (auto x : nums)
        &#123;
            hash.insert(x);
        &#125;
        int res = 1;
        while (hash.count(res)) res ++; 

        return res;
    &#125;
&#125;;

AC代码2

class Solution &#123;
public:
    int firstMissingPositive(vector<int>& nums) &#123;
        int n = nums.size();
        if (!n) return 1;

        // 映射一下
        for (auto&x : nums)
            if (x != INT_MIN) x --;

        for (int i = 0; i < n; i ++)
        &#123;
            while (nums[i] >= 0 && nums[i] < n && nums[i] != i && nums[i] != nums[nums[i]])
            &#123;
                swap(nums[i], nums[nums[i]]);
            &#125;
        &#125;

        // 查询
        for (int i = 0; i < n; i ++)
        &#123;
            if (nums[i] != i)
                return i + 1;
        &#125;
        return n + 1;
    &#125;
&#125;;

LeetCode 42. 接雨水

题目类型

  1. 题目链接

https://leetcode.cn/problems/trapping-rain-water/

思路

AC代码


LeetCode 45 跳跃游戏 II

题目类型

  1. 题目链接

https://leetcode.cn/problems/jump-game-ii/

思路

AC代码

class Solution &#123;
public:
    int jump(vector<int>& nums) &#123;
        int start = 0;
        int end = 1;
        int res = 0;
        while (end < nums.size())
        &#123;
            int maxPos = 0;
            // 能跳跃的最大距离
            for (int i = start; i < end; i ++)
            &#123;
                maxPos = max(maxPos, i + nums[i]);
            &#125;

            start = end;
            end = maxPos + 1;
            res ++;
        &#125;
        return res;
    &#125;
&#125;;

LeetCode 53. 最大子数组和

题目类型

  1. 动规

题目链接

https://leetcode.cn/problems/maximum-subarray/

思路

AC代码

class Solution &#123;
public:
    int maxSubArray(vector<int>& nums) &#123;
        int res = nums[0];
        for (int i = 1; i < nums.size(); i ++)
        &#123;
            nums[i] = max(nums[i], nums[i - 1] + nums[i]);
            res = max(res, nums[i]);
        &#125;
        return res;
    &#125;
&#125;;

LeetCode 54. 螺旋矩阵

题目类型

  1. 搜索

题目链接

https://leetcode.cn/problems/spiral-matrix/

思路

  1. 定义四个方向的向量
  2. 每次遇到边界或者已经访问过了就改变运动方向
  3. 使用变量d代表下一次运动方向,运动顺序依次是右(0) 下(1) 左(2)上(3),每次对d取模4,得到下一次运动方向向量

AC代码

class Solution &#123;
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) &#123;
        vector<int> res;
        int n = matrix.size();
        int m = matrix[0].size();
        if (!n) return res;
        vector<vector<bool>> st(n, vector<bool>(m));

        // 定义四个方向向量 右 下 左 上
        int dx[] = &#123;0, 1, 0, - 1&#125;, dy[] = &#123;1, 0, -1, 0&#125;;

        // d指的是下一次运动方向
        for (int i = 0, x = 0, y = 0, d = 0; i < n * m; i ++)
        &#123;
            res.push_back(matrix[x][y]);
            st[x][y] = true;

            // 计算下一次运动位置
            int a = x + dx[d], b = y + dy[d];
            if (a < 0 || a >= n || b < 0 || b >= m || st[a][b]) // 改变方向
            &#123;
                d = (d + 1) % 4;
                a = x + dx[d], b = y + dy[d];
            &#125;
            x = a, y = b;
        &#125;
        return res;
    &#125;
&#125;;

##

题目类型

  1. 题目链接

思路

AC代码


LeetCode 55. 跳跃游戏

题目类型

  1. 题目链接

https://leetcode.cn/problems/jump-game/

思路

AC代码

class Solution &#123;
public:
    bool canJump(vector<int>& nums) &#123;
        for (int i = 0, j = 0; i < nums.size(); i ++)
        &#123;
            if (i > j) return false;
            j = max(j, i + nums[i]);
        &#125;
        return true;
    &#125;
&#125;;

LeetCode 56. 合并区间

题目类型

  1. 贪心

题目链接

https://leetcode.cn/problems/merge-intervals/submissions/

思路

AC代码

class Solution &#123;
public:
    vector<vector<int>> merge(vector<vector<int>>& a) &#123;
         vector<vector<int>> res;
         if (!a.size()) return res;

        sort(a.begin(), a.end());

         int l = a[0][0], r = a[0][1];
         for (int i = 1; i < a.size(); i ++)
         &#123;
             if (a[i][0] > r) // 不相交
             &#123;
                 res.push_back(&#123;l, r&#125;);
                 l = a[i][0], r = a[i][1];
             &#125;
             else // 两个区间相交
             &#123;
                r = max(r, a[i][1]);
             &#125;
         &#125;
         res.push_back(&#123;l, r&#125;);
         return res;
    &#125;
&#125;;

##

题目类型

  1. 题目链接

思路

AC代码



 上一篇
408相关算法刷题【并查集】 408相关算法刷题【并查集】
AcWing 1250. 格子游戏题目类型 并查集 题目链接 https://www.acwing.com/problem/content/1252/ 思路 将该二维矩阵弄成一维来计算,对于 (x, y) 映射为x * n + y 每次
下一篇 
LeetCode刷题记31-40 LeetCode刷题记31-40
LeetCode 31. 下一个排列题目类型 数组 找规律题 题目链接 https://leetcode.cn/problems/next-permutation/ 思路建议画图用例子模拟 [2 3 5 4 1] => [2 4
  目录