python

2019-09-10-python

python

注释: 单行#comment 多行'''comment''' """comment"""

1
2
3
4
5
6
python2 -m pip install --upgrade pip  
pip install virtualenv virtualenvwrapper
virtualenv testvir
active.bat 或者 deactive.bat
pip install flask
pip freeze >requirements.txt

基础语法

1
2
from package import module  
import module as alias

变量和数据类型

对象(object)是内存中专门用来存储数据的一块区域,id && type && value

变量和对象:

(1)对象并没有直接存储到变量中,Python中变量更像是给对象起了一个别名

(2)变量中存储的不是对象的值,而是对象的id(内存地址),使用变量时,实际上就是在通过对象id在查找对象

(3)变量中保存的对象,只有在为变量重新赋值时才会改变;

(4)变量和变量之间是相互独立的,修改一个变量不会影响另一个变量

python中的数据类型: 不可变(Number/String/Tuple) 和 可变(list/dict/set),不可变值得是不允许变量的值发生变化,如果改变变量的值,相当于新建了一个对象,而对于相同值的对象,在内存中只有一个对象。

如果改变数字数据类型的值,意味着是一个新的对象,将会重新分配内存空间

判断是否引用的是同一个对象: x is y,类似于id(x)===id(y)

数据类型

  • 整数、浮点数(1.23x10^9: 1.23e9)

  • 字符串

    1
    2
    3
    4
    'abc', "xyz"         >> abc xyz
    'I\'m\"OK\"!' >> I'm OK!
    r'\\\t\\' >> '\\\t\\' # 原始字符串r
    r'''hello,\nworld''' >> 'hello,\\nworld'

  • 布尔值

    1
    2
    3
    and: ture and flase  >> false
    or: false or true >> true
    not: not false >> true

变量

变量名必须是大小写英文、数字和_的组合,且不能用数字开头, Python支持多种数据类型,在计算机内部,可以把任何数据都看成一个“对象”,而变量就是在程序中用来指向这些数据对象的,对变量赋值就是把数据和变量给关联起来.

1
2
3
4
5
6
7
# -*- coding: utf-8 -*-
a = 'ABC' # 内存中创建'ABC'字符串
b = a # 内存创建变量b指向'ABC'
a = 'XYZ' # 创建'XYZ', 将a指向此字符串
print(b)

>> ABC

字符串和编码

Python 3版本中,字符串是以Unicode编码

1
2
3
4
5
6
7
8
9
10
11
ord('中')  >> 20013
chr(25991) >> '文'

'中文'.encode('utf-8')
>> b'\xe4\xb8\xad\xe6\x96\x87'

b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')
>> '中'

len(b'ABC') >> 3 # 字节
len('中文'.encode('utf-8')) >> 6

格式化输出(%)

  • %s %d %?

    1
    2
    3
    'Hello, %s' % 'world'	    >> 'Hello, world'
    print('%2d-%02d' % (3, 1)) >> 补空格3-01
    print('%.2f' % 3.1415926) >> 3.14

  • format()

    1
    'Hello, {0}, 成绩提升了{1:.1f}%'.format('小明', 17.125)  >> 'Hello, 小明, 成绩提升了17.1%' 

  • 格式化字符串

    • 格式化字符串,可以通过在字符串前添加一个f来创建一个格式化字符串
    • 在格式化字符串中可以直接嵌入变量
      1
      c = f'hello {a} {b}' \ print(f'a = {a}')

list tuple dict set

list[]

Python内置的数据类型列表:list是一种有序的集合,可以随时添加删除其中的元素

方法 说明
list.append() 追加元素到末尾
list.insert() 插入到指定位置
list.pop()方法 删除指定位置元素
list.len() 列表元素个数
1
2
3
4
5
6
7
8
9
10
11
classmates = ['Michael', 'Bob', 'Tracy']  >> ['Michael', 'Bob', 'Tracy']
len(classmates) >> 3
classmates[-1] >> 'Tracy'
classmates[-2] >> 'Bob'
classmates.append('Adam') >> ['Michael', 'Bob', 'Tracy', 'Adam']
classmates.insert(1, 'Jack') >> ['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']
classmates.pop(3) >> 'Tracy' -->['Michael', 'Jack', 'Bob', 'Adam']
classmates[1] = 'Sarah' >> ['Michael', 'Sarah', 'Tracy']

L = ['Apple', 123, True]
s = ['python', 'java', ['asp', 'php'], 'scheme']

tuple()

Python内置的数据类型有序列表叫元组:tuple,tuple和list非常类似,但是tuple一旦初始化就不能修改

1
2
3
4
classmates = ('Michael', 'Bob', 'Tracy')
t = ('a', 'b', ['X', 'Y'])
>> t[2][0] = 'X'
>> t[2][1] = 'Y'

dict

字典的可以是任意的不可变对象(int, str, bool, tuple…), 不能重复;字典的值可以是任何对象
{key1:value1,key2:value2,…}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
d = dict(name='Li',age='1',gender='boy')
d = dict([('name','Li'),('age','1')])
d = {'name': 'Li', 'age': 1, 'gender': 'boy'}

d['name'] >> Li
d['name'] = "Xing" # 修改
d.get('name', default) >> Li # key存在返回对应值,不存在返回默认值
d.pop('name') >> 删除name对应的值

for k in d.keys(): # keys() 返回序列,保存由字典所有键
print(k,d[k])

>> name Li
age 1
gender by

for v in d.values(): # values() 返回序列,保存由字典所有值
print(v)

for k,v in d.items(): # items() dict_item([('name','Li'), ('age', '1'), ('gender', 'boy')])
print(k , '=' , v)

>> name = Li
age = 18
gender = boy

set

集合中只能存储不可变对象,不重复且无序; 将字典转为集合只包含字典中键
对于不变对象来说,调用对象自身的任意方法,也不会改变该对象自身的内容。相反,这些方法会创建新的对象并返回,这样,就保证了不可变对象本身永远是不可变的

1
2
3
4
s = {'a', 'b', '1,' '2', '3'}  >> {'a', 'b', 1, 2, 3}
s = set([1, 2, 3, 1, 4]) >> {1, 2, 3, 4}
s.add(5)
s.remove(4)

条件判断&&循环(注意缩进)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 判断水仙花数(n>=3)
i = 100
while i < 1000:
bai = i // 100
# shi = (i -a * 100) // 10
shi = i // 10 % 10
ge = i % 10
if bai**3 + shi**3 + ge**3 == i:
print(i)
i += 1
----------------------------------------
# 判断质数(只能被1和它自身整除)
from time import *
begin = time()
num = int(input('输入大于1的整数:'))
i = 2
while i <= num: # 取出 2-num 所有数
flag = True #
j = 2
while j <= i ** 0.5:
if i % j == 0: # num不是质数
flag = False
break
j += 1
if flag:
# pass
print(i)
i += 1
end = time()
print("use time=",end - begin, '秒')
----------------------------------------------
# 99乘法表(嵌套)
i = 0
while i < 9:
i += 1 # 外层高度
while j < i: # 内层宽度
j += 1
print(f"{j}*{i}={i*j} ", end="")
print()
----------------------------------------------
# break && continue(对就近循环起作用)
i = 0
while i < 5:
i += 1
if i == 2:
break # 结束整个循环
continue # 结束当次循环
print(i)
i += 1
else:
print('循环结束')
---------------------------------------------
names = ['Michael', 'Bob', 'Tracy']
for name in names:
print(name)

迭代器:iter和生成器:yield

迭代器是访问集合元素的一种方式,是可以记住遍历的位置的对象,从集合第一个元素开始到所有元素被访问完结束,只能往前不会后退;基本方法iter()和next(),字符串、列表和元组均可用于创建迭代器

生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器,调用一个生成器函数,返回的是一个迭代器对象,在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import sys
def fibonaci(n,w=0): # 生成器函数:斐波那契
a, b, counter = 0, 1, 0
while True:
if(counter >n):
return
yield a
a, b = b, a + b
print('%d,%d' % (a,b))
counter +=1

f = fibonaci(3,0) # f 是一个迭代器,由生成器返回生成
while True:
try:
print(next(f), enf=" ")
except:
sys.exit()
------------
Output:
0 1,1
1 1,2
1 2,3
2 3,5

函数

概念

  • 函数是一个对象,在内存中专门用来存储数据的一块区域;如果形参执行的是一个对象,当通过形参去改对象时,会影响到所有指向该对象的变量;print(fn),fn是函数对象,实际是打印函数对象;而print(fn()),则是在打印fn()函数的返回值
  • 定义:
    1
    2
    def functionName(argu1, argu2, ...):
    code block

函数的参数:

  • 位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n

    1
    2
    3
    4
    5
    6
    def power(x,n):
    s = 1
    while n > 0:
    n = n -1
    s = s * x
    return s

  • 默认参数,必须指向不变对象

    1
    2
    3
    4
    5
    def add_end(L=None):
    if L is None:
    L = []
    L.append('END')
    return L

  • 可变参数,允许传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple

    1
    2
    3
    4
    5
    6
    7
    8
    def calc(*numbers):	# *nums表示把nums这个list的所有元素作为可变参数传进去
    sum = 0
    for n in numbers:
    sum = sum + n * n
    return sum
    >>> nums = [1, 2, 3]
    >>> calc(*nums)
    14

  • 关键字参数,允许传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict

    1
    2
    3
    4
    5
    def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)

    >>> person('Bob', 35, city='Beijing')
    name: Bob age: 35 other: {'city': 'Beijing'}

递归:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def factorial(n):
'''
求任意数的阶乘
参数:
n: 要求阶乘的数字
'''
if n == 1:
return 1
return n * factorial(n-1)
------------------------------
def huiWen(s):
'''
判断是否为回文字符串
参数:
s:要检查的字符串
'''
if len(s) == 2:
return False
elif s[0] != s[-1]:
return False
return huiWen(s[1:-1])

filter、匿名函数: lambda 与 map

  • filter(function,iterable): 可以从序列中过滤出符合条件的元素,保存到一个新的序列对象中,

    1
    2
    a = filter(lambda x: x % 2 == 0, range(10))
    >>> <filter object at 0x0000027939040390>

  • lambda 参数列表 : 返回值:

    1
    filter(lambda i:i>5,l)

  • map(function, iterable, ...): 可以对可迭代对象中的所有元素做指定操作,然后将其添加到一个新的对象中返回,

    1
    2
    map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10]) 
    >>> <map object at 0x0000027939040CF8>

闭包:函数嵌套 && 将内部函数作为返回值返回 && 内部函数必须使用到外部函数的变量

1
2
3
4
5
6
7
8
def makeAverager():
nums = []
def averager(n):
nums.append(n)
return sum(nums)/len(nums)
return averager

averager = makeAverager()

装饰器: 在不改变函数代码的情况下,扩展函数功能

1
2
3
4
5
6
7
8
9
10
11
12
13
def log(old):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper

@log # now = log(now)
def now():
print('2015-3-25')

>>> now()
call now():
2015-3-25

面向对象编程

基础

  • 类:对对象的抽象,是创建对象的模板;属性&&方法

  • 对象:则是由类创建的一个实例,而变量是指向对象的内容,如:a='abc',经常说的对象a的内容是’abc’,其实是指,a本身是一个变量,它指向的对象的内容才是’abc’

  • 定义类: p1 = Person('an')执行流程

    • (1)创建一个变量;
    • (2)在内存中创建新对象;
    • (3)__init__(self)方法执行,init在对象创建以后执行,用来初始化新创建的对象
    • (4)将对象的id赋值给变量
    • (5)self指的是类实例对象本身(注意:不是类本身)
    • self参考
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
       class Person:
      def __init__(self, name): # 在对象初始化时执行
      self.name = name # self为调用该属性/方法实例对象自身
      # self.__name = name # 隐藏属性 __name ==> _Person__name
      def sayHello(self):
      print('我是:%s' %self.name)
      def get_name(self):
      # print('读取属性')
      return self.name
      def set_name(self, name):
      # print('设置属性')
      return self.name = name

      p1 = Person('an')

特征:

  • 封装:隐藏对象中一些不希望被外部所访问到的属性或方法,确保对象中的数据安全

    • getter 获取对象中的指定属性(get_属性名)
    • setter 用来设置对象的指定属性(set_属性名)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      class Person:
      def __init__(self,name):
      self._name = name
      def get_name(self):
      return self._name

      def set_name(self , name):
      self._name = name

      p = Person('孙悟空')
      print(p._name)
  • 继承:实现子类的属性和方法的功能扩展,保证了对象的可扩展性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     class Animal:
    def run(self):
    print('动物会跑~~~')
    def sleep(self):
    print('动物睡觉~~~')
    @property
    def name(self):
    return self._name
    @name.setter
    def name(self,name):
    self._name = name

    class Dog(Animal):
    def __init__(self,name,age):
    # 调用父类的__init__来初始化父类中定义的属性
    # super() 可以用来获取当前类的父类,
    # 并且通过super()返回对象调用父类方法时,不需要传递self
    super().__init__(name)
    self._age = age
    def bark(self):
    print('汪汪汪~~~')
    def run(self):
    print('狗跑~~~~')
    @property
    def age(self):
    return self._age
    @age.setter
    def age(self,age):
    self._age = name

    d = Dog('旺财',18)
    print(d.name)
    print(d.age)

  • 多态:一个对象可以以不同的形态去呈现,保证了程序的灵活性

模块(python文件) 包(文件)

  • 导入模块:
    1
    2
    import 模块名 
    import 模块名 as 模块别名
  • 访问模块变量:模块名.变量名
  • 导入模块部分内容:
    1
    from 模块名 import 变量 as 别名

异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
print('异常出现前')
l = []
try:
print(10/0)
except NameError:
# 如果except后不跟任何的内容,则此时它会捕获到所有的异常
# 如果在except后跟着一个异常的类型,那么此时它只会捕获该类型的异常
print('出现 NameError 异常')
except ZeroDivisionError:
print('出现 ZeroDivisionError 异常')
except IndexError:
print('出现 IndexError 异常')

# Exception 是所有异常类的父类,所以如果except后跟的是Exception,他也会捕获到所有的异常
# 可以在异常类后边跟着一个 as xx 此时xx就是异常对象
except Exception as e :
print('未知异常',e,type(e))
finally :
print('无论是否出现异常,该子句都会执行')

print('异常出现后')
----------------------------------------------------------------------------------
# 自定义异常类,创建一个类继承Exception
class MyError(Exception):
pass

def add(a,b):
# 如果a和b中有负数,就向调用处抛出异常
if a < 0 or b < 0:
# raise用于向外部抛出异常,后边可以跟一个异常类,或异常类的实例
# raise Exception
# 抛出异常的目的
# raise Exception('两个参数中不能有负数!')
raise MyError('自定义的异常')

# 也可以通过if else来代替异常的处理
# return None
r = a + b
return r

print(add(-123,456))

文件

文件打开 –>操作文件(读/写) –>关闭文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
file_name = 'demo.txt'
file_obj = open(file_name)
content = file_obj.read()
file_obj.close()

# with ... as 语句
# with open(file_name) as file_obj :
# 在with语句中可以直接使用file_obj来做文件操作
# 此时这个文件只能在with中使用,一旦with结束则文件会自动close()
# print(file_obj.read())

file_name = 'demo.txt'
try:
with open(file_name,encoding='utf-8') as file_obj:
file_content = ''
chunk = 100
while True:
content = file_obj.read(chunk)
if not content:
break
# print(content,end='')
file_content += content

except FileNotFoundError :
print(f'{file_name} 这个文件不存在!')
print(file_content)

Py速成教程

目标:从”能看懂”到”能写出来”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ==========================================
# 10行代码
# ==========================================
"""
1. nums = list(map(int, input().split()))
2. from collections import Counter, deque, defaultdict
3. freq = Counter(s)
4. sorted(items, key=lambda x: (-x[1], x[0]))
5. ' '.join(map(str, result))
6. dq = deque(); dq.append(x); dq.popleft()
7. visited = set(); visited.add((r,c))
8. directions = [(-1,0),(1,0),(0,-1),(0,1)]
9. dp = [0] * (n+1)
10. float('inf') # 无穷大初始值
"""

第一章:输入输出(必须熟练,格式错误=0分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# --- 1.1 读一个整数 ---
n = int(input())

# --- 1.2 读一行整数(最常用)---
nums = list(map(int, input().split()))
# 输入:1 2 3 4 5
# 结果:[1, 2, 3, 4, 5]

# --- 1.3 读两个整数 ---
a, b = map(int, input().split())
# 输入:3 5
# 结果:a=3, b=5

# --- 1.4 读一个字符串 ---
s = input().strip() # strip()去掉首尾空格和换行

# --- 1.5 读多行(读n行)---
n = int(input())
lines = []
for _ in range(n):
lines.append(input().strip())

# --- 1.6 读到EOF(不知道有几行时)---
import sys
data = sys.stdin.read().splitlines()
# data是一个列表,每个元素是一行字符串

# --- 1.7 输出 ---
print(42) # 输出整数
print("hello") # 输出字符串
print(1, 2, 3) # 输出多个值,默认空格分隔
print(1, 2, 3, sep=',')# 指定分隔符,输出:1,2,3

# 输出列表(空格分隔)— 最常用
result = [1, 2, 3]
print(' '.join(map(str, result))) # 输出:1 2 3

# 输出列表(换行分隔)
for x in result:
print(x)

第二章:字符串操作(必考)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
s = "Hello World"

# --- 2.1 基本操作 ---
s.lower() # 转小写:"hello world"
s.upper() # 转大写:"HELLO WORLD"
s.strip() # 去首尾空格
s.split() # 按空格分割:['Hello', 'World']
s.split(',') # 按逗号分割
s.replace('l', 'L') # 替换:'HeLLo WorLd'
len(s) # 长度:11

# --- 2.2 字符串反转 ---
s[::-1] # 'dlroW olleH'

# --- 2.3 判断 ---
s.isalpha() # 是否全是字母
s.isdigit() # 是否全是数字
s.isalnum() # 是否是字母或数字
'Hello' in s # 是否包含子串:True

# --- 2.4 遍历字符串 ---
for c in s:
print(c)

# --- 2.5 字符和ASCII互转 ---
ord('A') # 字母转ASCII:65
chr(65) # ASCII转字母:'A'
ord('a') - ord('A') # = 32,大小写差值

# --- 2.6 统计字符频率 ---
from collections import Counter
freq = Counter(s.lower())
# Counter({'l': 3, 'o': 2, ...})
freq['l'] # 取某个字符的频率:3
freq.most_common(3) # 出现最多的3个:[('l',3),('o',2),...]

# --- 2.7 字符串拼接 ---
words = ['hello', 'world']
' '.join(words) # 'hello world'
''.join(words) # 'helloworld'

# --- 2.8 字符串切片 ---
s = "abcdef"
s[0] # 'a'(第一个)
s[-1] # 'f'(最后一个)
s[1:4] # 'bcd'(下标1到3)
s[:3] # 'abc'(前3个)
s[3:] # 'def'(第3个到结尾)
s[::2] # 'ace'(每隔一个取一个)
s[::-1] # 'fedcba'(反转)

第三章:列表操作(最常用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
nums = [3, 1, 4, 1, 5, 9, 2, 6]

# --- 3.1 基本操作 ---
nums.append(7) # 末尾添加:[3,1,4,1,5,9,2,6,7]
nums.insert(0, 0) # 指定位置插入
nums.pop() # 删除末尾
nums.pop(0) # 删除指定位置
nums.remove(1) # 删除第一个值为1的元素
len(nums) # 长度
nums.count(1) # 统计1出现次数
nums.index(5) # 找5的下标

# --- 3.2 排序 ---
nums.sort() # 升序排序(原地修改)
nums.sort(reverse=True) # 降序排序
sorted(nums) # 返回新列表,不修改原列表

# 自定义排序(按绝对值)
nums.sort(key=lambda x: abs(x))

# 多条件排序(先按第一个元素升序,再按第二个元素降序)
pairs = [(1, 3), (2, 1), (1, 2)]
pairs.sort(key=lambda x: (x[0], -x[1]))

# --- 3.3 列表推导式(精简写法)---
squares = [x**2 for x in range(10)] # [0,1,4,9,...]
evens = [x for x in nums if x % 2 == 0] # 偶数列表
matrix = [[0]*3 for _ in range(3)] # 3x3的零矩阵

# --- 3.4 切片 ---
nums[1:4] # 下标1到3的元素
nums[::-1] # 反转列表
nums[:3] # 前3个

# --- 3.5 常用函数 ---
sum(nums) # 求和
max(nums) # 最大值
min(nums) # 最小值
sum(nums)/len(nums) # 平均值

第四章:字典和集合(高频)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# --- 4.1 字典基本操作 ---
d = {'a': 1, 'b': 2, 'c': 3}
d['a'] # 取值:1
d['d'] = 4 # 添加
d.get('e', 0) # 取值,不存在返回默认值0
d.keys() # 所有键
d.values() # 所有值
d.items() # 所有键值对
'a' in d # 判断键是否存在:True
del d['a'] # 删除

# 遍历字典
for key, val in d.items():
print(key, val)

# --- 4.2 defaultdict(避免KeyError)---
from collections import defaultdict

# 值默认是int(初始为0)
count = defaultdict(int)
count['a'] += 1 # 不用判断'a'是否存在

# 值默认是list(初始为[])
groups = defaultdict(list)
groups['odd'].append(1)

# --- 4.3 集合 ---
s = {1, 2, 3, 4}
s.add(5) # 添加
s.remove(1) # 删除(不存在会报错)
s.discard(10) # 删除(不存在不报错)
3 in s # 判断是否存在:True

# 集合运算
a = {1, 2, 3}
b = {2, 3, 4}
a & b # 交集:{2, 3}
a | b # 并集:{1, 2, 3, 4}
a - b # 差集:{1}

# 去重(列表转集合再转回来)
nums = [1, 2, 2, 3, 3, 3]
unique = list(set(nums)) # [1, 2, 3](顺序可能变)

第五章:双端队列(BFS必用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from collections import deque

dq = deque()
dq.append(1) # 右边添加
dq.appendleft(0) # 左边添加
dq.pop() # 右边取出
dq.popleft() # 左边取出(比list.pop(0)快得多)
len(dq) # 长度
dq[0] # 查看最左边(不取出)
dq[-1] # 查看最右边(不取出)

# BFS标准模板
def bfs(grid, start, end):
rows, cols = len(grid), len(grid[0])
queue = deque([(start[0], start[1], 0)]) # (行, 列, 步数)
visited = set()
visited.add(start)

directions = [(-1,0),(1,0),(0,-1),(0,1)] # 上下左右

while queue:
r, c, steps = queue.popleft()

if (r, c) == end:
return steps

for dr, dc in directions:
nr, nc = r+dr, c+dc
if (0 <= nr < rows and
0 <= nc < cols and
(nr, nc) not in visited and
grid[nr][nc] != '#'):
visited.add((nr, nc))
queue.append((nr, nc, steps+1))

return -1 # 不可达

第六章:排序技巧(面试高频)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# --- 6.1 基本排序 ---
nums = [3, 1, 4, 1, 5]
sorted(nums) # 升序:[1,1,3,4,5]
sorted(nums, reverse=True) # 降序:[5,4,3,1,1]

# --- 6.2 自定义排序 key ---
words = ['banana', 'apple', 'cherry', 'date']
sorted(words, key=len) # 按长度:['date','apple','banana','cherry']
sorted(words, key=lambda x: x[-1]) # 按最后一个字母

# --- 6.3 多条件排序 ---
students = [('Alice', 85), ('Bob', 92), ('Charlie', 85)]
# 先按分数降序,分数相同按名字升序
students.sort(key=lambda x: (-x[1], x[0]))
# [('Bob',92), ('Alice',85), ('Charlie',85)]

# --- 6.4 对字典按值排序 ---
d = {'a': 3, 'b': 1, 'c': 2}
sorted(d.items(), key=lambda x: x[1]) # 按值升序
sorted(d.items(), key=lambda x: -x[1]) # 按值降序
sorted(d.items(), key=lambda x: (-x[1], x[0])) # 值降序,值相同键升序

七章:递归和DFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# --- 7.1 递归基本结构 ---
def recursion(参数):
# 终止条件(必须有,否则死循环)
if 终止条件:
return 结果

# 递归调用
return recursion(更小的参数)

# --- 7.2 DFS模板(统计连通块)---
def dfs(grid, r, c, visited):
rows, cols = len(grid), len(grid[0])

# 终止条件
if (r < 0 or r >= rows or
c < 0 or c >= cols or
visited[r][c] or
grid[r][c] == '0'):
return

visited[r][c] = True

# 往四个方向递归
dfs(grid, r+1, c, visited)
dfs(grid, r-1, c, visited)
dfs(grid, r, c+1, visited)
dfs(grid, r, c-1, visited)

第八章:动态规划(200分大题)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# --- 8.1 最大子数组和(经典)---
# 输入:-2 1 -3 4 -1 2 1 -5 4
# 输出:6(子数组[4,-1,2,1])

def max_subarray(nums):
max_sum = nums[0]
curr = nums[0]
for n in nums[1:]:
curr = max(n, curr + n) # 要么接着前面,要么重新开始
max_sum = max(max_sum, curr)
return max_sum

# --- 8.2 01背包(经典)---
# n个物品,背包容量W,每个物品只能放一次
# 求能放入背包的最大价值

def knapsack(W, weights, values):
dp = [0] * (W + 1)
for i in range(len(weights)):
# 逆序遍历,防止同一个物品被放多次
for w in range(W, weights[i]-1, -1):
dp[w] = max(dp[w], dp[w-weights[i]] + values[i])
return dp[W]

# --- 8.3 最长公共子序列(LCS)---
def lcs(s1, s2):
m, n = len(s1), len(s2)
dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(1, m+1):
for j in range(1, n+1):
if s1[i-1] == s2[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
return dp[m][n]

第九章:常用技巧速查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# --- 9.1 进制转换 ---
bin(10) # 十进制转二进制:'0b1010'
oct(10) # 十进制转八进制:'0o12'
hex(10) # 十进制转十六进制:'0xa'
int('1010', 2) # 二进制转十进制:10
int('ff', 16) # 十六进制转十进制:255

# --- 9.2 最大公约数和最小公倍数 ---
import math
math.gcd(12, 8) # 最大公约数:4
12 * 8 // math.gcd(12, 8) # 最小公倍数:24

# --- 9.3 无穷大 ---
float('inf') # 正无穷
float('-inf') # 负无穷
# 用途:初始化最小值/最大值
min_val = float('inf')
max_val = float('-inf')

# --- 9.4 enumerate(带下标遍历)---
for i, val in enumerate(['a', 'b', 'c']):
print(i, val)
# 0 a
# 1 b
# 2 c

# --- 9.5 zip(同时遍历多个列表)---
keys = ['a', 'b', 'c']
values = [1, 2, 3]
for k, v in zip(keys, values):
print(k, v)

# --- 9.6 any 和 all ---
any([False, True, False]) # 有一个True就返回True
all([True, True, True]) # 全部True才返回True

# --- 9.7 堆(优先队列)---
import heapq

# 最小堆(默认)
heap = []
heapq.heappush(heap, 3)
heapq.heappush(heap, 1)
heapq.heappush(heap, 2)
heapq.heappop(heap) # 取出最小值:1

# 最大堆(取负数模拟)
heapq.heappush(heap, -3)
-heapq.heappop(heap) # 取出最大值:3

# --- 9.8 二分查找 ---
import bisect
nums = [1, 3, 5, 7, 9]
bisect.bisect_left(nums, 5) # 找插入位置(左):2
bisect.bisect_right(nums, 5) # 找插入位置(右):3

第十章:完整例题(综合运用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 题目:给定字符串数组,按以下规则排序后输出
# 1. 按字符串长度升序
# 2. 长度相同按字典序升序
# 3. 输出排序后的结果

def solve():
n = int(input())
words = []
for _ in range(n):
words.append(input().strip())

# 多条件排序:先按长度,再按字典序
words.sort(key=lambda x: (len(x), x))

for w in words:
print(w)

# solve() # 取消注释运行

python
https://anyue967.github.io/posts/a4d4b8b8.html
作者
anyu967
发布于
2019年9月10日
许可协议