datawhale学习-算法入门与数组篇

一、数组基础

1.数组简介

1.1数组定义

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

1.整数数组的储存方式:

1.2如何随机访问数组元素

可以进行随机访问。即数组可以根据下标,直接定位到某一个元素存放的位置。

数组寻址公式如下:下标 i 对应的数据元素地址 = 数据首地址 + i × 单个数据元素所占内存大小

1.3多维数组

二维数组其本质上是以数组作为数据元素的数组,二维数组的第一维度表示行,第二维度表示列。

二维数组形式如下图:

1.4不同编程语言中二维数组的创建

1.c/c++:

C / C++ 语言中的数组最接近数组结构定义中的数组,使用的是一块存储相同类型数据的、连续的内存空间。不管是基本类型数据,还是结构体、对象,在数组中都是连续存储的。

int arr[3][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}};

2.java:

Java 中的数组跟数据结构定义中的数组不太一样。Java 中的数组也是存储相同类型数据的,但所使用的内存空间却不一定是连续(多维数组中)。且如果是多维数组,其嵌套数组的长度也可以不同。

int[][] arr = new int[3][]{ {1,2,3}, {4,5}, {6,7,8,9}};

3.python:

python使用了类似 Java 中的 ArrayList 容器类数据结构,叫做列表。通常我们把列表来作为 Python 中的数组使用。Python 中列表存储的数据类型可以不一致,数组长度也可以不一致。

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

2.数组的基本操作

我将通过LeetCode中的题目来带大家认识python中的数组操作。

1.访问元素

2.查找元素

3.插入元素

4.改变元素

5.删除元素

在LeetCode有一道非常经典的题,两数之和,这道题考查了我们对数组元素的访问。

个人题解:

class Solution:

    def twoSum(self, nums: List[int], target: int) -> List[int]:

        for i, x in enumerate(nums):  # x=nums[i],nums中的元素可以通过nums[i]的方式直接访问

#enumerate(nums) 可以返回一个迭代器,其中包含每个元素的索引和对应的值。i 表示索引,x 表示对应的值。

            for j in range(i + 1, len(nums)):  # 枚举 i 右边的 j

                if x + nums[j] == target:  # 满足要求

                    return [i, j]     #返回结果

这道题涉及访问、插入元素以及数组和数字之间的转换,我们通过取出数组中的每个元素,并在运算操作后再将数据插入数组中。

个人题解:

class Solution:

    def plusOne(self, digits: List[int]) -> List[int]:

        num=0

        for i in digits:#将数组中的元素取出

            num*=10

            num+=i

        num+=1

        digits_0=[]

        while num!=0:

            digits_0.insert(0,num%10)#将处理后的数据插入数组

            num=num//10

        return digits_0

这道题涉及到查找元素以及对数组的理解

个人题解:

class Solution:

    def pivotIndex(self, nums: List[int]) -> int:

        n=len(nums)

        total=sum(nums)

#计算整个数组的总和 total,作为右侧元素的和。

        start=0

#初始化 start 为 0,用于记录左侧元素的和

        for i in range(n):

            total-=nums[i]

#遍历数组 nums,对于每个元素,首先将其从 total 中减去,得到右侧元素的和(不包括当前元素)

            if start==total:

                return i

#检查 start 是否等于 total,如果相等,则说明当前索引 i 是中心索引,返回 i

            start+=nums[i]

        return -1

#如果没有找到中心索引,则返回 -1

该题涉及到改变元素、以及对元素的倒数访问

个人题解:

class Solution:

    def rotate(self, nums: List[int], k: int) -> None:

        """

        Do not return anything, modify nums in-place instead.

        """

        k=k%len(nums)

        nums[:]=nums[-k:]+nums[:-k]

在此题中注释表示函数不要返回任何值,而是直接在原始的 nums 列表上进行修改。

我们来区分一下nums=nums[-k:]+nums[:-k]与nums[:]=nums[-k:]+nums[:-k]区别

前者表示创建一个新的列表,并将其赋值给 nums后者使用切片赋值的方式来修改列表。通过将新列表的元素切片赋值给 nums,可以直接修改列表的内容,而不创建新的列表对象,而此题要求我们直接在原始的列表上修改,故采用后者来对nums的值进行修改。  

3.数组的基础知识总结

数组是最基础、最简单的数据结构。数组是实现线性表的顺序结构存储的基础。它使用一组连续的内存空间,来存储一组具有相同类型的数据。

数组的最大特点的支持随机访问。访问数组元素、改变数组元素的时间复杂度为 O(1),在数组尾部插入、删除元素的时间复杂度也是 O(1),普通情况下插入、删除元素的时间复杂度为 O(n)。

4.数组练习题目

部分题目已在前面的教程中展出

1.

解决该题目需要用到矩阵的转置以及行顺序调换

class Solution:

    def rotate(self, matrix: List[List[int]]) -> None:

        """

        Do not return anything, modify matrix in-place instead.

        """

        n=len(matrix) #表示矩阵的边长

        for i in range(n):

            for j in range(i+1,n):#通过双重循环进行矩阵的转置

                temp=matrix[i][j]

                matrix[i][j]=matrix[j][i]

                matrix[j][i]=temp

        for i in range(n):

            for j in range(n//2):#通过双重循环完成每行元素顺序的反转

                temp=matrix[i][n-1-j]

                matrix[i][n-1-j]=matrix[i][j]

                matrix[i][j]=temp

2.

此题考查了对二维数组结构的理解,我们采用a,b,m,n分别表示图表的上边界、下边界、左边界、右边界,每当添加完一行或一列数据后把对应上边界和左边界的记录值减一,下边界和右边界的记录值加一,从而完成图表的更新,如此循环,最终得出结果。

个人题解如下:

class Solution:

    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:

        a=0

        b=len(matrix)-1

        m=0

        n=len(matrix[0])-1

        count=(b+1)*(n+1)#count表示二维数组的元素数

        result=[]

        if count==0:

            return result#若为空数组则直接返回

        else:

            while True:

                for i in range(m,n+1):

                    result.append(matrix[a][i])#从左到右添加行数据

                a+=1#上边界更新

                if a>b:

                    break

                for i in range(a,b+1):

                    result.append(matrix[i][n])#从上到下添加列数据

                n-=1#右边界更新

                if m>n:

                    break

                for i in range(n,m-1,-1):

                    result.append(matrix[b][i])#从右向左添加行数据

                b-=1#下边界更新

                if a>b:

                    break

                for i in range(b,a-1,-1):

                    result.append(matrix[i][m])#从下到上添加列数据

                m+=1#上边界更新

                if m>n:

                    break

            return result#返回添加后的数组

3.

本题通过巧妙的方式考察了对二维数组下标的访问,以及对循环的理解和掌握,通过使用两个嵌套循环来遍历矩阵的对角线;使用条件判断进行不同情况的处理,根据循环次数的奇偶性,选择不同的遍历方向;列表操作的运用,使用列表推导式生成并添加遍历的元素到结果列表。

个人题解:

class Solution:

    def findDiagonalOrder(self, mat: List[List[int]]) -> List[int]:

        m=len(mat)

        n=len(mat[0])

        result=[]

        for i in range(m+n-1):#通过使用两个嵌套循环来遍历矩阵的对角线

            if i % 2 == 0:#根据循环次数的奇偶性,选择不同的遍历方向

                result+=[mat[count][i-count]for count in range(min(i,m-1),max(-1,i-n),-1)]

            else:#使用列表推导式生成并添加遍历的元素到结果列表

                result+=[mat[count][i-count]for count in range(max(0,i-n+1),min(i+1,m))]

        return result

4.

这道题较为基础,需要遍历给定的二进制数组 nums,以便逐个检查其中的元素,以及根据当前的元素值(0 或 1)来判断连续 1 的个数应该如何更新,在遇到 0 时如何重新计数,还需要不断更新一个最大值变量,以便记录已经遍历过的连续 1 的最大个数。 

个人题解:

class Solution:

    def findMaxConsecutiveOnes(self, nums: List[int]) -> int:

        count=[]

        index=0

        for i in nums:#遍历给定的二进制数组 nums

            if i==1:#根据当前的元素值(0 或 1)来判断连续 1 的个数

                index+=1#记录已经遍历过的连续 1 的最大个数

            else:

                count.append(index)

                index=0

            count.append(index)

        return max(count)#取数组中的最大值

5.

个人题解:

这段代码时间复杂度为O(n),空间复杂度为O(1),核心思想是通过先遍历一次数组得到每个元素前面所有元素的乘积,再遍历一次数组得到每个元素后面所有元素的乘积,最后将前后两个乘积合并。

class Solution:

    def productExceptSelf(self, nums: List[int]) -> List[int]:

        result=[1]*len(nums)#result 列表是一个空列表,用于存储每个元素左侧所有元素的乘积

        num=1

        for i in range(len(nums)):

            result[i]=num#遍历输入的 nums 列表,使用变量 num 记录当前位置左侧所有元素的乘积,并将其赋值给 result[i]

            num*=nums[i]#更新 num 为当前位置元素的乘积,以便计算下一个位置左侧所有元素的乘积

        num=1

        for i in range(len(nums)-1,-1,-1):#进行一次反向的循环,从倒数第二个元素开始到第一个元素(索引为 len(nums)-1 到 -1)

            result[i]*=num#计算每个元素右侧所有元素的乘积,并将其与 result[i] 相乘,得到每个元素除自身以外的所有元素的乘积。

            num*=nums[i]

        return result

6.

个人题解:

class Solution:

    def setZeroes(self, matrix: List[List[int]]) -> None:

        """

        Do not return anything, modify matrix in-place instead.

        """

        m=len(matrix)

        n=len(matrix[0])#获取矩阵的行数和列数

        a=set()

        b=set()#创建两个空的集合 ab

        for i in range(m):#通过两层嵌套循环遍历矩阵的每个元素。

            for j in range(n):

                if matrix[i][j]==0:#如果当前元素的值为 0

                    a.add(i)#将该元素所在的行号和列号分别添加到集合 ab

                    b.add(j)

        for i in range(m):#再进行一次两层嵌套循环遍历矩阵的每个元素。

            for j in range(n):

                if (i in a)or(j in b):#对于每个元素,如果该元素所在的行号或列号出现在集合 ab

                    matrix[i][j]=0#就将该元素的值修改为 0

7.

class Solution:

    def generateMatrix(self, n: int) -> List[List[int]]:

        a=0

        b=n-1

        c=0

        d=n-1

#使用类似的边界控制和循环结构,通过四个变量 abcd 来表示当前矩阵的上下左右边界

        result = [[0 for j in range(n)] for i in range(n)]

#创建一个大小为 n x n 的二维数组 result,用于存放最终生成的蛇形矩阵

        num=1

#循环开始之前,初始化变量 num 为 1,用于记录当前要填入的数字。接下来,通过一个无限循环来不断填充矩阵中的元素

        while True:

            for i in range(c,d+1):

#循环中,首先从左到右填充最上面的行,然后将上边界下移一行(a+=1

                result[a][i]=num

                num+=1

            a+=1

            if a>b:

                break

            for i in range(a,b+1):

#从上到下填充最右边的列,然后将右边界左移一列(d-=1

                result[i][d] =num

                num+=1

            d-=1

            if c>d:

                break

            for i in range(d,c-1,-1):

#从右到左填充最下面的行,将下边界上移一行(b-=1

                result[b][i]=num

                num+=1

            b-=1

            if a>b:

                break

            for i in range(b,a-1,-1):

#从下到上填充最左边的列,将左边界右移一列(c+=1

                result[i][c]=num

                num+=1

            c+=1

            if c>d:

                break

#当所有位置都被填充完后,返回生成的蛇形矩阵 result

        return result

 8.

个人题解:

此题较难,思考半天也法处理细胞之间的相互影响,借鉴了下大佬的思路才运行成功

class Solution:

    def gameOfLife(self, board: List[List[int]]) -> None:

        """

        Do not return anything, modify board in-place instead.

        """

        m=len(board)

        n=len(board[0])

        for i in range(m):

            for j in range(n):

                count=0#这里统计每个格子周围八个格子的活细胞数,每个格子计数重置为零

                for a in range(-1,2):

                    for b in range(-1,2):

#if判断取出越界的情况

                        if (a==0 and b==0)or i+a<0 or i+a>=m or j+b<0 or j+b>=n:

#如果周围格子是活细胞(1)或活细胞变死细胞(2)的,都算一个活细胞

                            continue

                        if board[i+a][j+b]==1 or board[i+a][j+b]==2:

                            count+=1

                if board[i][j] == 1 and (count < 2 or count > 3):

                    board[i][j] = 2

#格子本身是活细胞,周围满足变成死细胞的条件,标记为2

                if board[i][j] == 0 and count == 3:

#格子本身是死细胞,周围满足复活条件,标记为3

                            board[i][j] = 3

        for i in range(m):

            for j in range(n):

# 死细胞为0,活细胞变成死细胞为2,都为偶数,模2为0,刚好是死细胞
# 活细胞为1,死细胞变成活细胞为3,都为奇数,模2为1,刚好是活细胞

                board[i][j] %= 2

本文参考链接: 

https://datawhalechina.github.io/leetcode-notes/#/ch01/01.02/01.02.01-Array-Basic

https://leetcode.cn/leetbook/

https://leetcode.cn/problems/game-of-life/solutions/2353592/javapython3cmo-ni-te-shu-zhi-biao-ji-by-9b72c/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值