Python学习笔记

犀利的毛毛虫 发布于 2025-03-02 247 次阅读


计数

number_0 = s_list.count('0')

计算s_list数组中0的个数

合成元组+排序

dishes = sorted(zip(a, s_list))
  • zip(a, s_list) 将两个列表 a 和 s_list 中的元素一一对应地组合成元组,形成一个新的列表。例如,如果 a = [10, 20, 30] 和 s_list = ['0', '0', '1'],那么 zip(a, s_list) 会生成 [(10, '0'), (20, '0'), (30, '1')]
  • sorted(...) 对这些元组进行排序。默认情况下,sorted 函数会根据元组的第一个元素(即价格 a)进行排序。因此,dishes 最终会是一个按价格从小到大排序的列表,每个元素是一个元组,包含价格和对应的蘑菇状态。

翻转

result = result[::-1]

字符串加法

    len1, len2 = len(string1), len(string2)
    max_len = max(len1, len2)
    result = []
    carry = 0

    for i in range(max_len):
        digit_1 = int(string1[len1 - i - 1]) if i < len1 else 0
        digit_2 = int(string2[len2 - i - 1]) if i < len2 else 0
        total = digit_1 + digit_2 + carry
        carry = total // 10
        result.append(total % 10)
    
    if carry:
        result.append(1)

    result = result[::-1]

选择数组中的所有最值与下标

    min_val, max_val = float('inf'), float('-inf')
    min_pos, max_pos = [], []
    for i, val in enumerate(result):
        if val < min_val:
            min_val = val
            min_pos = [i]
        elif val == min_val:
            min_pos.append(i)

        if val > max_val:
            max_val = val
            max_pos = [i]
        elif val == max_val:
            max_pos.append(i)

双指针

    j, k = 0, 0
    min_distance = float('inf')
    while j < len(min_pos) and k < len(max_pos):
        distance = abs(min_pos[j] - max_pos[k])
        min_distance = min(min_distance, distance)
        if min_pos[j] < max_pos[k]:
            j += 1
        else:
            k += 1
    return max(0, min_distance - 1)

数组操作

序列添加:

new_li.extend(range(1, num + 1)) 

这行代码的作用是将一个从 1 到 num 的递增序列添加到 new_li 列表中。

具体来说:

range(1, num + 1) 生成一个从 1 到 num 的整数序列。例如,如果 num 是 4,那么 range(1, 5) 会生成 [1, 2, 3, 4]。
new_li.extend(...) 将生成的序列中的所有元素添加到 new_li 列表的末尾。
所以,new_li.extend(range(1, num + 1)) 的作用是将 [1, 2, ..., num] 这个序列追加到 new_li 列表中。

示例
假设 num = 3,那么:

python
执行后,new_li 将变为 [1, 2, 3]。

将数组转为字符串

# 将数字数组转换为字符串
result_str = "".join(map(str, nums))

这里,map(str, nums)nums中的每个数字转换为字符串,然后"".join(...)将这些字符串连接成一个单一的字符串。

进制

int(''.join(f'{x:02x}' for x in mc), 16)

这段代码的作用是将一个包含RGB值的列表转换为一个十六进制整数。让我们逐步解析这段代码:

  1. f'{x:02x}':
    • f'{x:02x}' 是一个格式化字符串,用于将整数 x 转换为两位的十六进制字符串。
    • :02x 表示将 x 转换为十六进制,并且如果结果不足两位,则在前面补零。
  2. ''.join(...):
    • ''.join(...) 用于将一个可迭代对象(在这里是一个生成器表达式)中的所有元素连接成一个字符串。
    • 生成器表达式 f'{x:02x}' for x in mc 会遍历 mc 列表中的每一个元素 x,并将其转换为两位的十六进制字符串。
  3. int(..., 16):
    • int(..., 16) 将一个字符串转换为整数,其中 16 表示这个字符串是一个十六进制数。
    • 因此,''.join(f'{x:02x}' for x in mc) 生成的字符串会被解释为一个十六进制数,并转换为对应的整数。

f'{x:02x}' 是 Python 中的一种格式化字符串的方式,通常用于将整数 x 转换为两位的十六进制表示形式。下面是对这个表达式的详细解释:

  1. f'...': 这是 Python 3.6 引入的 f-string 格式化字符串的方式。f-string 允许在字符串中嵌入表达式,这些表达式会在字符串被创建时进行求值。
  2. {x:...}: 在 f-string 中,{x:...} 表示对变量 x 进行格式化。x 是要格式化的变量或表达式,: 后面的部分是格式说明符。
  3. 02x: 这是格式说明符,具体含义如下:
    • 02: 表示输出的字符串至少要有两位。如果 x 的十六进制表示不足两位,前面会用 0 补齐。例如,如果 x 是 1,那么 02 会将其格式化为 01
    • x: 表示将 x 转换为小写的十六进制表示。例如,如果 x 是 10,那么 x 会将其格式化为 0a

二分查找

int searchInsert(int* nums, int numsSize, int target) {
    int left=0,right=numsSize-1;
    while(left<=right){
        int mid=(left+right)/2;
        if(nums[mid]<target){
            left=mid+1;
        }else{
            right=mid-1;
        }
    }
    return left;
}

连连看

from collections import *
 
n, m = map(int, input().split())
a = [list(map(int, input().split())) for _ in range(n)]
 
def acc(a): # 统计从左上到右下方向上的格子对数量
    res = 0
    for k in range(-(n - 1), m):
        i, j = -k * (k < 0), k * (k > 0) # 该方向上第一个位置
        c = Counter()
        while i < n and j < m:
            c[a[i][j]] += 1
            i += 1; j += 1
        for v in c.values():
            res += v * (v - 1)
    return res
 
print(acc(a) + acc([a[i][::-1] for i in range(n)]))

这段代码主要的功能是计算一个二维数组中,对角线方向上相同数字的配对数量。它考虑了两种对角线方向:从左上到右下,以及从右上到左下。

代码结构分解:

  1. 导入模块: Pythonfrom collections import * 这行代码从 collections 模块导入了所有的类和函数。在这个代码中,主要用到了 Counter 类。Counter 是一个很有用的工具,它可以用来统计列表中每个元素出现的次数。
  2. 读取输入: Pythonn, m = map(int, input().split()) a = [list(map(int, input().split())) for _ in range(n)]
    • n, m = map(int, input().split()): 这行代码首先从用户的输入读取一行,这行输入应该包含两个整数,分别代表二维数组的行数 n 和列数 minput().split() 会将输入的字符串按空格分割成一个字符串列表,map(int, ...) 会将列表中的每个字符串转换为整数,最后 n, m = ... 将这两个整数分别赋值给变量 nm
    • a = [list(map(int, input().split())) for _ in range(n)]: 这行代码用来读取二维数组的元素。它使用列表推导式来创建 n 行的二维数组。
      • for _ in range(n): 这个循环会执行 n 次,即读取 n 行数据。
      • input().split(): 每次循环读取一行输入,同样按空格分割成字符串列表。
      • map(int, ...): 将字符串列表中的每个元素转换为整数。
      • list(...): 将 map 对象转换为列表,即得到一行的整数列表。
      • [...]: 将每行得到的整数列表收集起来,形成一个包含 n 个列表的列表,也就是二维数组 a
  3. acc(a) 函数: Pythondef acc(a): # 统计从左上到右下方向上的格子对数量 res = 0 for k in range(-(n - 1), m): i, j = -k * (k < 0), k * (k > 0) # 该方向上第一个位置 c = Counter() while i < n and j < m: c[a[i][j]] += 1 i += 1; j += 1 for v in c.values(): res += v * (v - 1) return res
    • 函数定义: def acc(a): 定义了一个名为 acc 的函数,它接受一个二维数组 a 作为输入。这个函数的功能是统计从左上到右下方向的对角线上,相同数字的配对数量。
    • 初始化结果: res = 0 初始化一个变量 res 为 0,用来累加配对数量。
    • 遍历对角线:for k in range(-(n - 1), m): 这个循环遍历所有从左上到右下的对角线。这里的 k 值决定了对角线的起始位置。
      • range(-(n - 1), m): k 的取值范围是从 -(n-1)m-1。这个范围覆盖了所有从左上到右下的完整对角线,以及可能只在数组部分区域内的对角线。
      • i, j = -k * (k < 0), k * (k > 0): 这行代码计算当前对角线的起始位置 (i, j)
        • 如果 k < 0,则 i = -k, j = 0。这对应于对角线起始于第一列(j=0),并在下方开始的情况。例如,当 k = -1 时,起始位置是 (1, 0)
        • 如果 k >= 0,则 i = 0, j = k。这对应于对角线起始于第一行(i=0),并在右方开始的情况。例如,当 k = 1 时,起始位置是 (0, 1)
      • 统计对角线元素: Pythonc = Counter() while i < n and j < m: c[a[i][j]] += 1 i += 1; j += 1
        • c = Counter(): 在开始处理每条对角线时,创建一个新的 Counter 对象 c,用于统计当前对角线上每个数字出现的次数。
        • while i < n and j < m:: 这个循环遍历当前对角线上的元素,条件是 i(行索引)不能超出数组的行数 n,且 j(列索引)不能超出数组的列数 m
        • c[a[i][j]] += 1: 对于对角线上的每个格子 a[i][j],将其值作为键,在 Counter 对象 c 中增加计数。
        • i += 1; j += 1: 移动到对角线上的下一个格子(行索引和列索引都加 1)。
      • 计算当前对角线的配对数量: Pythonfor v in c.values(): res += v * (v - 1)
        • for v in c.values():: 遍历 Counter 对象 c 中所有的值(即每种数字出现的次数)。
        • res += v * (v - 1): 对于每种数字,假设它出现了 v 次,那么这种数字在当前对角线上形成的配对数量是 v * (v - 1)。这里计算的是有序对的数量。例如,如果有 3 个相同的数字,它们可以形成 3*2 = 6 个有序对 ( (元素1, 元素2), (元素1, 元素3), (元素2, 元素1), (元素2, 元素3), (元素3, 元素1), (元素3, 元素2) )。 如果是计算无序对(即组合),应该使用 v * (v - 1) // 2。代码中使用 v * (v - 1) 可能是因为问题需要计算有序对,或者在后续的计算中,配对数量会被除以 2(但代码中没有除以 2 的操作,所以更倾向于计算的是有序对)。 将每种数字的配对数量加到总结果 res 中。
    • 返回结果: return res 函数返回累加的总配对数量 res,这代表了所有从左上到右下对角线上相同数字的配对总数。
  4. 主程序和输出: Pythonprint(acc(a) + acc([a[i][::-1] for i in range(n)]))
    • 计算第一部分配对数: acc(a): 首先调用 acc(a) 函数,计算原始二维数组 a 中,所有从左上到右下对角线上的相同数字配对数量。
    • 创建翻转数组并计算第二部分配对数: [a[i][::-1] for i in range(n)]: 这是一个列表推导式,它创建了一个新的二维数组。对于原始数组 a 的每一行 a[i],使用 [::-1] 将行进行反转。这样就得到了一个行被水平翻转的新数组。 acc([a[i][::-1] for i in range(n)]): 然后,对这个行翻转后的新数组调用 acc() 函数。由于行被翻转了,所以在新数组中从左上到右下的对角线,实际上对应于原始数组中从右上到左下的对角线。因此,这次 acc() 函数调用计算的是原始数组从右上到左下对角线上的相同数字配对数量。
    • 求和并输出: acc(a) + acc([a[i][::-1] for i in range(n)]): 将两次 acc() 函数调用的结果相加,得到总的配对数量(包括左上到右下和右上到左下两个方向)。 print(...): 最后,将这个总配对数量输出到控制台。

总结代码功能:

这段代码接收一个二维数组作为输入,然后计算并输出了该数组中,以下两种对角线方向上,相同数字的配对总数(有序对):

  1. 从左上到右下的对角线
  2. 从右上到左下的对角线(通过将原始数组的每一行翻转,然后计算翻转后数组的左上到右下对角线来间接实现)。

代码的核心在于 acc() 函数,它通过遍历不同起始位置来覆盖所有需要的对角线,并使用 Counter 有效地统计每条对角线上数字的频率,最后计算配对数量。主程序通过两次调用 acc() 函数,分别处理了两种对角线方向,并将结果求和得到最终答案。

关于时间

t = int(input())
start = datetime.fromisoformat('1970-01-01 00:00:00')
for _ in range(t):
    date, time, interval = input().split()
    dt = datetime.fromisoformat(date + ' ' + time)
    now = int((dt - start).total_seconds()) // 60
    now -= now % int(interval)
    print(start + timedelta(minutes=now))

python中的cin函数自定义

cin = lambda: list(map(int, input().split()))
 
for s, t in zip(cin(), cin()):
    s, t = str(s), str(t)
    f2_ = f2.copy() # 拷贝
    update(t, f2, f1)
    for d in digs:
        if str(d) in s and f1[d] < 0:
            f1[d] = max(*f1, 1) # 确保先从 s 开始走
    update(s, f1, f2_)
            
print(max(f1 + f2))

动态规划+哈希表的一道题

cin = lambda: list(map(int, input().split()))
 
input()
f1, f2 = [-1] * 5, [-1] * 5
digs = (0, 2, 4)
 
def update(s, f1, f2):
    for d in digs:
        if str(d) in s:
            f1[d] = max(f1[d], max(f2[i] + 1 for i in digs if str(i) in s))
 
for s, t in zip(cin(), cin()):
    s, t = str(s), str(t)
    f2_ = f2.copy() # 拷贝
    update(t, f2, f1)
    for d in digs:
        if str(d) in s and f1[d] < 0:
            f1[d] = max(*f1, 1) # 确保先从 s 开始走
    update(s, f1, f2_)
            
print(max(f1 + f2))

质数判定

import random
def is_prime(n):
    if n <= 1:
        return False
    if n <= 3 :
        return True
    if n % 2 == 0 or n % 3 == 0:
        return False
    r, s = 0, n - 1
    while s % 2 == 0: # n-1 = 2^r * s , s为奇数部分
        r += 1
        s //= 2
    for _ in range(5):
        a = random.randint(2, n - 2)
        x = pow(a, s, n)  # a^s mod n
        if x == 1 or x == n - 1:
            continue
        for _ in range(r - 1):
            x = pow(x, 2, n)
            if x == n - 1:
                break
        else:
            return False
    return True

t = int(input())
for i in range(t):
    n = int(input())
    if is_prime(n):
        print("1")
    else:
        print("0")

自动安装库

import sys
import subprocess
import importlib.util

# 检查必要的库是否已安装
required_packages = ['requests']
for package in required_packages:
    if importlib.util.find_spec(package) is None:
        print(f"正在安装必要的库: {package}")
        subprocess.check_call([sys.executable, "-m", "pip", "install", package])

Floyd寻找最小路径

import sys

INF = float('inf')
n, m, q = map(int, input().split())
dis = [[INF] * (n + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
    dis[i][i] = 0
for _ in range(m):
    u, v, w = map(int, input().split())
    dis[u][v] = dis[v][u] = min(dis[u][v], w)
# Floyd-Warshall algorithm
for k in range(1, n + 1):
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j])
# Output
for _ in range(q):
    s, t = map(int, input().split())
    ans = dis[s][t] if dis[s][t] != INF else -1
    print(ans)

标准库bisect自带的二分函数

🚀 四种经典使用场景

场景1:精确查找目标值

def binary_search(arr, target):
    index = bisect.bisect_left(arr, target)
    if index < len(arr) and arr[index] == target:
        return index
    return -1

场景2:寻找插入位置

# 在有序数组中找插入位置(如leetcode35)
pos = bisect.bisect_left([1,3,5,7], 6)  # 返回3(插入到5和7之间)

场景3:统计区间元素数量

# 统计[L, R]范围内的元素个数(闭区间)
count = bisect.bisect_right(arr, R) - bisect.bisect_left(arr, L)

场景4:维护动态有序列表

sorted_list = []
for num in stream:
    bisect.insort_left(sorted_list, num)  # 实时保持有序性