目录
1672. 最富有客户的资产总量
tips: sum函数可以直接用~
class Solution:
def maximumWealth(self, accounts: List[List[int]]) -> int:
maxSum=0 #记录下最大值
for a in accounts: #遍历每个客户
if sum(a)>maxSum: #当前客户资产总和大于记录的最大值
maxSum=sum(a)
return maxSum
1920. 基于排列构建数组
class Solution:
def buildArray(self, nums: List[int]) -> List[int]:
return [nums[i] for i in nums] # 这一句话解决问题
1. 两数之和
tips: 通过这个题可以 get 到字典的妙用,python中字典就是一种哈希结构,编程中用起来时间复杂度也比较低。
形象解释:(这个题就像是找老伴儿哈哈哈~~~)
列表中的每个人心里都知道自己的老伴儿应该是谁(如果target=8,当前这个数是2,它知道自己需要找到的是6)。
所以当遍历到这个人身上的时候,他就会去查一下字典,看看老伴儿在字典里吗,如果在,那这道题就结束了;
如果不在,那他就先把自己放到字典中(他的值是字典中独一无二的key),乖乖等着他的老伴儿来找他。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hashtable=dict() # 创建一个字典
for i,num in enumerate(nums): # 遍历数组nums,每当遇到一个数num时
if target-num in hashtable: # 如果老伴儿(target-num)就在字典中
return [hashtable[target-num],i] # 问题结束,返回他俩各自的位置
else: # 老伴儿不在字典中
hashtable[num]=i # 那就把自己的信息以key(本身值大小)、value(下标位置)的形式存到字典中,等着他的老伴儿来找他
##### 二刷时的写法 #######
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# 字典能很好的直接访问到,哪个元素在,哪个元素不在,而且还能帮你存放一个附加的value值
map_dict = {} # 数值:下表
for i, num in enumerate(nums):
if target-num in map_dict:
return [i, map_dict[target-num]]
else:
map_dict[num] = i
9. 回文数
class Solution:
def isPalindrome(self, x: int) -> bool:
x_str=str(x) #把x转化成字符串
x_ver_str=''.join(reversed(x_str)) #用''.join(reversed(str))这个方式求逆序字符串
if x_str==x_ver_str:
return True
else:
return False
13. 罗马数字转整数
用两个字符组合代表数字的就那6个特例('IV,‘IX’,‘XL’,‘XC’,‘CD’,‘CM’),字符串中的每个字符要么就是跟后边字符形成特例,不然的话那就是单独自己代表一个数字。(所以只需要走一遍字符串,看看每个字符跟后边是否能组合,不能组合就单独累加)
class Solution:
def romanToInt(self, s: str) -> int:
mapDict={
'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000,
'IV':4,'IX':9,'XL':40,'XC':90,'CD':400,'CM':900
}
countSum=0
i=0
while i<=len(s)-1: # 直到最后一位
if i+1<=len(s)-1: # 如果后边有数
# 取出这两个字母,看看是不是特例里中的
if s[i:i+2] not in mapDict.keys(): # 两位组合的不在,那只能单独成数
countSum+=mapDict[s[i]] #直接由s[i]这个字符在字典中定位到其值
i+=1 #指针后移一位
else:
countSum+=mapDict[s[i:i+2]] #s[i:i+2]两个字符形成的字符串也是在字典中直接定位到其值
i+=2 #指针后移两位
else: # 后边没数,那它就是最后一位了
countSum+=mapDict[s[i]] #直接加
i+=1 #指针后移一位
return countSum
14. 最长公共前缀
方法1:可以拓展成一种思想,要找出一堆东西中的共同基础部分,我们就按照规则让它们依次排队,排到最后会越来越严格,如果留到最后的那个都能和第一个有相同之处,那中间的肯定也没啥问题~
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
if len(strs)==0: #空字符数组
return ""
minStr=min(strs) #找到排序之后最小的字符串
maxStr=max(strs) #找到排序之后最大的字符串
## 遍历最小的字符串,依次检查里边每个字符是否在最大的字符串中
for i,v in enumerate(minStr):
## 又小又短的会默认排在前边,所以不用担心maxStr[i]超出索引下标的问题
if v!=maxStr[i]: #找到首个不一样的字符位置
return maxStr[:i] #直接返回前边这些相同的字符串
## 如果一直没有返回,那最大的字符串就已经把最小的全包含了,直接返回最小的
return minStr
方法2:通过这个题正好学习一下zip的用法
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
if len(strs)==0: #空字符数组
return ""
strSum=""
for i in zip(*strs): #每个i是一个元组(),大家把第几位都放到一起,例如('f','f','f')
if len(set(i))==1: #转化成集合(自动去重),长度不为1那就是有不一样的
strSum+=i[0]
else:
break
return strSum
20. 有效的括号
还记得 1.两数之和 那个题我们用到了老伴儿思想嘛!这个题我们继续沿用情侣的思想,oh no这就是爱情的力量嘛?!(单身狗表示不懂了)
【用 ‘[’ ‘(’ ‘{’ 表示女生,等着男生 ‘]’ ‘)’ ‘}’ 来带走她,切记男生只去牵离他最近的那个女生 , 例如字符串 “( [ ) ]” ,前两个女生都在等着被牵手,第三个男生 ‘)’ 只尝试去牵第二个女生 ‘[’ ,发现不配对,就直接牵手失败喽~ 】
class Solution:
def isValid(self, s: str) -> bool:
#键:男方,值:要找的女方
partnerMap_Dict={
')':'(',']':'[','}':'{'
}
waitList=[] #存放等待被牵的女方
#遍历字符串
for i in s:
if i not in partnerMap_Dict.keys(): #这是个女方,等着被牵
waitList.append(i) #进去等着吧
elif (len(waitList)!=0 and waitList[-1]!=partnerMap_Dict[i]) or len(waitList)==0: #这是个男方,有女方在等,但最近的那个女方和他并不配对;或者里边压根没人
return False
elif len(waitList)!=0 and waitList[-1]==partnerMap_Dict[i]: #这是个男方,且最后那个女生在等他,这一对儿就成了,把最近那个女方牵走吧
waitList.pop()
if len(waitList)==0: #最后wait列表空了,全部配对成功
return True
else:
return False
LCP 33. 蓄水
浅试一下简单题中通过率最低的题目,结果直接让我怀疑人生~~
虽然我的解题逻辑有误,但是通过做这道题让我学会了python中很多的骚操作,也算是有很大的收获啦~~
收获如下:
【
1. 如何删除列表中值为0的元素
2. np.delete() 执行完后返回的是 ndarray,不是 list 了,转化回列表用 .tolist()
3. 对浮点数 x 向上取整用 math.ceil (x) ,记得要 import math
4. 找出列表 a 中最小值 b 所在的位置,用 a.index(b) 来获取
5. np.sum返回的是 float 类型,千万要注意这个坑
6. 遍历列表 a 时想跳过某个位置 i , 可以用 index =
list(range(0,i))+list(range(i+1,len(a))) 来重新组建下标索引,这样就避免了遍历时一直要 if 判断是不是我们不想要的那个位置
】
下边的错误代码也放上来做个纪念,目的是大家可以看一下上边的收获代码都是怎么实现的【正解在后边】:
import numpy as np
import math
class Solution:
def storeWater(self, bucket: List[int], vat: List[int]) -> int:
operationNums=0 #操作总次数
## 设置一个列表,存放每个水缸需要倒水的次数
## 当我们升级了水桶时,需要倒水的次数肯定也会随之变化,所以这个列表也是在动态改变的
needToPushWaterNums=[0]*len(vat)
# 0.对于水缸压根不要水的,我们就直接删掉就好啦
flag=0
for i in range(len(vat)-1,-1,-1):
if vat[i]==0: #这个水缸压根不需要水
#直接删掉这组就可以了
vat=np.delete(vat,i)
bucket=np.delete(bucket,i)
needToPushWaterNums=np.delete(needToPushWaterNums,i)
flag=1
## 注意:np.delete()执行完后返回的是ndarray,不是list了,这里需要转化一下
## 如果不转化的话,下边的.index就用不了了,运行会报错
if flag==1:
needToPushWaterNums=needToPushWaterNums.tolist()
if len(needToPushWaterNums)!=0: #如果还有水缸需要倒水
# 1.遍历每个水缸和对应的水桶,计算初始的需要倒水次数
for i in range(len(bucket)):
if bucket[i]==0:
needToPushWaterNums[i]=100000 #用100000代表一个很大的数
else:
needToPushWaterNums[i]=math.ceil(vat[i]/bucket[i])
# 2.找出倒水次数最少的那组,用G表示
minPushNums=min(needToPushWaterNums)
minIndex=needToPushWaterNums.index(minPushNums)
if minPushNums==100000: #特殊情况,所有的桶容量一开始都是0
operationNums+=int(np.sum(vat)) #这种情况下就是把所有的桶容量先升级起来
operationNums+=1 #最后再执行一次蓄水
return operationNums
else: #正常情况
operationNums+=minPushNums
# 3.对于其他那些组,以G的倒数次数为baseline,那看一下它们的桶至少变为多大才可以
otherIndex=list(range(0,minIndex))+list(range(minIndex+1,len(needToPushWaterNums)))
#### (这样遍历时就可以跳过某个位置,不需要在遍历时一直加上if来判断)
for oI in otherIndex:
bucketNeedSize=vat[oI]/minPushNums #水桶至少需要达到这么大
operationNums+=math.ceil(bucketNeedSize-bucket[oI]) #升级这个水桶需要的次数
return operationNums
正解: 参考b站视频
【我之前的想法是考虑不周全的,想法比较狭隘。我是用初始蓄水次数最少的那个水桶和水缸对儿来作为baseline,但其实这个最小的蓄水次数值并不一定是好的,可能我再加一次蓄水操作,效果就直接等同于三次升级水桶的操作】
import math
import numpy as np
class Solution:
def storeWater(self, bucket: List[int], vat: List[int]) -> int:
# 蓄水次数是一个没法一下就算出来最优值的变量,所以我们可以去遍历尝试它的值
# 对于设置的当前蓄水次数i,我们看一下每个水桶首先要升级多少次才能用这个蓄水次数i来灌满水缸
# 各个水桶的升级次数再加上蓄水次数i,那就是需要的操作数
# 对比设置的所有蓄水次数i中,操作数最少的那个,就是最优的
## 如果所有的水缸蓄水量都是0,那就不需要任何操作,直接返回0(不需要改动minOperationNumber的值)
if np.sum(vat)==0:
return 0
minOperationNumber=10005 # 存储最小的操作数值
## 遍历所有的蓄水次数值,1~10000
for storeWaterNumber in range(1,10001):
operationSum=storeWaterNumber #先累加上蓄水操作的次数
for i in range(len(bucket)): #对于每一个水桶水缸对儿,看一下这个水桶需要升级多少次
bucketSize=bucket[i]
vatSize=vat[i]
needBucketSize=math.ceil(vatSize/storeWaterNumber) #当蓄水次数一定时,水桶容量需要达到多大
updateBucketNumber=needBucketSize-bucketSize #需要升级的次数
if updateBucketNumber>0:
operationSum+=updateBucketNumber #再累加上每个水桶的升级次数
if operationSum<minOperationNumber: #更新minOperationNumber
minOperationNumber=operationSum
return minOperationNumber
70. 爬楼梯
当前台阶的答案和前两个台阶有关,弄个dp数组保存一下结果
class Solution:
def climbStairs(self, n: int) -> int:
# 方法1:设置dp数组,推荐这个
dp = [0,1,2]
for i in range(3, n+1):
dp.append(dp[i-1]+dp[i-2])
return dp[n]
# 方法2:省去dp数组,直接用两个变量来记录
# 不过这种占的内存反倒更高,可能是因为变量太多了
if n==1:
return 1
elif n==2:
return 2
else:
pre1, pre2 = 1, 2
cur = 0
for i in range(3, n+1):
cur = pre1 + pre2
# 更新pre1和pre2的值,为下个人做准备
pre1 = pre2
pre2 = cur
return cur
83. 删除排序链表中的重复元素
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
p = head
while p and p.next: #这里要确保一下p.next是存在的
#这里用到了p.next它的val值,那就一定要确保p.next是存在的,不然就会报错
if p.next.val==p.val:
p.next=p.next.next
else:
p=p.next
return head #注意这里返回的是head,不是p哈
141. 环形链表
设置快慢指针,一个每次走两步,一个每次走一步
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
fast = head
slow = head
# 快指针每次移动两步,慢指针每次移动一步
# 如果他俩能相遇,说明有环,返回true
while fast and fast.next: #while循环一直next走就行,
#如果是直链,while最终会退出去的,而且快慢指针绝对碰不上
fast = fast.next.next
slow = slow.next
if fast == slow:
return True
return False
704. 二分查找
解法一:基础的二分查找代码
class Solution:
def search(self, nums: List[int], target: int) -> int:
n=len(nums)
left,right=0,n-1
while left<=right: #要考虑清楚这里是小于等于哦
mid=int((left+right)/2)
if nums[mid]==target:
return mid
elif target>nums[mid]: #找右边
left=mid+1
else: #找左边
right=mid-1
return -1
解法二:利用python中列表自带的函数,直接返回索引位置
class Solution:
def search(self, nums: List[int], target: int) -> int:
if target in nums:
return nums.index(target)
else:
return -1
27. 移除元素
思路:数组前边都是弄好的数,以end来标记,每次有新数就挨着往后放
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
# 【关键】把要留下的数,全都放到数组的最前边
# 根据返回的数值,就去取数组的最前边这几个数
end=-1
for i in range(len(nums)): #遍历数组
if nums[i]!=val: #这个数是要留下的
nums[end+1]=nums[i]
end+=1 #把这个棋子插在它身上
return end+1 #数组长度的话是最后一个下标加1
977. 有序数组的平方
直接借助python自带的一些函数,“对列表求平方和”、“对列表排序”
# 时间:76ms
class Solution:
def pow2(self,arg): #类内定义的函数记得要加self哈
return arg**2
def sortedSquares(self, nums: List[int]) -> List[int]:
return sorted(list(map(self.pow2,nums))) #类中方法相互调用,self.方法名
# 时间:60ms
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
return sorted(list(map(lambda x:x*x, nums))) #使用lambda匿名函数也行
# 时间:68ms
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
return sorted([x**2 for x in nums]) #列表的推导式
203. 移除链表元素
- 需要注意和83.删除排序链表中的重复元素区分开。
- 这个题需要在链表最前边自己定义一个空head,因为链表第一个元素也是有可能要被删掉的,所以p要从前边的空head开始。
- 而83题链表第一个元素是不会被删除的,所以p从它开始是没有问题的。
- 链表的题目,如果某个节点存在要被删除的可能,此时一定确保要有个指针指向着它前边的元素。
- 返回的时候是剩余链表的第一个元素,所以是newHead.next哦。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
newHead = ListNode(0,head)
p = newHead #用p来进行遍历
while p and p.next:
if p.next.val == val: #下一个数是要被删掉的
p.next = p.next.next
else:
p = p.next
return newHead.next #返回链表第一个数的节点
206. 反转链表
虽说是双指针题目,其实是涉及到三个指针,其中有一个是临时指针temp
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
cur = head #用cur主指针来遍历,遍历到的这个元素是需要被调整next指向的
pre = None ## 当涉及到删除或调整指针时,都要有一个指向前一个节点的从指针
while cur: # 主指针一个一个节点遍历
# 1、先把下一个节点记录下来,不然一会调整next指向就找不到它了
temp = cur.next
# 2、next指针调方向【核心语句】
cur.next = pre
# 3、两个指针后移
pre = cur
cur = temp
return pre #最后返回的谁不要搞错了
面试题 02.07. 链表相交
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
# 这两个链表的公共尾部,在内存中的地址是一样的
# 因此我们不需要时刻盯着长度,当地址相等时自然就该停了
# 所以我们的目标是:
# 如何用双指针分别在这两个链表上做遍历,使得在某一个时刻上的这俩指针指向的地址相等
# 要有发散思维,只是局限地在一个链表身上遍历,是没有办法重合的,两个链表长度都不同
# 完全可以跳转到对方链表身上去做遍历
A, B = headA, headB
while A!=B: # 只要地址还不相同,两个指针就继续沿着设定的路线走
# A的路线
if A: # A链表长度还够
A = A.next # 继续沿A走
else: # A链表走完了
A = headB # 跳转到B身上
# B的路线
if B: # B
B = B.next
else:
B = headA
return A
242. 有效的字母异位词
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
ds,dt = {},{}
for i in s:
if i not in ds.keys():
ds[i] = 1
else:
ds[i] += 1
for j in t:
if j not in dt.keys():
dt[j] = 1
else:
dt[j] += 1
if ds==dt:
return True
else:
return False
349. 两个数组的交集
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
return list(set(nums1) & set(nums2))