LC打怪录 数组array

 数组(Array)

definition: 一种线性表数据结构。它使用一组连续的内存空间,来存储一组具有相同类型的数据。

如上图所示,假设数据元素的个数为 nnn,则数组中的每一个数据元素都有自己的下标索引,下标索引从 000 开始,到 n−1n - 1n−1 结束。数组中的每一个「下标索引」,都有一个与之相对应的「数据元素」。

从上图还可以看出,数组在计算机中的表示,就是一片连续的存储单元。数组中的每一个数据元素都占有一定的存储单元,每个存储单元都有自己的内存地址,并且元素之间是紧密排列的。

  1. 线性表:线性表就是所有数据元素排成像一条线一样的结构,线性表上的数据元素都是相同类型,且每个数据元素最多只有前、后两个方向。数组就是一种线性表结构,此外,栈、队列、链表都是线性表结构。
  2. 连续的内存空间:线性表有两种存储结构:「顺序存储结构」和「链式存储结构」。其中,「顺序存储结构」是指占用的内存空间是连续的,相邻数据元素之间,物理内存上的存储位置也相邻。数组也是采用了顺序存储结构,并且存储的数据都是相同类型的。

原生 Python 中其实没有数组的概念,而是使用了类似 Java 中的 ArrayList 容器类数据结构,叫做列表。通常我们把列表来作为 Python 中的数组使用。Python 中列表存储的数据类型可以不一致,数组长度也可以不一致。例如:

arr = ['python', 'java', ['asp', 'php'], 'c']

数组的优点与局限性¶

数组存储在连续的内存空间内,且元素类型相同。这种做法包含丰富的先验信息,系统可以利用这些信息来优化数据结构的操作效率。

  • 空间效率高:数组为数据分配了连续的内存块,无须额外的结构开销。
  • 支持随机访问:数组允许在 �(1) 时间内访问任何元素。
  • 缓存局部性:当访问数组元素时,计算机不仅会加载它,还会缓存其周围的其他数据,从而借助高速缓存来提升后续操作的执行速度。

连续空间存储是一把双刃剑,其存在以下局限性。

  • 插入与删除效率低:当数组中元素较多时,插入与删除操作需要移动大量的元素。
  • 长度不可变:数组在初始化后长度就固定了,扩容数组需要将所有数据复制到新数组,开销很大。
  • 空间浪费:如果数组分配的大小超过实际所需,那么多余的空间就被浪费了

题目

438. 找到字符串中所有字母异位词

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例 1:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

 示例 2:

输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。

189. 轮转数组 rotate array

方法1: 创建新的数组

创建新的数组,使用额外的储存空间

python切片语法
列表切片语法:
  • 基本形式:list[start:stop:step]
    • start是切片开始的索引(包含该索引指向的元素),默认值为0。
    • stop是切片结束的索引(不包含该索引指向的元素),默认值为列表长度。
    • step是切片的步长,表示取元素的间隔,默认值为1。
使用[:]进行列表复制:
  • 当你省略startstop索引时(即[:]),切片操作会选取整个列表。
  • 这种方式实现的是列表的浅拷贝,意味着列表本身被复制了,但是列表中的元素并没有被复制。如果列表中的元素是不可变类型(如整数、字符串等),这通常不会引起问题。但如果列表中包含可变对象(如其他列表),则原始列表和复制的列表中的可变元素将指向相同的对象。
  • example: 
    original_list = [1, 2, 3, 4]
    copied_list = original_list[:]  # 创建 original_list 的一个浅拷贝# 修改 copied_list 不会影响 original_list
    copied_list.append(5)
    print(original_list)  # 输出: [1, 2, 3, 4]
    print(copied_list)    # 输出: [1, 2, 3, 4, 5]
    
1. 暴力法3种写法
insert and pop
class Solution(object):def rotate(self, nums, k):""":type nums: List[int]:type k: int:rtype: None Do not return anything, modify nums in-place instead."""res = nums[:] #创建列表副本:res = nums[:] 创建了nums的一个副本,名为res。这样做是为了在不改变原始列表的情况下,先在副本上进行修改。n=len(nums)for i in range(n):pos =(i+k)%nres[pos]=nums[i]for i in range(n):nums[i]=res[i]
  • 计算新位置并填充到副本

    • n = len(nums) 获取列表nums的长度,存储在变量n中。
    • 接着使用一个循环for i in range(n):来遍历nums中的每个元素。
      • 对于每个元素的索引i,计算它旋转k步后的新位置pos,这通过(i+k)%n得到。这里使用取模操作符%是为了处理k大于列表长度的情况,确保计算出的位置索引不会超出列表范围。
      • 然后将原始列表nums中索引为i的元素赋值给副本res中计算出的新位置pos
  • 将修改后的副本复制回原列表

    • 使用另一个循环for i in range(n):来遍历修改后的副本res
    • nums[i] = res[i]将副本res中的每个元素复制回原始列表nums的对应位置
  • 时间复杂度: O(n) + O(n) + O(n) = O(n)
  • 空间复杂度:O(n)

综合来看,这个旋转数组的方法是时间效率较高(线性时间复杂度),但在空间上并不是最优的,因为它需要额外的空间来存储整个数组的副本。在一些对空间敏感的场景下,可能需要考虑其他更节省空间的旋转方法。

 2. 切片并拼接
class Solution:def rotate(self, nums: List[int], k: int) -> None:"""Do not return anything, modify nums in-place instead."""n = len(nums) #Gets the length of the nums list and stores it in n.k = k % n #Updates k to k % n to handle cases where k is greater than n. #This step ensures that the rotation count is within the range of the list's length.nums[:] = nums[n - k:] + nums[:n - k]

 Rotating the List: The list is rotated by slicing and rearranging its elements:

  • nums[:] = nums[n - k:] + nums[:n - k]: This line is the key to rotating the list. It works as follows:
    • nums[n - k:]: Takes a slice of the last k elements from the list.
    • nums[:n - k]: Takes a slice of the first n - k elements from the list.
    • nums[n - k:] + nums[:n - k]: Concatenates the last k elements with the first n - k elements, effectively rotating the list to the right by k steps.
    • nums[:] =: Assigns the newly arranged list back to nums. Using nums[:] instead of nums for assignment modifies the list in place, meaning the original list passed to the function is changed outside the function as well.

综合来看,这个解法在时间复杂度上与前一个方法相同(都是O(n)),但在空间复杂度上更优(O(1) vs. O(n)),因为它避免了创建整个数组副本的需要。这使得它在空间使用上更为高效,特别是对于大数据量的情况。

2. reverse 

class Solution:def rotate(self, nums: List[int], k: int) -> None:"""Do not return anything, modify nums in-place instead."""def reverse(l,r):while (l<r):nums[l],nums[r]= nums[r],nums[l]l += 1r -= 1n = len(nums)k = k % n #计算实际的旋转步数reverse(0, n-1) #翻转整个列表reverse(0, k-1) #翻转前k个元素reverse(k,n-1) #翻转剩余的元素
辅助函数reverse
  • reverse(l, r): 这个内部定义的函数用于翻转nums列表中索引从lr(包含lr)的元素。它通过一个while循环交换两端的元素,直到中间相遇
主方法rotate
  1. 计算实际的旋转步数:因为列表的长度可能小于旋转步数k,所以首先通过k = k % n计算实际需要旋转的步数(n是列表的长度)。这样做的目的是处理k大于列表长度的情况,确保旋转步数是有效的。

  2. 翻转整个列表:通过调用reverse(0, n-1)翻转整个列表。这个步骤是将列表看作是一个环,通过翻转来初始化旋转操作。

  3. 翻转前k个元素:然后通过reverse(0, k-1)仅翻转列表中前k个元素。由于整个列表在第一步中已经翻转过了,这一步实际上是将最初的后k个元素移动到了列表的前面。

  4. 翻转剩余的元素:最后,通过reverse(k, n-1)翻转索引从kn-1的元素,即列表中剩余的部分。这一步将这部分元素恢复到正确的顺序。

示例

假设nums = [1,2,3,4,5,6,7]k = 3,那么旋转的步骤如下:

  1. 原始列表:[1,2,3,4,5,6,7]
  2. 翻转整个列表:[7,6,5,4,3,2,1]
  3. 翻转前k个元素:[5,6,7,4,3,2,1]
  4. 翻转剩余的元素:[5,6,7,1,2,3,4]
最终结果是[5,6,7,1,2,3,4],即将原始列表向右旋转了3步。

66. 加一

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

你可以假设除了整数 0 之外,这个整数不会以零开头。

class Solution(object):def plusOne(self, digits):""":type digits: List[int]:rtype: List[int]"""s = '' #定义一个空字符串s,用于临时存储digits数组表示的数字。l = [] #定义一个空列表l,用于存储最终结果。for i in range(len(digits)):s += str(digits[i])s = str(int(s)+1)for i in s:l.append(int(i))return l

方法步骤详解

将数字数组转换为字符串

  • 通过一个循环for i in range(len(digits)):遍历digits数组。
  • s += str(digits[i]):将每个数字转换为字符串并附加到s上。这一步骤将数字数组如[1, 2, 3]转换为字符串"123"

字符串数字加一

  • s = str(int(s)+1):将字符串s转换为整数并加一,然后再次转换为字符串。这一步处理了整数加一的操作。例如,如果s"123",加一后会变成"124"

将结果字符串转换回数字数组

  • 再次使用循环for i in s:遍历字符串中的每个字符。
  • l.append(int(i)):将每个字符转换回整数并添加到列表l中。例如,如果s"124",则l将变为[1, 2, 4]

返回结果

  • return l返回列表l作为最终结果。

示例

假设输入digits = [1, 2, 3],方法的执行过程如下:

  1. digits转换为字符串s = "123"
  2. 将字符串表示的数字加一得到s = "124"
  3. 将字符串s转换回数组l = [1, 2, 4]
  4. 返回结果[1, 2, 4]

724. 寻找数组的中心下标

示例 1:

输入:nums = [1, 7, 3, 6, 5, 6]
输出:3
解释:
中心下标是 3 。
左侧数之和 sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11 ,
右侧数之和 sum = nums[4] + nums[5] = 5 + 6 = 11 ,二者相等。
class Solution:def pivotIndex(self, nums: List[int]) -> int:sum_left, sum_right = 0, sum(nums)for i in range(len(nums)):sum_right -= nums[i]# 若左侧元素和等于右侧元素和,返回中心下标 iif sum_left == sum_right:return isum_left += nums[i]return -1

方法步骤详解

  1. 初始化变量

    • sum_left, sum_right = 0, sum(nums)sum_left用于存储当前索引左侧元素的和(初始值为0),sum_right用于存储整个数组的和,表示初始时右侧元素的总和。
  2. 遍历数组

    • 使用for i in range(len(nums)):遍历数组中的每个元素。变量i代表当前考虑的中心索引。
  3. 更新右侧和并检查条件

    • sum_right -= nums[i]:在每次循环开始时,从右侧元素和中减去当前元素,因为此元素将被考虑为中心索引的左侧部分。
    • if sum_left == sum_right::检查当前的左侧和是否等于右侧和。如果相等,说明找到了中心索引,直接返回该索引i
  4. 更新左侧和

    • sum_left += nums[i]:将当前元素加到左侧和中,因为在下一次迭代中,当前元素将属于左侧部分。
  5. 遍历结束后

    • 如果遍历了整个数组都没有找到符合条件的中心索引,则返回-1。

示例

假设输入nums = [1, 7, 3, 6, 5, 6],方法的执行过程如下:

  1. 初始sum_left = 0sum_right = 28(数组元素之和)。
  2. 遍历开始,i = 0sum_right更新为27,左侧和不等于右侧和,继续遍历。
  3. i = 3时,sum_left = 11(1+7+3),sum_right也为11(5+6),左侧和等于右侧和,因此返回中心索引3

这种方法的优点是只需要一次遍历就可以找到中心索引(如果存在的话),时间复杂度为O(n),空间复杂度为O(1)(只使用了有限的额外空间)。这种方法既高效又简洁。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线上应用部署了两台load为1四核服务器

线上应用部署了两台服务器。 项目发布后&#xff0c;我对线上服务器的性能进行了跟踪&#xff0c;发现一台负载为3&#xff0c;另一台负载为1&#xff0c;其中一台四核服务器已经快到瓶颈了&#xff0c;所以我们紧急排查原因。 1、使用TOP命令查看占用CPU较大的负载和进程&…

【鸿蒙开发】第十八章 Web组件(二)

接上一章节 【鸿蒙开发】第十七章 Web组件&#xff08;一&#xff09; 4 H5与端侧交互 4.1 应用侧调用前端页面函数 应用侧可以通过runJavaScript()方法调用前端页面的JavaScript相关函数。 在下面的示例中&#xff0c;点击应用侧的“runJavaScript”按钮时&#xff0c;来触…

20、电源管理入门之Hypervisor中的电源管理

目录 1. Hypervisor概念介绍 2. 汽车软件中的Hypervisor应用 3. QNX Hypervisor 4. Hypervisor中的多OS通信技术 5. 电源管理相关 参考: 很多时候听说Hypervisor,但是对底层软件技术不了解的人感觉挺神秘。本篇文章简单介绍下Hypervisor的基本概念,另外介绍下电影管理…

个人健康管理系统|基于微信小程序的个人健康管理系统设计与实现(源码+数据库+文档)

个人健康管理小程序目录 目录 基于微信小程序的个人健康管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1、用户信息管理 2 运动教程管理 3、公告信息管理 4、论坛信息管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设…

资源哟正版无授权模版源码(含搭建教程)

资源哟 v1.3 – 新增两种首页布局 – 新增幻灯片插件 – 优化深色模式颜色效果 – 优化导航页面左侧栏目跳转效果 – 优化后台辅助插件当前页面打开 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/88898100 更多资源下载&#xff1a;关注我。

R语言复现:中国Charls数据库一篇现况调查论文的缺失数据填补方法

编者 在临床研究中&#xff0c;数据缺失是不可避免的&#xff0c;甚至没有缺失&#xff0c;数据的真实性都会受到质疑。 那我们该如何应对缺失的数据&#xff1f;放着不管&#xff1f;还是重新开始?不妨试着对缺失值进行填补&#xff0c;简单又高效。毕竟对于统计师来说&#…

签约仪式如何策划和安排流程?如何邀约媒体现场见证报道

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 签约仪式的策划和安排流程&#xff0c;以及邀约媒体现场见证报道&#xff0c;都是确保活动成功和提升影响力的关键环节。以下是一些建议&#xff1a; 签约仪式的策划和安排流程 明确目标…

SDM450核心板_高通SDM450安卓核心板模块性能参数

高通SDM450核心板是基于SDM450移动平台开发的一款高性能核心板。采用领先的14纳米技术&#xff0c;该核心板为高端智能设备提供了卓越的性能和优质的体验。板载2GB16GB的内存(可选配4GB32GB)&#xff0c;双 ISP(图像传感器处理器)支持丰富的照片细节和双摄像头体验&#xff0c;…

计算机网络——计算机网络的性能

计算机网络——计算机网络的性能 速率带宽吞吐量时延时延宽带积往返时间RTT利用率信道利用率网络利用率 我们今天来看看计算机网络的性能。 速率 速率这个很简单&#xff0c;就是数据的传送速率&#xff0c;也称为数据率&#xff0c;或者比特率&#xff0c;单位为bit/s&#…

MySQL主从读写分离之Proxysql(openEuler版)

实验目的&#xff1a; 基于proxysql实现MySQL的主从读写分离。 实验过程&#xff1a; 前期准备&#xff1a; 一共有四台虚拟机&#xff0c;其中三台为配置好的一主两从虚拟机&#xff0c;还有一台干净的虚拟机用来配置proxysql。 主机名地址master192.168.27.137node1192.…

C语言笔记:文件的操作各种文件函数讲解

突然发现自己的C语言文件部分还没有学&#xff0c;赶紧来补一下~~ 1.文件分类 文本文件磁盘文件&#xff08;二进制文件&#xff09;C语言特殊文件标识&#xff1a;stdin&#xff08;标准输入&#xff1a;通指键盘输入&#xff09;&#xff0c;stdout&#xff08;标准输出&am…

【HarmonyOS】ArkTS-联合类型

目录 联合类型实例 联合类型 联合类型是一种灵活的数据类型&#xff0c;它修饰的变量可以存储不同类型的数据。 语法&#xff1a;let 变量: 类型1 | 类型2 | 类型3 值 基于联合类型&#xff0c;变量可存不同类型数据 实例 // 需求&#xff1a;定义一个变量&#xff0c;存放…