力扣 无重复字符的最长字串-3

news/2024/11/22 7:36:43/

无重复字符的最长字串-3

class Solution {
public:// 解决方法:双指针int lengthOfLongestSubstring(string s) { // 如果字符串为空,直接返回0if (s.length() == 0)return 0;// 如果字符串不为空,字符串每个字符都不同的情况下,最长字串的长度为1,所以Max初始化为1int left = 0, right = 0, Max = 1;//字符变量t用来存放每次两个指针范围内的后一个字符,用于与两个指针范围内的所有元素判断是否相同char t = 0;while (left < s.length()) {while (right < s.length() - 1) {//flag初始化为1用于标记,方便后续判断int flag = 1;//t赋值为两个指针范围内的后一个字符t = s[right + 1];//循环判断t是否与两个指针内有相同的字符for (int f = left; f <= right; f++) {//如果有相同字符flag标记为0,并break结束循环if (s[f] == t) {flag = 0;break;}}/*如果flag为零,说明双指针范围的后一个字符与双指针范围内有相同字符,后续的字符也没有必要判断了,break结束循环因为此情况下无论范围再怎么扩大(right++),双指针范围内总是有这个的重复字符,不符合题意。*/if (flag == 0)break;/*如果flag为1,说明双指针范围的后一个字符与双指针范围内没有相同字符,则把双指针范围的后一个字符括入到双指针范围内(right++)并与Max比较找到最大字串*/if (flag) {right++;Max = max(Max, right - left + 1);}}//内层while循环结束说明,字符串从头到尾已经遍历完,或者找到了相同字符break结束循环了//那么继续缩小左指针的范围(left),继续从左值针的位置开始查找最长字串,一直找到结尾left++;right = left;}return Max;}
};

每日问题

什么是 C++ 中的移动语义?它的作用是什么?

C++中的移动语义

        移动语义是C++11中引入的一种特性,通过引入右值引用(T&&),支持资源的高效转移,而无需昂贵的拷贝操作。移动语义的核心作用是通过移动而不是复制的方式管理资源,从而提升程序性能,特别是在处理动态分配的资源(如内存、文件句柄等)时。、

移动语义的关键概念

1.右值引用(T&&):

        是一个能够绑定到右值(临时对象)的引用类型。

        它允许开发者直接访问右值对象的资源,并安全地将资源转移到其他对象中。

2.移动构造函数和移动赋值运算符:

        是实现移动语义的两大工具。

        它们负责接收一个右值引用参数,从而将资源从一个对象移动到另一个对象。

作用

1.提高性能:

        在传递或返回大型对象时,通过移动语义可以避免昂贵的拷贝操作,直接转移资源的所有权。

        常用于容器类(如std:vector)在插入、删除或交换元素时。

2.避免资源浪费:

        临时对象通常会在作用域结束时被销毁,移动语义使得这些资源可以被重复利用,而不是浪费掉。

3.支持现代化C++编程:

        与标准库(如std:move)结合,为开发者提供了更多灵活性和效率。

移动语义的实现

移动构造函数
class MyClass {
private:int* data;public:// 构造函数MyClass(int value) : data(new int(value)) {}// 移动构造函数MyClass(MyClass&& other) noexcept : data(other.data) {other.data = nullptr; // 资源转移,确保原对象不再持有资源}// 析构函数~MyClass() {delete data; // 释放资源}
};
  • 这是一个移动构造函数,接受一个右值引用 other(右值或临时对象)。
  • 实现了资源转移:
    • 将 other.data 的值转移给当前对象的 data。
    • 将 other.data 置为 nullptr,避免原对象在销毁时重复释放资源。
  • noexcept 表示此操作不会抛出异常,确保移动操作在某些场景(如标准容器的优化)中安全进行。
移动赋值运算符
class MyClass {
private:int* data;public:// 构造函数MyClass(int value) : data(new int(value)) {}// 移动赋值运算符MyClass& operator=(MyClass&& other) noexcept {if (this != &other) {         // 防止自我赋值delete data;              // 释放当前资源data = other.data;        // 转移资源other.data = nullptr;     // 确保原对象不再持有资源}return *this;}~MyClass() {delete data;}
};
配合标准库使用
1.std::move

        用于将一个左值显示转换为右值,从而启用移动语义。

        常见用法时将一个临时对象的资源转移到另一个对象中。

示例:

std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = std::move(v1); // v1 的资源转移到 v2,避免拷贝
2.std::forward

        通常用于完美转发函数模板参数,确保参数的值类别(左值或右值)正确传递。

使用场景

1.容器优化:

        C++标准库容器(如std::vector、std::string)在插入或删除元素时,利用移动语义大幅减少不必要的拷贝。

2.返回值优化:

        函数返回临时对象时,可以直接移动对象资源,避免临时对象的构造和销毁。

示例:

MyClass createObject() {MyClass obj(42);return obj; // 编译器自动应用移动语义
}

3.避免多余的动态分配:

        动态资源管理类(如文件句柄、数据库连接)可以通过移动语义避免资源的重复分配和释放。

移动语义是 C++11 的重要特性,专注于高效的资源管理和性能优化。它通过右值引用、移动构造函数和移动赋值运算符,避免了不必要的拷贝操作,特别适合处理动态资源密集型任务。在现代 C++ 编程中,移动语义和标准库(如 std::move)的结合已经成为编写高效代码的重要工具。

右值引用是什么?如何使用右值引用实现移动语义?

右值引用是什么?

        右值引用(T&&)是C++11引入的一种新类型引用,允许程序员直接操作右值(临时对象)。右值引用的主要目的是支持移动语义和完美转发。

右值与左值的区别

左值:表示一个内存中有确定存储地址的对象,可以被持久引用或操作。

        例如:变量名、数组元素。

        int a = 5;中的a是左值。

右值:表示临时对象或者表达式结果,通常无法直接获取地址。

        例如:字面值、临时对象、函数返回的非引用置。

        5、a + b的结果是右值。

        右值引用可以绑定到右值上,与普通左值引用(T&)不同。

右值引用的语法

int&& r = 10;  // r 是右值引用,绑定到字面值 10
int x = 20;
int&& r2 = x + 5;  // r2 是右值引用,绑定到临时值 25

右值引用允许我们直接获取右值的资源,并通过移动语义避免拷贝操作。

右值引用和移动语义

        移动语义的核定是将资源从一个对象“移动”到另一个对象,而不是“拷贝”它们。右值引用在实现移动语义时扮演了关键角色。

传统拷贝vs移动

1.传统拷贝:

        创建一个对象的完整副本,可能会涉及动态资源的重新分配。

        成本较高,特别是对动态内存的管理类(如vector)。

        例如:

std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = v1; // 复制 v1 的内容,可能导致多次内存分配
2.移动:

        通过右值引用,将一个对象的资源直接转移到另一个对象。

        避免了不必要的内存分配和数据复制,提高性能。

        示例:

std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = std::move(v1); // v1 的资源转移到 v2,v1 被置为“空”

如何使用右值引用实现移动语义

        为了实现移动语义,需要提供移动构造函数和移动赋值运算符。

1.移动构造函数

        移动构造函数接受一个右值引用作为参数,将资源从右值对象转移到当前对象。

        示例:

class MyClass {
private:int* data;public:// 构造函数MyClass(int value) : data(new int(value)) {}// 移动构造函数MyClass(MyClass&& other) noexcept : data(other.data) {other.data = nullptr; // 将原对象的资源置为空}// 析构函数~MyClass() {delete data; // 释放资源}
};
2.移动赋值运算符

        移动赋值运算符转移资源时需要释放当前对象已有的资源(避免内存泄漏),然后接管右值对象的资源。

        示例:

class MyClass {
private:int* data;public:// 构造函数MyClass(int value) : data(new int(value)) {}// 移动赋值运算符MyClass& operator=(MyClass&& other) noexcept {if (this != &other) {      // 避免自我赋值delete data;           // 释放当前对象的资源data = other.data;     // 转移资源other.data = nullptr;  // 将原对象的资源置为空}return *this;}// 析构函数~MyClass() {delete data;}
};

完整示例:

#include <iostream>
#include <utility> // for std::moveclass MyClass {
private:int* data;public:// 构造函数MyClass(int value) : data(new int(value)) {std::cout << "Constructing: " << *data << std::endl;}// 移动构造函数MyClass(MyClass&& other) noexcept : data(other.data) {other.data = nullptr;std::cout << "Moving: " << *data << std::endl;}// 移动赋值运算符MyClass& operator=(MyClass&& other) noexcept {if (this != &other) {delete data;data = other.data;other.data = nullptr;std::cout << "Assigning: " << *data << std::endl;}return *this;}// 析构函数~MyClass() {if (data) {std::cout << "Destructing: " << *data << std::endl;delete data;} else {std::cout << "Destructing: nullptr" << std::endl;}}
};int main() {MyClass obj1(10);              // 调用构造函数MyClass obj2 = std::move(obj1); // 调用移动构造函数MyClass obj3(20);obj3 = std::move(obj2);        // 调用移动赋值运算符return 0;
}

输出:

Constructing: 10
Moving: 10
Constructing: 20
Assigning: 10
Destructing: nullptr
Destructing: nullptr
Destructing: 10

右值引用允许我们绑定到右值(临时对象),直接操作其资源。

移动语义通过右值引用实现,主要通过 移动构造函数 和 移动赋值运算符,实现高效的资源转移。

使用右值引用和 std::move 可以显著提升程序性能,特别是当类中包含动态资源(如内存、文件句柄)时。


http://www.ppmy.cn/news/1548973.html

相关文章

鸿蒙NEXT开发案例:血型遗传计算

【引言】 血型遗传计算器是一个帮助用户根据父母的血型预测子女可能的血型的应用。通过选择父母的血型&#xff0c;应用程序能够快速计算出孩子可能拥有的血型以及不可能拥有的血型。这个过程不仅涉及到了简单的数据处理逻辑&#xff0c;还涉及到UI设计与交互体验的设计。 【…

引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例

引用类型的局部变量线程安全问题 背景注意事项分析步骤拆解&#xff08;文字描述时序图&#xff09; 背景 最近博主在看B站上的一个JUC并发编程视频中&#xff0c;碰到了一个比较有争议性的局部变量线程安全讨论问题。 先贴代码如下&#xff1a; Slf4j(topic "c.Threa…

数组作为函数参数--选择排序

#include<stdio.h> #define n 6 void s(int a[])//写a的话&#xff0c;是地址 { int i,j; for(i0;i<n-2;i) { for(ji1;j<n-1;j) { if(a[j]<a[i]) { int ta[i]; a[i]a[j];…

大模型时代的具身智能系列专题(十三)

迪士尼研究中心 瑞士苏黎世迪斯尼研究中心致力于不同领域的业务活动&#xff0c;其中包括电影、电视、公园和度假村以及消费产品。我们针对所有这些领域进行科研工作。我们开发能使我们将后道生产元素整合到前级生产中的技术。由此可节省许多昂贵的效果&#xff0c;这些效果最…

python爬虫初体验(五)—— 边学边玩小游戏

1. 打开浏览器 利用webbrowser 模块的 open()函数可以启动一个新浏览器&#xff0c;打开指定的 URL。 import webbrowser webbrowser.open(http://inventwithpython.com/) 2. 猜数字游戏 # -*- coding: utf-8 -*- # This is a guess the number game. import randomsecretN…

iOS 18.2 Beta 4开发者预览版发布,相机新增辅助功能

昨天刚连发iOS 18.1.1正式版、iOS 17.7.2正式版&#xff0c;今天凌晨&#xff0c;苹果就又发布iOS 18.2 Beta 4&#xff0c;据了解iOS18.2正式版将在 12 月初发布。那么这次的更新又有哪些变化呢&#xff1f;下面我们就来一起了解一下。 iOS 18.2 Beta 4的版本号为&#xff1a;…

【弱监督语义分割】Self-supervised Image-specific Prototype Exploration for WSSS 论文阅读

Self-supervised Image-specific Prototype Exploration for Weakly Supervised Semantic Segmentation 论文阅读 Abstract1. Introduction2. Related Work3. Approach3.1. Class Activation Mapping3.2. Image-specific Prototype Exploration3.3. Self-supervised Learning w…

FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我已有的PCIE方案10G/25G Ethernet Subsystem实现万兆以太网物理层方案本博客方案的PCIE2.0版本 3、PCIE基础知识扫描4、工程详细设计方案工程设计原理框图电脑端视频…