【学习日志】202403w2\数据处理和算法

20240309

一. 数组和字符串

1.1 数组介绍

1.1.1 集合、列表和数组
  1. 集合
  • 由一个或多个确定的元素所构成的整体。
  • 特点:
    • 集合里的元素类型不一定相同
    • 无序
  1. 列表
  • 具有相同特性的数据元素构成的有限序列
  • 特点:
    • 元素个数有限,相对位置线性,且长度是可变的(购物清单)
    • 元素无索引,在内存中连续存储(顺序表);非连续存储(链表)
  1. 数组
  • 列表的实现方式之一
  • 特点:
    • 有索引来标识每项数据在数组中的位置,大多数从0开始;
    • 数组中每个元素在内存中连续存储,且占用相同大小的内存
1.1.2 数组的操作
  1. 读取元素
  • 人:访问索引 A A A
  • 计算机:已知数组索引0的内存地址,将内存地址+ A A A,找到对应内存地址的元素,输出目标元素
  • 时间复杂度:只访问了一次内存地址,时间复杂度为 O ( 1 ) O(1) O(1)
  1. 查找元素:
  • 人:输入要查找的元素’ B B B
  • 计算机:找到索引0的内存地址,内存地址依次+1,逐步查找元素是否是目标元素’ B B B’,是则停止查找,否则一直搜索直到数组末尾。
  • 时间复杂度:最长需要搜索到数组末尾,假设数组长度为 N N N,访问 N N N次内存地址,时间复杂度 O ( N ) O(N) O(N)
  1. 插入元素
    两种情况:插入到数组末端或者其他(如索引 C C C C ∈ [ 0 , N − 1 ) C\in [0,N-1) C[0,N1)))
  • 末端:计算机已知数组索引0的内存地址,将内存地址+ N N N,将待插入元素插入到计算得到的的内存地址中
  • 其他:计算机已知数组索引0的内存地址,将内存地址+ N N N,将末尾元素到计算得到的的内存地址中,依次将索引 N − 1 → C N-1 \to C N1C的元素往后移,直到索引 C C C出内存地址对应元素空出,插入目标插入元素
  • 时间复杂度:最坏的情况,要移动 N N N次,所以时间复杂度 O ( n ) O(n) O(n)
  1. 删除元素
  • 人:删除索引 D D D的元素
  • 计算机:找到索引 D D D元素内存地址,删除,将后面的元素依次对该位置进行填补
  • 时间复杂度:最坏的情况,删除索引0对应元素,需要步骤1+(n-1)步,时间复杂度 O ( n ) O(n) O(n)
1.1.3 解题测试
  1. 找数组中心索引
  • 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
    如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1
  • 解题思路:遍历索引计算left总和,如果left总和*2+数组[i]==sum(数组),返回当前i,否则left总和+=数组[i]
  1. 二分法搜索
  • 思想:每次将搜索范围缩小一半
  • 基本条件:数据列表是有序的
class BinarySearch(object):
	def binary_search(self, array, target):
		"""二分法递归查找"""
		if len(array)==0
			return -1
		array.sort()
		mid_index = len(array) // 2
		if array[mid_index] == target
			return mid_index
	return self.binary_search(array[mid_index+1 :], target) if target > array[mid_index] else  self.binary_search(array[:mid_index], target)
  1. 合并区间
  • 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

class Solution(object):
    def merge(self, intervals):
        """
        :type intervals: List[List[int]]
        :rtype: List[List[int]]
        """
        if not intervals:
            return []

        intervals.sort(key=lambda x: x[0])   #将intervals按照每个区间的起始位置进行排序,确保区间按照起始位置的顺序排列。
        merge_list = list()   # 创建一个空列表 merges,用于存储合并后的区间。
        for intervel in intervals:
            if not merge_list or merge_list[-1][-1]<intervel[0]:
                merge_list.append(intervel)
            else:
                merge_list[-1][-1]=max(merge_list[-1][-1],intervel[-1])
        return merge_list

1.2 二维数组介绍

1.2.1 二维数组
  • 将数组中的每个元素变成了一维数组。
  • 计算机已知第一行数组第一个元素的索引位置,即数组[0][0],内存地址顺序为:[0][0]、[0][1]、…、[1][0]、[1][1]、…、[2][0]、…、[N][N]依次存储。
  • 注意:数组中元素由于类型不同会占用不同的字节数,因此内存递增不一定为1.
1.2.2 解题测试
  1. 旋转矩阵
  • 给一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请设计一种算法,将图像旋转 90 度。(不占用额外内存空)
class Solution(object):
    def rotate(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: None Do not return anything, modify matrix in-place instead.
        """
        # 先按主对角线翻转矩阵
        for i in range(len(matrix)):
            for j in range(0,i+1):
                 matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
        # 再左右翻转矩阵         
        for i in range(len(matrix)):
            for j in range(len(matrix)//2):
                matrix[i][j], matrix[i][len(matrix)-1-j]  = matrix[i][len(matrix)-1-j], matrix[i][j]
        return matrix
  1. 零矩阵
  • 编写一种算法,若M × N矩阵中某个元素为0,则将其所在的行与列清零。
class Solution(object):
    def setZeroes(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: None Do not return anything, modify matrix in-place instead.
        """
        m = len(matrix)
        n = len(matrix[0])
        row = [0] * len(matrix)
        column = [0] * len(matrix[0])

        # 统计、记录行列为0的元素
        for i in range(m):
            for j in range(n):
                if matrix[i][j] == 0:
                    row[i] = 1
                    column[j] = 1
        
        for i in range(m):
            for j in range(n):
                if row[i] == 1 or column[j] == 1:
                    matrix[i][j] = 0
  1. 对角线遍历
class Solution(object):
    def findDiagonalOrder(self, mat):
        """
        :type mat: List[List[int]]
        :rtype: List[int]
        """
        m = len(mat)
        n = len(mat[0])
        result_list = list()

        for i in range(0, m+n-1):
            # 如果遍历数是偶数,向上遍历,行列元素值相加为i
            if i % 2 == 0:
                l = min(m-1, i)
                c = i-l
                while l>=0 and c<n: # 添加边界检查
                    result_list.append(mat[l][c])
                    l -=1
                    c +=1
            else:
            # 如果遍历数是奇数,向下遍历,行列元素值相加为i
                c = min(n-1, i)
                l = i-c
                while c>=0 and l<m: # 添加边界检查
                    result_list.append(mat[l][c])
                    l +=1
                    c -=1
        return result_list

1.3 字符串介绍

1.3.1 字符串简介
string = 'Hello, world!'  # 字符串用'' 或者""括起来,可包含任何字符(字母、数字、标点符号和特殊字符)
# 可使用索引或者切片来访问单个字符或者子串
print(string[0])  # 输出'H'
print(string[7:])  # 输出'world!'
str_a = string.strip().split()   # 去掉空前后缀
print(str_a)  #输出 ['Hello,', 'world!']
str_a.reverse()  # 反转字符串
print(' '.join(str_a)) # 输出 world! Hello,
1.3.2 解题测试
  1. 最长公共前缀
  • 编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 “”
from typing import List

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
            if not strs: return ""
            s1 = min(strs)  # 字符串中表示 最小字典序 ASCII值 
            s2 = max(strs)
            # enumerate()返回一个元组(index,value)-->索引,元素
            for i,x in enumerate(s1):  
                if x != s2[i]:
                    return s2[:i]
            return s1

strs = ["flower","flow","flight"]
s1 = min(strs)  # 'flight'
s2 = max(strs)  # 'flower'
result = Solution()
result_end = result.longestCommonPrefix(strs)
  1. 最长回文子串
class Solution:
    def longestPalindrome(self, s: str) -> str:
        ret = ''
        for i in range(len(s)):
        	# 考虑回文串长度为奇数的情况,即以s[i]为中心对齐
            tmp = self.helper(s,i,i)
            if len(tmp)>len(ret):
                ret = tmp
            # 考虑回文串长度为偶数的情况,即以s[i]和s[i+1]之间的间隙为中心对齐
            tmp  = self.helper(s,i,i+1)
            if len(tmp)>len(ret):
                ret = tmp
        return ret 

    def helper(self, s, l, r):
        while l>=0 and r<len(s) and s[l]==s[r]:
            l-=1; r+=1
        return s[l+1:r]

result = Solution() #定义对象
result_end = result.longestPalindrome("cbbd") #调用函数,传入字符串参数
result_end
  1. KMP算法(模式匹配)
    问题:主串 S 和模式串T ,在主串 S中找出模式串T的第一个匹配项的下标(下标从 0 开始)。如果模式串T不是主串 S 的一部分,则返回 -1 。
  • 朴素解法:将S中元素与模式串T逐个匹配,若不匹配,则匹配起始点右移,逐个匹配,直到匹配成功。最坏情况需执行匹配 len(S)-len(T)+1轮,每一轮匹配执行匹配操作 len(T)次
class Solution:
    def strStr(self, S: str, T: str) -> int:
        i = 0
    	j = 0
    	while i < len(S) and j < len(T):
        	if S[i] == T[j]:    # 依次比较,相等则比较下一个字符
            	i += 1; j += 1
        	else:    # 如果不相等,指针i需要回溯到上个起点的下一个位置, 并从头开始比较
            	i = i - j + 1; j = 0
    	# while循环结束后,要么是找到合适匹配了,要么是遍历完主串都没有找到合适匹配
    	if j == len(T):
        	return i - j
    	else:
        	return -1
  • KMP解法
    • 定义next()函数,其中包含模式串T的局部信息,利用匹配失败后的信息,进行下次匹配。
    • 将S中元素与模式串T逐个匹配,如果匹配失败时在主串S[i]和T[j]上,那么匹配起始点尽可能右移多个元素(j-k个),S[i]和T[k]继续匹配。
    • next()函数求出k值

    next(j) 满足: 当 j=0时,next(0)=-1
    其他情况,next(j)= 前后缀(不包括本身)的最长公共子缀的长度T[:j]前后缀(不包括本身)的最长公共子缀的长度

class Solution:
    def strStr(self, S: str, T: str) -> int:
            i = 0
            j = 0
            prefix = self.net_generate(T)
            while i<len(S) and j<len(T):
                if  j ==-1 or S[i]==T[j]:
                    i+=1; j+=1
                else:
                    j =prefix[j]
                
            if j==len(T):
                 result = i-j
            else:
                result = -1
            return result
      

    def net_generate(self, s):
        j = 0
        t = -1 
        next = [-1] *len(s)
        while j < len(s)-1:
            if t == -1 or s[j]==s[t]:
                j +=1; t+=1
                next[j] = t
            else:
                t = next[t]
        return next

- 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值