当前位置: 首页 > article >正文

数组类算法【leetcode】

704. 二分查找

2024.11.06

题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。力扣题目链接

二分查找 用于有序数组中,没有重复的数组。首先需要定义一个头(left)和尾(right),最后通过mid和target对比不断修改头和尾指向的位置。

【需要注意区间问题,根据区间的开和闭决定边界条件】

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        while(left <= right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] > target)
            {
                right = mid - 1;
            }
            else if(nums[mid] == target)
            {
                return mid;
            }
            else if(nums[mid] < target)
            {
                left = mid + 1;
            }
        }
        return -1;

    }
};

推荐练习 leetcode35. 

27.移除元素

2024.11.07

题目:给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。力扣题目链接

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

这里其实有序无序都可以,正常的调用内置函数的复杂度是O(n),是用的两个for循环进行暴力解。这里要求我们原地执行,所以用一个for循环解决。

【这里我们要知道数组的删除,其实和我们平时理解的删除并不一样,数组的删除前其实是将不需要的元素进行覆盖,内存中他还是存在的】

这里用到了快慢指针,一个fast和一个slow,fast用于遍历整个数组,所以for循环的执行条件就应该是当fast小于数组长度的时候就进行一次循环,而slow指针怎么变化呢?如果nums[fast]不是需要的val,那就令nums[fast] = nums[slow],当nums[fast] = val的时候,slow指针的位置不需要变,这样可以把slow看作一个新的数组,用于装不包含val值的数组,当nums[fast]再次不等于val的时候将nums[fast]再次赋给nums[slow],slow指针再次向后移动。

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slow = 0;
        int fast = 0;
        for(; fast < nums.size(); fast++)
        {
            if(val != nums[fast])
            {
            nums[slow] = nums[fast];
            slow++;
            }
        }
        return slow;
    }
};

977.有序数组的平方

2024.11.07

题目:给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。力扣题目链接

思路和上一题类似,也是用双指针,这里两头的平方一定会大于中间的值的平方,所以新建立一个数组从后往前放置原数组的平方的值。

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int left = 0;
        int right = nums.size() - 1;
        int k = nums.size() - 1;   //因为数组的两头的数字的绝对值一定大于中间的,所以result数组从后往前放
        vector<int> result(nums.size(), 0);
        for(; left <= right;)
        {
            if(nums[left] * nums[left] < nums[right] * nums[right])
            {   
                result[k--] = nums[right] * nums[right];
                right --;
            }
            else
            {
                result[k--] = nums[left] * nums[left];
                left ++;
            }
        }
        return result;
    }
};

209.长度最小的子数组

2024.11.08

这是第一道中等题,但其实也挺简单的力扣题目链接

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

1.暴力解

这道题目暴力解法当然是 两个for循环,然后不断的寻找符合条件的子序列,时间复杂度很明显是O(n^2)。

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX; // 最终的结果
        int sum = 0; // 子序列的数值之和
        int subLength = 0; // 子序列的长度
        for (int i = 0; i < nums.size(); i++) { // 设置子序列起点为i
            sum = 0;
            for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为j
                sum += nums[j];
                if (sum >= s) { // 一旦发现子序列和超过了s,更新result
                    subLength = j - i + 1; // 取子序列的长度
                    result = result < subLength ? result : subLength;
                    break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                }
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

2.最优解

滑动窗口,有点类似之前的双指针的解法,不断更新子序列的两头指针,只要窗口中的sum大于target,就把左边的指针往右移一格,如果sum一直小于target就右边的指针持续后移。那么我们就可以通过记录每次得到的小于sum的子数组,并每次进行比较,及时更新最小值。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int left = 0;
        int right = 0;
        int sum = 0;
        int length = 0;                     //滑动窗口的长度(子数组)

        //在算法中,当你需要找到一组数中的最小值时,可以将初始值设为 INT32_MAX,这样任何实际的数值都会比它小。
        int result = INT32_MAX;

        for(right=0;right < nums.size();right++)
        {
            sum += nums[right];
            while(sum >= target)
            {
                length = right - left + 1;  //截至sum 小于 target, 数组的长度(未必是最小的)
                if (result > length)
                {
                    result = length;        // 更新最小子数组长度
                }
                sum -= nums[left++];
            }
        }
        if(result == INT32_MAX)
            return 0;
        else
            return result;
    }
};

 不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。

 59.螺旋矩阵II

2024.11.08

这是第一道中等题,思路很简单,只需要注意边界条件,按顺序赋值就完了

题目:给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

思路:

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去.......【我按照左闭右开的原则】统一填充方式可以很大程度避免自己写到后面乱掉了。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
        int x = 0;
        int y = 0;
        int loop = n / 2;       //  循环次数
        int offset = 1;         // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int mid = n / 2;        //  n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int count = 1;          //  用来给矩阵中每一个空格赋值
        int i, j;
        while(loop--)
        {
            i = x; 
            j = y;

            for(;j < n - offset;j++)
            {
                res[i][j] = count++;
            }
            //第一个for循环完之后,j = n - offset

            for(;i < n - offset;i++)
            {
                res[i][j] = count++;
            }
            //第二个for循环完之后,i = n - offset

            for(;j > y;j--)
            {
                res[i][j] = count++;
            }

            for(;i > x;i--)
            {
                res[i][j] = count++;
            }

 // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            x++;
            y++;

 // offset 控制每一圈里每一条边遍历的长度
            offset++;
        }
            if (n % 2) 
            {
                res[mid][mid] = count;
            }
        return res;
    }
};


http://www.kler.cn/a/389884.html

相关文章:

  • Linux第四讲:Git gdb
  • 学Linux的第八天
  • Java学习--网络编程
  • Spark 核心概念与宽窄依赖的详细解析
  • 使用HTML、CSS和JavaScript创建动态圣诞树
  • uniapp打包华为,提示请提供64位版本软件包后再提交审核
  • 「IDE」VS2022插件 Visual Assist X 番茄助手介绍说明
  • Python小游戏24——小恐龙躲避游戏
  • 使用 Elasticsearch 构建食谱搜索(一)
  • RSTP的配置
  • DNS Resolver解析服务器出口IP查询
  • 2024 年 Apifox 和 Postman 对比介绍详细版
  • vue3 动态路由+动态组件+缓存应用
  • 华为数通HCIA系列第5次考试-【2024-46周-周一】
  • 吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)4.9-4.10
  • 计算机课程管理:Spring Boot实现的工程认证框架
  • 基于FPGA FPD-Link(LVDS7:1)与FPD-Link IIIII实现与定制
  • 人才流失预测模型(机器学习)
  • SpringBoot中的响应式编程和WebFlux入门
  • Unity——配置文件的使用
  • ceph介绍和搭建
  • 无人驾驶汽车——AI技术在交通领域的进展与未来展望
  • C语言 | Leetcode C语言题解之第560题和为K的子数组
  • 学习笔记大导航
  • GitHub Org如何运营
  • 新标准大学英语综合教程1课后习题答案PDF第三版