力扣热题100——普通数组(不普通)

news2025/4/19 16:01:35

普通数组但一点不普通!

  • 最大子数组和
  • 合并区间
  • 轮转数组
  • 除自身以外数组的乘积
  • 缺失的第一个正数

最大子数组和

在这里插入图片描述
在这里插入图片描述

这道题是非常经典的适用动态规划解决题目,但同时这里给出两种解法
动态规划分治法
那么动态规划方法大家可以在我的另外一篇博客总结中看到,因此直接给出代码,着重讲第二道题

动态规划:

//使用动态规划方法
class Solution {
public:
    int ans = INT_MIN;
    //动态规划方法:令A[i]表示以i结尾的连续子数组的和
    int maxSubArray(vector<int>& nums) {
        int n = nums.size();
        int A[n];
        
        for(int i = 0;i<n;i++){
            if(!i){
                A[0] = nums[0];
                ans = nums[0];
                continue;
            }
            A[i] = max(A[i-1]+nums[i],nums[i]);
            ans = max(A[i],ans);
        }
        return ans;
    }
};

使用分治法
分治法就可以片面的理解为递归 若只是应对公司的笔试 不必分的那么清 咱又不写教科书:
分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。
1.我们来定义get(a,l,r)表示查询a序列 [l,r] 区间内的最大子段和,那么最终的答案就是get(nums,0,num.size()-1)。则实现分治法应该将区间进行划分:
对于一个区间[l,r],取m = [(l+r)/2],对区间[l,m]和[m+1,r]分治分解。当递归逐层深入直到区间长度缩小为1的时候,递归开始回升。
2. 对于一个区间[l,r] 我们可以维护四个量:
lSum表示[l,r]内以l为左端点的最大子段和;
rSum表示[l,r]内以r为右端点的最大子段和
msum表示[l,r]内的最大子段和
iSum表示[l,r]的区间和
以下简称[l,m]为[l,r]的左子区间,[m+1,r]为[l,r]的右子区间。且对于长度为1的区间[i,j],四个量的值都和nums[i]相等。

对于长度为1的区间:

  • 首先最好维护的是isum,区间[l,r]的iSum就等于[左子区间]的iSum加上[右子区间]的iSum。
  • 对于[l,r]的lSum,存在两种可能,要么等于左子区间的lSum,要么等于左子区间的iSum加上右子区间的lSum,二者取大。
  • 对于[l,r]的rSum,同理,要么等于右子区间的rSum,要么等于右子区间的iSum加上左子区间的rSum,二者取大。
  • 当计算好上面的三个量之后,就很好计算[l,r]的mSum了。可以考虑[l,r]的mSum对应的区间是否跨越m——它可能不跨越m,,也就是[l,r]的mSum可能是左子区间的mSum和右子区间的mSum中的一个;它也可能跨越m,可能是左子区间的rSum和右子区间的lSum求和。三者取大。
    下面给出代码:
class Solution{
public:
	struct Status{
		int lSum,rSum,mSum,iSum;
	};
	Status pushUp(Status l,Status r){
		int iSum = l.iSum + r.iSum;
		int lSum = max(l.lSum,l.iSum + r.lSum);
		int rSum = max(r.rSum,r.iSum+l.rSum);
		int mSum = max(max(l.mSum,r.mSum),l.rSum+r.lSum);
		return (Status) {lSum,rSum,mSum,iSum};
	};
	
	Status get(vector<int> &a,int l,int r){
		if(l==r){
			return (Status) {a[l],a[l],a[l],a[l]};
		}
		int m = (l+r)/2;
		Status lSub = get(a,l,m);
		Status rSub = get(a,m+1,r);
		return pushUp(lSub,rSub);
	}
	int maxSubArray(vector<int>& nums){
		return get(nums,0,nums.size()-1).mSum;
	}
};

合并区间

在这里插入图片描述
在这里插入图片描述

这道题的解题思路就是先将intervals内的区间按照左端点进行排序,再定义一个新的vector<vector<int>>数组merged,且如果下一个遍历到的区间的左端点如果比 比merged最后一个区间的右端点还要大,则两个区间就没有交集了,否则就将merged最后一个区间的右端点设置为merged最后一个区间的右端点与intervals中的当前区间中右端点这两者之间的最大值,以此循环即可。最后得到的merged数组便是最终的结果 。

下面给出代码:

class Solution{
public:
	vector<vector<int>> merge(vector<vector<int>>& intervals){
		if(intervals.size()==0) return {};
		//这里默认排序是左端点递增 左端点相同的话则按照右端点递增的顺序进行排序
		sort(intervals.begin(),intervals.end());
		vector<vector<int>> merged;
		for(int i=0;i<intervals.size();i++){
			int L = intervals[i][0], R = intervals[i][1];
			if(!merged.size()||merged.back()[1]<L){
				merged.push_back({L,R});
			}else{
				merged.back()[1] = max(merged.back()[1],R);
			}
		}
		return merged;
	}
}

轮转数组

在这里插入图片描述
在这里插入图片描述

这里给出使用额外数组和翻转数组的两种方法


1.使用额外数组与原数组元素的位置对应关系为:原数组下标为i的元素放至新数组下标为(i+k)%n的位置
下面给出代码:

class Solution{
public:
	void rotate(vector<int>& nums,int k){
		int n=nums.size();
		vector<int> newArr(n);//定义动态数组
		for(int i=0;i<n;i++){
			newArr[(i+k)%n] = nums[i];
		}
		nums.assign(newArr.begin(),newArr.end());
		//assign是STL的成员函数,用于替换容器中的元素,指定容器中的元素为新内容
	}
}

2.翻转数组:将原数组的末尾元素放至在数组的头部等价于是将整个数组进行翻转,然后将前[0,k-1]个元素翻转,再将[k,n-1]的元素进行翻转,示例如下:
在这里插入图片描述
下面给出代码:

class Solution{
public:
 void reverse(vector<int>& nums,int start,int end){
 	swap(nums[start],nums[end]);
 	start++;
 	end--;
 }
 void rotate(vector<int>& nums,int k){
 	k %= nums.size();
 	reverse(nums,0,nums.size()-1);
 	reverse(nums,0,(k-1));
 	reverse(nums,k,nums.size()-1);
 }
}

除自身以外数组的乘积

在这里插入图片描述
在这里插入图片描述

这道题按照你以为的常规的方法做会超时,笔者已经试过了类似下面这样吧

        // int n = nums.size();
        // vector<int> answer(n);
        // for(int i=0;i<n;i++){
        //     int res=1;
        //     for(int j=0;j<n;j++){
        //         if(i!=j){
        //             res *=nums[j];
        //         }
        //     }
        //     answer[i] = res;
        // }
        // return answer;

这道题跟PAT算法题的"几个PTA"这道例题很像,这里应该采用活用递推的方法求解,即根据当前位置的数值应该是左边的乘积乘以右边数的乘积,对左右两边乘积可以用两个数组存放
于是有了下面的做法

class Solution{
public:
	vector<int> productExcepSelf(vector<int>& nums){
		int n = nums.size();
		vector<int> answer(n);
		vector<int> L(n,0),R(n,0); //L,R代表左右两侧的乘积列表
		L[0] = 1;//索引为‘0’的元素,因为左侧没有元素 因此L[0] = 1;
		for(int i = 1;i<n;i++){
			L[i] = nums[i-1]*L[i-1];
		}
		R[n-1]=1;//最后一个元素的右侧没有元素 
		for(int i=n-2;i>=0;i--){
			R[i] = nums[i+1]*R[i+1];
		}
		//以上便定义好了两个列表
		//对于索引i,除nums[i]之外其余各元素的乘积就是左侧所有元素的乘积乘以右侧所有元素的乘积
		for(int i=0;i<n;i++){
			answer[i] = L[i]*R[i];
		}
		return answer;
	}
}

此处为了降低空间的复杂度 先试用answer数组作为左侧乘积的列表,answer[i]代表的是i左侧乘积的列表。 不构造R数组,用一个遍历跟踪右侧乘积并更新数组answer[i] = answer[i] * R,然后更新R = R*nums[i],其中变量R表示的就是索引右侧数字的乘积。

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int length = nums.size();
        vector<int> answer(length);

        // answer[i] 表示索引 i 左侧所有元素的乘积
        // 因为索引为 '0' 的元素左侧没有元素, 所以 answer[0] = 1
        answer[0] = 1;
        for (int i = 1; i < length; i++) {
            answer[i] = nums[i - 1] * answer[i - 1];
        }

        // R 为右侧所有元素的乘积
        // 刚开始右边没有元素,所以 R = 1
        int R = 1;
        for (int i = length - 1; i >= 0; i--) {
            // 对于索引 i,左边的乘积为 answer[i],右边的乘积为 R
            answer[i] = answer[i] * R;
            // R 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 R 上
            R *= nums[i];
        }
        return answer;
    }
};

缺失的第一个正数

在这里插入图片描述
在这里插入图片描述

这道题直接秒了:
先看我的做法:

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int j=1;
        for(int i =0;i<nums.size();i++){
            if(j==nums[i]) j++;
            if(j<nums[i]) return j;
        }
        return j;

    }
};

下面还是给一个更加规范的做法:
对于一个长度为 N 的数组,其中没有出现的最小正整数只能在 [1,N+1] 中。这是因为如果 [1,N] 都出现了,那么答案是 N+1,否则答案是 [1,N] 中没有出现的最小正整数。这样一来,我们将所有在 [1,N] 范围内的数放入哈希表,也可以得到最终的答案。而给定的数组恰好长度为 N,这让我们有了一种将数组设计成哈希表的思路:
对数组进行遍历,对于遍历到的数x,如果它在[1,N]的范围内,那么就将数组中的第x-1个位置打上[标记](数组下标从0开始)。在遍历结束之后,如果所有的位置都被打上了标记,那么答案是N+1,否则答案是最小的没有打上标记的位置+1。
但问题是应该如何标记 考虑到不在1-N内的话 就是N+1;则考虑将所有非整数都变为N+1;然后遍历数组中的每一个数x,他可能已经被打了标记,因此原本对应的数为|x|,其中| |为绝对值符号。如果|x|在[1,N],那么我们给数组中的第|x|-1个位置的数添加一个负号。
在这里插入图片描述

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        for (int& num: nums) {
            if (num <= 0) {
                num = n + 1;
            }
        }
        for (int i = 0; i < n; ++i) {
            int num = abs(nums[i]);
            if (num <= n) {
                nums[num - 1] = -abs(nums[num - 1]);
            }
        }
        for (int i = 0; i < n; ++i) {
            if (nums[i] > 0) {
                return i + 1;
            }
        }
        return n + 1;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2337235.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习与机器学习的关系解析:从基础到应用

&#x1f4cc; 友情提示&#xff1a; 本文内容由银河易创AI&#xff08;https://ai.eaigx.com&#xff09;创作平台的gpt-4-turbo模型生成&#xff0c;旨在提供技术参考与灵感启发。文中观点或代码示例需结合实际情况验证&#xff0c;建议读者通过官方文档或实践进一步确认其准…

工业物联网的可视化编程革新:Node-RED与边缘计算的深度融合-纵横智控

在工业物联网的演进历程中&#xff0c;可视化编程工具正成为打破技术壁垒的核心力量。Node-RED作为开源的可视化编程平台&#xff0c;通过其独特的拖拽式逻辑构建能力&#xff0c;为设备连接、数据处理与业务逻辑设计提供了全新范式。本文将深入解析Node-RED的技术优势&#xf…

深度学习 从入门到精通 day_02

1. 自动微分 自动微分模块torch.autograd负责自动计算张量操作的梯度&#xff0c;具有自动求导功能。自动微分模块是构成神经网络训练的必要模块&#xff0c;可以实现网络权重参数的更新&#xff0c;使得反向传播算法的实现变得简单而高效。 1.1 基础概念 1. 张量 &#xff1a…

Linux通用一键换源脚本.sh - ubuntu、centos全自动更换国内源 - LinuxMirrors神器

效果 脚本 bash <(curl -sSL https://linuxmirrors.cn/main.sh) 来自 https://linuxmirrors.cn/ 截图 ending...

【Python学习笔记】Pandas实现Excel质检记录表初审、复核及质检统计

背景&#xff1a; 我有这样一个需要审核的飞书题目表&#xff0c;按日期分成多个sheet&#xff0c;有初审——复核——质检三个环节&#xff0c;这三个环节是不同的同学在作业&#xff0c;并且领到同一个题目的人选是随机的&#xff0c;也就是说&#xff0c;完成一道题的三个人…

Gparted重新分配swap空间之后,linux电脑读不到swap空间

问题背景 lsblk 显示存在物理设备&#xff08;如 /dev/nvme0n1&#xff09;&#xff0c;但 swapon --show 无输出 说明 系统未启用任何 Swap 设备 问题原因分析 /etc/fstab 中 Swap 的 UUID 配置错误 从图片中看到执行 sudo swapon -a 时报错&#xff1a; swapoff: cannot fin…

第一节:Vben Admin 最新 v5.0初体验

系列文章目录 基础篇 第一节&#xff1a;Vben Admin介绍和初次运行 第二节&#xff1a;Vben Admin 登录逻辑梳理和对接后端准备 第三节&#xff1a;Vben Admin登录对接后端login接口 第四节&#xff1a;Vben Admin登录对接后端getUserInfo接口 第五节&#xff1a;Vben Admin权…

ARCGIS国土超级工具集1.5更新说明

ARCGIS国土超级工具集V1.5版本更新说明&#xff1a;因作者近段时间工作比较忙及正在编写ARCGISPro国土超级工具集&#xff08;截图附后&#xff09;的原因&#xff0c;故本次更新为小更新&#xff08;没有增加新功能&#xff0c;只更新了已有的工具&#xff09;。本次更新主要修…

CNN:卷积到底做了什么?

卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09; 是一种深度学习模型&#xff0c;专门用于处理具有网格结构的数据&#xff08;如图像、视频等&#xff09;。它在计算机视觉领域表现卓越&#xff0c;广泛应用于图像分类、目标检测、图像分割等任务。CN…

AI应用开发之扣子第二课-AI翻译(第1节/共2节)

简介 共分为两节介绍&#xff0c;内容简单易懂&#xff0c;步骤详细&#xff0c;可以避免很多坑&#xff0c;建议直接上手操作&#xff08;预估30分钟&#xff09;。 AI应用开发之扣子第二课学习-AI翻译&#xff08;第1节/共2节&#xff09;&#xff1a;业务逻辑实现 AI应用…

linux学习 3.用户的操作

用户 建议在系统操作的时候不要一直使用root用户&#xff0c;因为root用户具有最高权限&#xff0c;你可能因为某些操作影响了你的系统&#xff0c;采用子用户则可以避免这一点 这里的学习不用太深入&#xff0c;掌握如何创建删除切换即可(除非你要做详细的用户管理&#xff0…

Leetcode刷题 由浅入深之哈希表——242. 有效的字母异位词

目录 &#xff08;一&#xff09;字母异位词的C实现 写法一&#xff08;辅助数组&#xff09; &#xff08;二&#xff09;复杂度分析 时间复杂度 空间复杂度 &#xff08;三&#xff09;总结 【题目链接】242.有效的字母异位词 - 力扣&#xff08;LeetCode&#xff09; …

自动化构建工具:makemakefile

在Windows中&#xff0c;我们写C代码或者C代码都需要用先找到一款合适的编译器&#xff0c;用来方便我们更好的完成代码&#xff0c;比如说vs2019&#xff0c;这些工具的特点是集成了多种开发所需的功能&#xff0c;如代码编辑、编译、调试、版本控制等&#xff0c;无需在不同的…

刷题 | 牛客 - js中等10题(更ing)1/54知识点解答

知识点汇总&#xff1a; Array.from(要转换的对象, [mapFn], [thisArg ])&#xff1a;将类数组对象&#xff08;Array-like&#xff09;/可迭代对象&#xff08;Iterable&#xff09;转为真正的数组。 第二参 mapFn 是 类似 Array.prototype.map 的回调函数&#xff0c;加工…

Ubuntu 20.04.6编译安装COMFAST CF-AX90无线网卡驱动

目录 0 前言 1 CF-AX90无线网卡驱动 1.1 驱动下载 1.2 驱动准备 2 编译安装驱动 2.1 拷贝驱动依赖到系统 2.2 驱动安装编译 3 重启 0 前言 COMFAST CF-AX90或者说AIC8800D80的Linux版本驱动不支持高版本的linux内核&#xff0c;实测目前仅支持最高5.15的内核。Ubuntu2…

PPT无法编辑怎么办?原因及解决方法全解析

在日常办公中&#xff0c;我们经常会遇到需要编辑PPT的情况。然而&#xff0c;有时我们会发现PPT文件无法编辑&#xff0c;这可能由多种原因引起。今天我们来看看PPT无法编辑的几种常见原因&#xff0c;并提供实用的解决方法&#xff0c;帮助你轻松应对。 原因1&#xff1a;文…

安全用电基础知识及隐患排查重点

安全用电是电气安全的一个重要方面&#xff0c;作为普通人员&#xff0c;必须学会基础的用电知识和技巧&#xff0c;才能保障自己和家庭的安全。 以下是安全用电的基础知识及隐患排查重点&#xff1a; 一、基础知识 1.电压&#xff1a;单位为伏特&#xff08;V&#xff09;&a…

Laravel 使用通义灵码 - AI 辅助开发提升效率

一、引言 Laravel 是 PHP 常用的一种后端开发框架&#xff0c;遵循 MVC&#xff08;模型 - 视图 - 控制器&#xff09;架构&#xff0c;以简洁、优雅的语法和强大的功能著称&#xff0c;旨在提升开发效率并简化复杂任务的实现。然而&#xff0c;它的开发习惯可能与传统的 PHP …

签到功能---实现签到接口

文章目录 概要整体架构流程技术细节小结 概要 需求分析以及接口设计 由KEY的结构可知&#xff0c;要签到&#xff0c;就必须知道是谁在哪一天签到&#xff0c;也就是两个信息&#xff1a; 当前用户 当前时间 这两个信息我们都可以自己获取&#xff0c;因此签到时&#xff…

LWIP_MQTT连接ONENET

前言&#xff1a; 使用正点原子STM32F407, LWIP,MQTT demo,验证LwIP的MQTT连接ONENET物联网平台,测试整个链路是否畅通&#xff0c;后面再详细分析LWIP移植和MQTT协议的使用。 26 基于 MQTT 协议连接 OneNET 服务器 本章主要介绍 lwIP 如何通过 MQTT 协议将设备连接到 OneNET…