C++刷题笔记(2)——leetcode27、26、283

2024-02-02 19:32
文章标签 c++ 笔记 刷题 26 283 leetcode27

本文主要是介绍C++刷题笔记(2)——leetcode27、26、283,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

双指针法

双指针法利用两个指针对数组进行扫描,利用问题本身所给的序列特性(升序或降序),通常是相反方向的或者相同方向不同速度(快慢指针)

并非是一种算法,更像是一种变成技巧;

快慢指针中,在慢指针循环内定义快指针,快指针在慢指针之前,对数组后续元素依次扫描,在扫描到指定元素或者数组结尾的时候快指针返回,慢指针后移,并且根据题目要求移动或替换元素。

题目1:27.移除元素在这里插入图片描述

数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖

暴力解法

两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组
在这里插入图片描述
暴力算法的解题思路很简单,就是遍历数组找到目标元素,然后依次移动目标元素后面的元素将其覆盖

class Solution {
public:int removeElement(vector<int>& nums, int val) {int size = nums.size();for (int i = 0; i < nums.size(); i++) {            //遍历数组if (nums[i] == val) {                          //发现需要移除的元素for (int j = i + 1; j < size; j++) {       //就将数组集体向前移动一位nums[j - 1] = nums[j];             }i--;                                       //因为下标i以后的数值都向前移动了一位,所以i也向前移动一位size--;                                    //此时数组的大小-1}}return size;}
};

双指针法

在这里插入图片描述
当碰到target数值,慢指针停止移动,快指针保持移动,并把快指针指向的数组元素移动到慢指针
单向双指针方法:
没有改变数组中元素的相对位置

//单向双指针
class Solution {
public:int removeElement(vector<int>& nums, int val) {int i = 0;                                         //i为慢指针for (int j = 0; j < nums.size() - 1; j++) {        //j为快指针,这里不能写j < nums.size() - 1,防止数组长度为1和0if (val != nums[j]) {nums[i++] = nums[j];                      //nums中的j元素如果不等于val,则慢指针后移一位,快指针后移一位}}                                                //若j等于val,则再次进入循环体,快指针后移,慢指针不动return i;}
};

单向双指针方法解题思路:
在这里插入图片描述
首先就是快指针、慢指针的索引初始为0,根据循环条件j < nums.size()进入循环,寻找数组中等于目标值的元素,这里要注意后置递增是先计算表达式、再对变量进行加1
在这里插入图片描述
直到i=2、j=2,此时j的值仍满足循环条件,但不满足if语句,因此不会执行if语句,直接执行j++,j=3
在这里插入图片描述
再次进行循环,j=3,满足循环条件且满足if语句,此时j=3、i=2,执行if语句会将进行赋值操作nums[2] = nums[3]; 完成移除元素操作
在这里插入图片描述
之后会依次将快指针的值赋给慢指针
在这里插入图片描述
当i=3、j=4时依然满足循环条件和if语句条件,继续进行一个循环后i=4、j=5,不再满足循环条件,返回i,返回移除后数组的新长度。
在这里插入图片描述

双向指针方法:
基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素

class Solution {
public:int removeElement(vector<int>& nums, int val) {int i = 0;                                      //左指针int j = nums.size() - 1;                        //右指针while (i <= j) {                                while (i <= j && nums[i] != val) {          //找左边等于val的元素,如果这里不加i <= j的限制,就可能i一直右移到j右边,造成数组长度不准确++i; }while (i <= j && nums[j] == val) {          //找右边不等于val的元素,这里i<=j同上--j;}if (i < j) {                                //将右边不等于val的元素覆盖左边等于val的元素,这里i<j没有等于,如果可以等于,那么执行i++、j--后同样i可能移动到j右边nums[i++] = nums[j--];}}return i;                                       //i一定指向了最终数组末尾的下一个元素}
};

双向指针方法解题思路:
在这里插入图片描述
这种解法的思路左指针从数组的左边开始遍历数组,寻找等于目标值的元素右指针从右开始遍历数组,寻找不等于目标值的元素
在这里插入图片描述
于是就有了等于目标值的元素的索引和正常的元素,用正常元素覆盖等于目标值的元素完成移除元素操作
在这里插入图片描述
之后左指针继续遍历数组,当左指针i=4时仍满足while (i <= j)while (i <= j && nums[i] != val)的循环条件,因此还会继续进行累加,累加后i=5,不再满足循环条件,返回i,返回移除后数组的新长度。
在这里插入图片描述

题目2:26.删除排序数组中的重复项

在这里插入图片描述
单向双指针方法:

class Solution {
public:int removeDuplicates(vector<int>& nums) {int i = 0;                                //i慢for (int j = 1; j < nums.size(); j++) {   //j快if (nums[i] != nums[j]) {i++;                              //移到下一位,将不同的数放入nums[i] = nums[j];}}return i + 1;                            //删除后数组的新长度}
};

单向双指针方法解题思路:
在这里插入图片描述
解题思路大概和27题差不多,当i=2、j=3时,将会跳过if语句,执行j++,此时i=2、j=4
在这里插入图片描述
继续执行代码i++;nums[i] = nums[j];(i=3,nums[3] = nums[4]),删除数组中的重复项,j++,此时i=3、j=5,不再满足循环条件,返回数组成都
在这里插入图片描述
然后进行j++,此时i=3、j=5,不再满足循环条件,返回数组长度。

题目3:283.移动零

在这里插入图片描述
这一题和27题非常的类似了
单向双指针方法:

class Solution {
public:void moveZeroes(vector<int>& nums) {int slowIndex = 0;for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {if (nums[fastIndex] != 0) {nums[slowIndex++] = nums[fastIndex];}}// 将slowIndex之后的冗余元素赋值为0for (int i = slowIndex; i < nums.size(); i++) {nums[i] = 0;}}
};

单向双指针方法解题思路:
主要解题思路就是用双指针遍历数组,当遇到0元素时,slowIndex不动,fastIndex+1,然后将快指针赋值给慢指针。

相当于对整个数组移除元素0,然后slowIndex之后都是移除元素0的冗余元素,把这些元素都赋值为0就可以了。

这篇关于C++刷题笔记(2)——leetcode27、26、283的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/671727

相关文章

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

C++归并排序代码实现示例代码

《C++归并排序代码实现示例代码》归并排序将待排序数组分成两个子数组,分别对这两个子数组进行排序,然后将排序好的子数组合并,得到排序后的数组,:本文主要介绍C++归并排序代码实现的相关资料,需要的... 目录1 算法核心思想2 代码实现3 算法时间复杂度1 算法核心思想归并排序是一种高效的排序方式,需要用

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

C++中detach的作用、使用场景及注意事项

《C++中detach的作用、使用场景及注意事项》关于C++中的detach,它主要涉及多线程编程中的线程管理,理解detach的作用、使用场景以及注意事项,对于写出高效、安全的多线程程序至关重要,下... 目录一、什么是join()?它的作用是什么?类比一下:二、join()的作用总结三、join()怎么

C++中全局变量和局部变量的区别

《C++中全局变量和局部变量的区别》本文主要介绍了C++中全局变量和局部变量的区别,全局变量和局部变量在作用域和生命周期上有显著的区别,下面就来介绍一下,感兴趣的可以了解一下... 目录一、全局变量定义生命周期存储位置代码示例输出二、局部变量定义生命周期存储位置代码示例输出三、全局变量和局部变量的区别作用域