【优选算法必刷100题】第001~002题(双指针算法):移动零、复写零问题求解

【优选算法必刷100题】第001~002题(双指针算法):移动零、复写零问题求解

🔥个人主页:艾莉丝努力练剑

❄专栏传送门:《C语言》《数据结构与算法》C语言刷题12天IO强训LeetCode代码强化刷题洛谷刷题C/C++基础知识知识强化补充C/C++干货分享&学习过程记录测试开发要点全知道Linux操作系统编程详解笔试/面试常见算法:从基础到进阶

🍉学习方向:C/C++方向学习者

⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平



目录

001  移动零

1.1  思路

1.2  算法原理

1.3  代码实现  

1.4  过程推算

002  复写零

2.1  思路

2.2  算法原理

2.3  代码实现  

2.4  过程推算

结尾


001  移动零

力扣链接:283. 移动零

力扣题解链接:双指针求解【移动零】问题

题目描述:

1.1  思路

双指针算法——

创建两个数组,cur和dest——

cur:从左往右扫描数组,遍历数组

dest:已处理的区间内,非零元素的最后一个位置

cur往后遍历数组的过程中:

1、遇到0元素:cur++;

2、遇到非零元素:swap(nums[dest+1],nums[cur]),然后dest++,cur++。

也就是说——

算法思路:

在本题中,我们可以用一个cur指针来扫描整个数组,另一个dest指针用来记录非零数序列的最后一个位置。根据cur在扫描过程中遇到的不同的情况,分类处理,实现数组的划分。

在cur遍历期间,使得[0 , dest]的元素全部都是非零元素,[dest + 1 , cur - 1]的元素都是零。

1.2  算法流程

1.2.1 

初始化cur = 0(用来遍历数组),dest = -1(指向非零元素序列的最后一个位置。因为刚开始我们也不知道最后一个非零元素到底在什么位置,因此初始化为-1)

1.2.2

cur依次往后遍历每个元素,遍历到的元素会有下面两种情况:

1、遇到的元素都是0,cur直接++。因为我们的目标是让[dest + 1 , cur - 1]内的元素全都是零,因此当cur遇到0的时候,直接++,就可以让0在cur - 1的位置上,从而在[dest + 1 , cur - 1]内;

2、遇到的元素不是0,dest++,并且交换cur位置和dest位置的元素(swap),之后让cur++,扫描下一个元素。

(1)因为dest指向的位置是非零元素区间的最后一个位置,如果扫描到一个新的非零元素,那么它的位置就应该在dest + 1的位置上,因此dest先自增1;

(2)dest++之后,指向的元素就是0元素(因为非零元素区间末尾的后一个元素就是0),因此可以交换到cur所处的位置上,实现[0 , dest]的元素全部都是非零元素,[dest + 1 , cur - 1]的元素都是零。

1.3  代码实现  

代码演示:

class Solution { public: void moveZeroes(vector<int>& nums) { for(int dest = -1,cur = 0;cur < nums.size();cur++) { if(nums[cur]) swap(nums[++dest],nums[cur]); } } };
时间复杂度:O(N),空间复杂度:O(1)。

1.4  过程推算

本题整个的思路、算法原理、解题过程博主在纸上推导了一遍,大家可以参考一下!


002  复写零

力扣链接:1089. 复写零

力扣题解链接:双指针算法解决【复写零】问题

题目描述:

2.1  思路

双指针算法——

先根据“异地”操作,然后优化成双指针下的“就地”操作。

1、先找到最后一个“复写”的数: 双指针算法——

(1)先判断cur位置的值;

(2)决定dest向后走一步还是两步;

(3)判断一下dest是否已经到结束位置;

(4)cur++。

2、处理一下边界情况——

到达n-1位置,cur--,dest -= 2,复写两次0。

3、“从后往前”完成复写操作。

也就是说——

如果“从前向后”进行原地复写操作的话,由于0的出现会复写两次,导致没有复写的数会被覆盖掉。因此我们选择“从后往前”的复写策略。

但是我们选择“从后往前”的复写的时候,需要找到“最后一个复写的数”,因此我们的大体流程分两步:(1)先找到最后一个复写的数;(2)然后从后往前进行复写操作。

2.2  算法流程

2.2.1

初始化两个指针cur = 0,dest = 0;

2.2.2

找到最后一个复写的数:

1、当cur < n的时候,一直执行下面循环:

(1)判断cur位置的元素:

1)如果是0的话,dest就往后移动两位;

2)否则,dest往后移动一位。

2.2.3

判断dest是否越界到n的位置:

1、如果越界,执行以下三步:

(1)n - 1位置的值修改成0;

(2)cur向前移动一步;

(3)dest向前移动两步。

2.2.4

从cur位置开始往前遍历原数组,依次还原出复写后的结果数组:

1、判断cur位置的值:

(1)如果是0:dest以及dest - 1位置修改成0,dest -= 2;

(2)如果非零:dest位置修改成0,dest -= 1;

2、cur--,复写下一个位置。

2.3  代码实现  

代码演示:

class Solution { public: void duplicateZeros(vector<int>& arr) { //1、先找到最后一个数 int cur = 0,dest = -1,n = arr.size(); while(cur < n) { if(arr[cur]) { dest++; } else { dest += 2; } if(dest >= n - 1) break; cur++; } //2、处理边界问题 if(dest == n) { arr[n -1] = 0; cur--; dest -= 2; } //3、从后往前完成复写操作 while(cur >= 0) { if(arr[cur]) arr[dest--] = arr[cur--]; else { arr[dest--] = 0; arr[dest--] = 0; cur--; } } } };
时间复杂度:O(N),空间复杂度:O(1)。

2.4  过程推算

本题整个的思路、算法原理、解题过程博主在纸上推导了一遍,大家可以参考一下!


结尾

结语:本文内容到这里就结束了,大家不要忘记给博主“一键四连”哦!

Read more

Spring Boot RESTful API 开发与测试

Spring Boot RESTful API 开发与测试

Spring Boot RESTful API 开发与测试 20.1 学习目标与重点提示 学习目标:掌握Spring Boot RESTful API开发与测试的核心概念与使用方法,包括RESTful API的定义与特点、Spring Boot RESTful API的开发、Spring Boot RESTful API的测试、Spring Boot RESTful API的认证与授权、Spring Boot RESTful API的实际应用场景,学会在实际开发中处理RESTful API问题。 重点:RESTful API的定义与特点(资源、表现层、状态转移)、Spring Boot RESTful API的开发(@RestController、@RequestMapping、@GetMapping、@PostMapping、@PutMapping、@DeleteMapping)、Spring

By Ne0inhk
Flutter 三方库 flad_cli 的鸿蒙化适配指南 - 实现 Dart 工程的自适应模板扫描与脚手架自动化、支持端侧资源一键生成与代码架构规约校验实战

Flutter 三方库 flad_cli 的鸿蒙化适配指南 - 实现 Dart 工程的自适应模板扫描与脚手架自动化、支持端侧资源一键生成与代码架构规约校验实战

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 flad_cli 的鸿蒙化适配指南 - 实现 Dart 工程的自适应模板扫描与脚手架自动化、支持端侧资源一键生成与代码架构规约校验实战 前言 在进行 Flutter for OpenHarmony 的企业级项目矩阵开发时,如何保证上百个模块的目录结构、基础依赖、甚至是 import 规约保持高度一致?手动复制粘贴模板显然不可持续。flad_cli 是一个专为 Dart 项目设计的极简脚手架(Scaffold)命令行工具。它能根据预设规则自动生成或扫描工程文件。本文将探讨如何在鸿蒙端利用此工具构建极致的工业化开发流水线。 一、原直观解析 / 概念介绍 1.1 基础原理 flad_cli 建立在“代码生成(Code Gen)”与“扫描(

By Ne0inhk
Rust异步测试与调试的实践指南

Rust异步测试与调试的实践指南

Rust异步测试与调试的实践指南 一、异步测试的基础 1.1 异步测试的概念 💡异步测试是对异步代码的功能和性能进行验证的过程,确保异步操作能够正确、高效地执行。与同步测试相比,异步测试需要处理任务调度、I/O操作和资源管理等复杂问题。 在Rust中,异步测试通常使用tokio::test宏或async-std::test宏来标记测试函数,这些宏会自动创建异步运行时环境。 1.2 常用的异步测试框架 * Tokio测试框架:适用于使用Tokio异步运行时的项目,提供tokio::test宏和tokio::spawn函数。 * Async-std测试框架:适用于使用async-std异步运行时的项目,提供async-std::test宏和async-std::task::spawn函数。 * Proptest:用于属性测试,支持异步属性测试。 * Mockall:用于模拟依赖对象,支持异步模拟。 1.3 简单异步函数的测试 下面是一个简单的异步函数测试示例: // src/lib.rsusetokio::time::sleep;usestd::time::D

By Ne0inhk

GLM-4.6V-Flash-WEB + API = 轻松构建多模态服务

GLM-4.6V-Flash-WEB + API = 轻松构建多模态服务 你有没有遇到过这样的场景: 客户发来一张模糊的发票截图,问“这笔报销能过吗?”; 运营同事甩来十张商品详情页,催你“快生成适配小红书的文案”; 教育产品需要实时解析学生手写作业照片,并判断解题逻辑是否正确…… 这些需求背后,都指向同一个技术能力——看懂图、听懂话、答得准、回得快。但现实是,很多视觉语言模型要么跑不动,要么等不及,要么看不懂中文语境下的真实图像。直到 GLM-4.6V-Flash-WEB 出现。 它不是又一个参数堆出来的“论文模型”,而是一款从第一天起就为 Web 服务而生的轻量级多模态引擎:单卡可跑、毫秒响应、中文原生、开箱即用。更重要的是,它同时提供网页交互界面和标准 API 接口——这意味着,你既可以点点鼠标快速验证效果,也能在五分钟内把它集成进自己的后端系统。 本文不讲论文、不比榜单,只聚焦一件事:怎么用最简单的方式,把 GLM-4.6V-Flash-WEB

By Ne0inhk