四月份还是三月份有蓝桥杯的算法比赛,加上一直对算法感兴趣。所以从现在开始稍微学一下。

每天会坚持做几题吧,因为不知道哪些比较重要,我就主要记一些我认为重要的内容和算法

数组

数组中心索引

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

当数组中一个索引右边的和等于左边和时,称这个索引为数组的中心索引

def midIndex(nums:List[int])->int:
    all = sum(nums)
    left = 0
    for i in range(len(nums)):
        if left*2+nums[i]==all:
            return i
        else:
            left += nums[i]
    return -1

大概的思路就是根据它的数值对称的思路来实现中心索引的寻找

二分法查找

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

这是一个经典的查找算法,相较于线性查找,它的时间复杂度更简单O(log_n)

def binary_search(nums:List[int],target:int)->int:
    left,right = 0,len(nums)-1
    while left<=right:
        mid = left + (right-left)//2	# 避免整数溢出
        if nums[mid] == target:
            return mid
        elif nums[mid] < target:
            left = mid+1
        else:
            right = mid-1
    return -1

首先设置左右边界,然后判断目标在左区间还是右区间。如果在左区间,则更改右边界条件;在右区间,则更改左边界条件。直到找到目标数值,返回索引

区间合并

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

给一个若干区间组成的数组,其区间含义为[start,end],我们将其进行合并

def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        intervals.sort(key= lambda x:x[0])
        rList = list()
        for interval in intervals:
            if not rList or rList[-1][-1]<interval[0]:
                rList.append(interval)
            else:
                rList[-1][-1] = max(rList[-1][-1],interval[1])
        return rList

首先根据区间的起始位置进行排序,然后创建一个新的列表,设置以下规则:

  • 当列表为空时,加入数组
  • 当列表中数组的最后一位小于当前数组的第一位,说明不重叠,加入数组
  • 当发生重叠时,比较两数组的最后一位,保留大的数字

二维数组

旋转矩阵

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

给你一个NXN矩阵表示的图像,其中每个像素大小为4字节,设计一种算法,将图像顺时针旋转90°

方法一:

使用一个额外的数组来辅助完成

def rotate(self,matrix: List[List[int]])->List[List[int]]:
    rlists = list()
    for j in range(len(matrix[0])):
        rlist = list()
        for i in range(len(matrix)-1,-1,-1):
            rlist.append(matrix[i][j])
            rlists.append(rlist)
    return rlists

这个实际上是通过更改读取顺序的方式,重新创建一个矩阵,但是不符合题目不额外使用空间的思想

方法二:

通过矩阵的几何特性来实现

def rotate(self,matrix: List[List[int]]):
    N = len(matrix)
    # 对角线互换
    for i in range(N):
        for j in range(i):	# 这里要仔细理解,因为接下来要进行互换,所以j要随i增大
            matrix[i][j],matrix[j][i] = matrix[j][i],matrix[i][j]
    # 水平互换
    for i in range(N):
        matrix[i][:] = matrix[i][::-1]

这里我们可以总结:

  • 顺时针旋转90°,先对角翻转,再水平翻转
  • 逆时针旋转90°,先水平翻转,再对角线翻转

零矩阵

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

数字0所在的行与列,在矩阵中全部置0

def setZeroes(self, matrix:List[List[int]]):
    M=len(matrix)
    N=len(matrix[0])
    line=[0]*M
    row=[0]*N
    for i in range(M):
        for j in range(N):
            if matrix[i][j]==0:
                line[i] = 1
                row[j] = 1
    for i in range(M):
        for j in range(N):
            if line[i]==1 or row[j]==1:
                matrix[i][j]=0

这个方法很直观,分别创建行和列的索引,并进行标记,当匹配到标记时,将数据置0

对角线遍历

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

给你一个大小mxn的矩阵mat,以对角线遍历的顺序,用一个数组返回

class Solution(object):
    def findDiagonalOrder(self, mat:List[List[int]])->List[int]:
        ans = []
        Xsize = len(mat)
        Ysize = len(mat[0])
        tot = Xsize + Ysize - 1
        x,y = 0,0
        for i in range(tot):
            if i%2==1:
                while y>=0 and x<Xsize:
                    ans.append (mat[x][y])
                    x += 1
                    y -= 1
                if x<Xsize:
                    y += 1
                else:
                    y += 2
                    x -= 1
            else:
                while x>=0 and y<Ysize:
                    ans.append (mat[x][y])
                    x -= 1
                    y += 1
                if y<Ysize:
                    x += 1
                else:
                    x += 2
                    y -= 1
        return ans

这道题目难在边界条件的处理,需要仔细分析(分类讨论)

**注意:**在观察二维数组时,一定要把索引与行列之间的关系理清除

这里附上一个很好的解答498. 对角线遍历 - 力扣(LeetCode)