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

两道算法题

两道算法题

合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1nums2,另有两个整数 mn ,分别表示 nums1nums2 中的元素数目。

请你 合并 nums2nums1 中,使合并后的数组同样按 非递减顺序 排列。

**注意:**最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n

示例 1:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

示例 2:

输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。

示例 3:

输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

提示:

  • nums1.length == m + n
  • nums2.length == n

代码如下:

class Solution {
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {int i=m-1;//nums1下标最后一个有效元素int j=n-1;//nums2小标最后一个有效元素int k=m+n-1;//扩容后的while(j>=0){if(i>=0&&nums1[i]>nums2[j]){nums1[k--]=nums1[i--];}else{nums1[k--]=nums2[j--];}}}
};

一、题目核心要求

题目要求很简单:

  • •你有两个**已经排好序(非递减)**的数组:nums1nums2
  • nums1的总长度是 m + n,但有效元素只有前 m,后面 n个位置是 0(预留出来给你放 nums2的元素)。
  • •你要把 nums2合并到 nums1中,并且合并后的 nums1仍然是有序的。
  • 不能返回新数组,必须直接修改 nums1

二、代码思路解析

class Solution {
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {int i = m - 1;      // nums1 有效部分的最后一个元素下标int j = n - 1;      // nums2 的最后一个元素下标int k = m + n - 1;  // nums1 最终位置的最后一个位置// 从后往前比较,选较大的放在 nums1 的末尾while (j >= 0) {if (i >= 0 && nums1[i] > nums2[j]) {nums1[k--] = nums1[i--];} else {nums1[k--] = nums2[j--];}}}
};

关键点:

  1. 1.为什么从后往前? •因为 nums1后面是空位(0),如果从前往后合并,会覆盖 nums1中还没比较的元素。 •从后往前合并,可以利用 nums1 尾部的空位,不会破坏还未比较的数据。
  2. 2.三个指针的作用: •i:指向 nums1有效部分的最后一个元素(初始为 m-1)。 •j:指向 nums2的最后一个元素(初始为 n-1)。 •k:指向 nums1最终结果的最后一个位置(初始为 m+n-1)。
  3. 3.循环逻辑: •比较 nums1[i]nums2[j],把较大的那个数放到 nums1[k]。 •然后对应的指针(ij)和 k往前移一位。 •循环条件是 j >= 0,意思是只要 nums2中还有元素没处理完,就继续。 •如果 nums2的元素先用完了,那么 nums1前面剩下的元素本来就在正确的位置,不需要再移动。

三、举例说明

用示例 1 来模拟一下:

nums1 = [1, 2, 3, 0, 0, 0], m = 3
nums2 = [2, 5, 6],         n = 3

初始:

i = 2 (指向3), j = 2 (指向6), k = 5

步骤

  1. 1.比较 3 和 6 → 6 大,把 6 放到 k=5:[1,2,3,0,0,6],j=1, k=4
  2. 2.比较 3 和 5 → 5 大,把 5 放到 k=4:[1,2,3,0,5,6],j=0, k=3
  3. 3.比较 3 和 2 → 3 大,把 3 放到 k=3:[1,2,3,3,5,6],i=1, k=2
  4. 4.比较 2 和 2 → 一样大,走 else,把 2 放到 k=2:[1,2,2,3,5,6],j=-1, k=1
  5. 5.j < 0,循环结束。结果正确。

四、如果你不理解的地方可能是

  1. 1.为什么循环条件是 while (j >= 0) •因为当 nums2的元素全部插入后,合并就完成了。nums1前面剩余的元素已经有序且位置正确。
  2. 2.如果 nums1的元素先比较完(i < 0)怎么办? •比如示例3:nums1 = [0], m=0, nums2=[1], n=1 •一开始 i=-1, j=0, k=0。 •因为 i<0,直接走 else,把 nums2 的元素依次放进 nums1 前面剩余位置即可。
  3. 3.时间复杂度 O(m+n),空间复杂度 O(1)(没有使用额外数组)。

移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

  • 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
  • 返回 k

用户评测:

评测机将使用以下代码测试您的解决方案:

int[] nums = [...]; // 输入数组
int val = ...; // 要移除的值
int[] expectedNums = [...]; // 长度正确的预期答案。// 它以不等于 val 的值排序。int k = removeElement(nums, val); // 调用你的实现assert k == expectedNums.length;
sort(nums, 0, k); // 排序 nums 的前 k 个元素
for (int i = 0; i < actualLength; i++) {assert nums[i] == expectedNums[i];
}

如果所有的断言都通过,你的解决方案将会 通过

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2,_,_]
解释:你的函数函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3,_,_,_]
解释:你的函数应该返回 k = 5,并且 nums 中的前五个元素为 0,0,1,3,4。
注意这五个元素可以任意顺序返回。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。

提示:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100

代码如下:

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

这个解法怎么理解?

想象你有两个指针:

  • 快指针:侦察兵,负责遍历整个数组,检查每个元素
  • 慢指针:建筑师,负责构建新的有效数组

工作流程

  1. 1.快指针从头到尾扫描数组
  2. 2.当快指针发现一个不等于val的元素时: •把这个元素复制到慢指针的位置 •慢指针向前走一步
  3. 3.当快指针发现等于val的元素时: •直接跳过,慢指针不动

举例说明:nums = [3,2,2,3], val = 3

初始:slow=0, fast=0, nums=[3,2,2,3]

第1步:fast=0, nums[0]=3等于val → 跳过,slow不动

数组不变,slow=0, fast=1

第2步:fast=1, nums[1]=2不等于val → 复制到slow位置

nums[0] = nums[1] → 数组变成[2,2,2,3]

slow从0变成1, fast=2

第3步:fast=2, nums[2]=2不等于val → 复制到slow位置

nums[1] = nums[2] → 数组变成[2,2,2,3]

slow从1变成2, fast=3

第4步:fast=3, nums[3]=3等于val → 跳过,slow不动

数组不变,slow=2, fast=4

循环结束,返回slow=2

最终结果:数组前2个元素[2,2]是有效部分,长度=2

为什么这个解法更简单?

  1. 1.逻辑清晰:快指针只管扫描,慢指针只管接收有效元素
  2. 2.符合直觉:就像把好的元素挑出来放到前面
  3. 3.易于理解:不需要考虑元素交换和边界问题

这个解法的时间复杂度也是O(n),空间复杂度O(1),而且代码只有6行,非常简洁!

http://www.dtcms.com/a/592754.html

相关文章:

  • 合肥建网站要多少钱网站空间和服务器
  • 网站优缺点分析网站备案怎么备案
  • 【Android】Android内存缓存LruCache与DiskLruCache的使用及实现原理
  • wps安装mathtype报错:错误‘48’:文件未找到:MathPage.WLL||终于解决MathPage.wll文件找不到问题(亲测有效!)
  • 苹果16Pro调研
  • 【共绩 ComfyUI 小课堂】Class 3 ComfyUI 升级更新完整指南:五种方法让你轻松跟上最新版本
  • 【系统架构设计师】2025年下半年真题论文回忆版及写作要点
  • 初识MYSQL —— 事务
  • 专题:2025AI时代的医疗保健业:应用与行业趋势研究报告|附130+份报告PDF、数据、可视化模板汇总下载
  • 电脑能控电脑控--Analog Discovery Python(1)
  • 入门指南|从文件到图表:Highcharts对接数据库(CSV、Excel)实现数据同步绘制图表
  • 什么网站能接单做网站聊城做网站费用价位
  • Kernel
  • C语言变量与输入输出详解——从printf到scanf的全掌握
  • MATLAB倍频转换效率分析与最佳匹配角模拟
  • Resilience4j 入门与实战
  • 智能投资,快速回本:复合机器人如何缩短你的投资回收期?
  • 5 Repository 层接口
  • 新乡网站优化平台id怎么打开wordpress
  • 小网站推荐会展官方网站建设
  • Springboot 启动过程及源码分析
  • STM32进行步进电机控制(PWM模式+翻转模式)
  • 信号系统常见的整体特性分类
  • PPT: Pre-trained Prompt Tuning - 预训练提示调优详解
  • 【RK3568】- 文件系统打包
  • 项目四:Dify智能开发与应用(零售企业基于Dify搭建会员智能运营平台)
  • 公司网站开发费计入什么科目迅当网络深圳外贸网站建设
  • 【C++11】右值引用+移动语义+完美转发
  • 商城系统的部署流程
  • 云朵课堂网站开发怎么收费装修公司口碑