每天都做两三道LeetCode算法题,以及进一步看了Imooc网上Python进阶的课程,结合所认知的和长时间的Java的使用,总结了一下新学到的知识、让人眼前一亮的程序写法和较java有区别的地方。
一:
注意时间复杂度和空间复杂度
一般我们更注重时间复杂度,常用空间换时间
比如二分法进行递归,时间复杂度一般是O(log n),k层for循环一般是O(n^k)等
二:
# l1是一个链表型,val是其属性,以下句子意义为如果l1不为空则取l1.val否则取0,节省代码空间,干净利落
x= l1.val if l1 else 0
# 三目运算符 条件为真时的结果 if 条件 else 条件为假时的结果
x = x if (x>y) else y # 取x,y中较大的数并赋给x
三:
# 正则表达式,可实现快速匹配指定字符
import re
re.search(r'^([+|-]?\d+)', " -14")
四:
# 被惊艳到了:判断是否为回文。不知道如何表达,虽然算法的时间空间复杂度差不多,但是这个太简美了
def isPalindrome(self, x: 'int') -> 'bool':
return str(x) == str(x)[::-1]
五:
# 类似数字转罗马数字这种问题,可用枚举涵盖所有情况采用定义枚举的方法,而不是多次if判断
m = [
['', 'M', 'MM', 'MMM'],
['', 'C', 'CC', 'CCC', 'DC', 'D', 'CD', 'CCD', 'CCCD', 'MC'],
['', 'X', 'XX', 'XXX', 'LX', 'L', 'XL', 'XXL', 'XXXL', 'CX'],
['', 'I', 'II', 'III', 'VI', 'V', 'IV', 'IIV', 'IIIV', 'XI']
]
# 对于罗马转数字这种问题,找其规律,从左到右,字符代表的值不小于右边则加,否则减
def romanToInt(self, s: 'str') -> 'int':
a = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
ans=0
for i in range(len(s)):
if i
else:
ans+=a[s[i]]
return ans
六:
# 对于一个不定长的输入,不要总是罗列枚举各个情况,适度使用if判断
# 比如nums是一个list,求其中和为0的三个数,不可重复
def threeSum(self, nums: 'List[int]') -> 'List[List[int]]':
for i in range(len(nums)):
if i == 0 or nums[i]>nums[i-1]:# 此行即避免重复计算或者第一次执行时为true,总之就是找公共部分少罗列
省略。。。
七:
# 排序之后双指针是一个好思想,比如排序后[0,1,2,3,4]求和为3的,从list[0]+list[4]开始,逐步减少
list=[0,1,2,3,4]
left,right = 0,4
while left < right:
if list[right] + list[left] > 3:
right-= 1
elif list[right] + list[left] < 3:
left += 1
else:return [list[left],list[rigth]]
return []
八:
# 列表解析,列表生成式,还可带条件过滤
list=[-1, 0, 1,1]
st = [x+2 for x in list] # st变成[1, 2, 3, 3]的列表
st = [x+2 for x in list if list[x]>0] # st变成[3, 3]的列表
九:
# is 和==的区别,is比较的内存地址,==比较的是内容
# java中String类型:==比较的是地址,equals比较内容,
十:
# 一个.py文件是一个模块,一个带__init.py__的文件夹是一个包,不同模块下函数可以重名,不同包下模块可以重名,同java
from math import pow,sin # 导入Math模块中某几个函数
from math import pow as pppp # 现在调用即使用pppp(2,3)即可,相当于起了别名
十一:
# lambda匿名函数可简化程序,但同时增加了理解成本和某些语句不可实现等劣势,用不用视情况而定
十二:
# 双下划线定义的属性不能被外部访问,但可以通过方法访问,相当于Java中Private
class person(object):
def __init__(self,name):
self.name = name
self.__job = 'student'
def getJob(self):
return self.__job
p=person('bob')
print(p.name) # 输出bob
print(p.__job) # error
print(p.getJob()) # 输出student
十三:
# 类属性属于类,不需要实例化就可访问,当然,实例化也可访问,且可动态修改添加等
class person(object):
address= 'earth'
...
print(person.address) # 无创建实例即可访问
p1 = person('bob')
print(p1.address) # 实例化后访问
person.address='china' # 可动态修改,再访问时已经改变值,也可添加
p1.address = 'beijing' #修改实例的类属性时,不会影响其他类属性,官方解释是“当实例属性和类属性重名时,实例属性优先级高”
十四:
# 父类与子类是is的关系,如果是子类,则也是父类,比如超类是人,继承类是学生,小明是学生,小明也是人
# 而has关系则是组合关系
# 继承时记得初始化,下一个例子有,记录下来,现在没使用到继承,没有概念,需要时百度
十五:
# 多态:这是动态语言(如Python)和静态语言(如java)最大的区别
# 如果子类和父类中都有同名的方法,调用时先调用子类的,如果没有,向上查找父类,直到找到为止
class person(object):
def __init__(self,name):
self.name = name
def whoAmI(self):
return "im a person"
class student(person):
def __init__(self,name,score):
super(student, self).__init__(name)
self.score = score
def whoAmI(self):
return "im a student"
p = person('tim')
s = student('bob',90)
print(p.whoAmI()) # 输出im a person
print(s.whoAmI()) # 输出im a student
2019/08/13修改:
动态语言不检查类型,这是最大的区别。java中同样是先调子类方法再调父类方法,直到找到为止。python比如def pri(x):print(x.val)只要x有val属性程序就是正确的,而java不是,必须限定检查类型。这篇文章详细例子:https://blog.csdn.net/u012762054/article/details/81980750
简单点说就是,python是无论什么class能用就行,java是类型不对传参错误
十六:
# map方法是可以写默认值的
words_dict[word] = words_dict.get(word, 0) + 1 # 在words_dict字典中是否有Key为word的条目,如果没有,默认值置0,再加+1,若有则加1
十七:
# python较java不同的是允许多重继承
# 除了isinstance()判断是否为某类型,还可以用Type(),还可用dir()获取所有属性
Type(123) #
十八:
'''特殊函数(又叫magic function):任何实例都有特殊方法以双下划线开始,双下划线结束,比如__str__(),输出为字符,用于len的__len__()方法,用于比较的__cmp__()方法,__int__()等。自定义一个类时没有这些方法,可自行写上,但记得定义时加下划线'''
s="abcd"
print(s) # 等价于print(s.__str__())
print()
十九:
# __call__()方法实例变成函数
# 一些概念,装饰器,动态增加函数功能
# 闭包