题9:用两个栈实现队列
队列是先进先出,栈是先进后出,两个栈实现队列的基本思想就是:数据从stack1进入,再将stack1中的数据倒到stack2中,那么从stack2中出来的数据顺序就和进入stack1中的数据顺序一样了,也就实现了队列。处理细节就是,有数据进入时,只管往stack1中添加,当需要取出数据时,只管从stack2中取,如果stack2为空,那么就把stack1中的元素倒到stack2中(妙喵喵~
王先生题解👉here
class CQueue:
def __init__(self):
self.instack = []
self.outstack = []
def appendTail(self, value: int) -> None:
self.instack.append(value)
def deleteHead(self) -> int:
if len(self.outstack)==0:
if len(self.instack)==0:
return -1
else:
while len(self.instack) !=0 :
self.outstack.append(self.instack.pop())
return self.outstack.pop()
else:
return self.outstack.pop()
题12:矩阵中的路径
我的错解👇,出错用例:[["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]] "SEE"
,错误原因是,s周围有两个e可选,但我的while if 导致每次都会先选择s上方的e,没法走到s下方的e,解决起来太麻烦了,放弃
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
n,m,find = len(board),len(board[0]),0
if n*m<len(word) or len(word)==0:
return False
if len(word)==1 and word[0] in board:
return True
visit = [[0]*m for _ in range(n)]
record = [0]*len(word)
word = word.upper()
for i in range(n):
for j in range(m):
if board[i][j].upper()==word[find]:
record[find]=(i,j)
visit[i][j]=1
a,b=i,j
find+=1
while find<len(word) and find>0:
#print(record)
if a>0 and board[a-1][b].upper()==word[find] and visit[a-1][b]==0:
record[find]=(a-1,b)
a,find=a-1,find+1
elif a<n-1 and board[a+1][b].upper()==word[find] and visit[a+1][b]==0:
record[find]=(a+1,b)
a,find=a+1,find+1
elif b>0 and board[a][b-1].upper()==word[find] and visit[a][b-1]==0:
record[find]=(a,b-1)
b,find=b-1,find+1
elif b<m-1 and board[a][b+1].upper()==word[find] and visit[a][b+1]==0:
record[find]=(a,b+1)
b,find=b+1,find+1
else:
visit[a][b]=0
find-=1
a,b=record[find]
if find == len(word):
return True
return False
王先生的做法👇,思路都是一样的:深度优先遍历,但他的写法就很简洁明了(妙喵喵
在函数里定义函数能省去很多传参的步骤,两个or用的实在是喵
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
n,m = len(board),len(board[0])
if n*m<len(word) or len(word)==0:
return False
def dfs(i:int,j:int,ind:int)->bool:
if ind>=len(word):
return True
if i<0 or j<0 or i>=n or j>=m or board[i][j]!=word[ind]:
return False
board[i][j]=''
if dfs(i-1,j,ind+1) or dfs(i+1,j,ind+1) or dfs(i,j-1,ind+1) or dfs(i,j+1,ind+1):
return True
board[i][j]=word[ind]
return False
for i in range(n):
for j in range(m):
if dfs(i,j,0):
return True
return False
题13:机器人的运动范围
和题12的思想是一致的,都是深度优先搜索,满足条件则res++,否则不操作
注意:函数嵌套时,想在子函数中引用父函数中的变量,需要在子函数里对所引用变量进行nonlocal
声明;
python里的除法不像C语言里的除法一样,需要int转换一下
class Solution:
def movingCount(self, m: int, n: int, k: int) -> int:
visit = [[0]*n for _ in range(m)]
res = 0
def dfs(x:int,y:int):
nonlocal res
print(x,y,res,self.mysum(x,y))
if 0<=x<m and 0<=y<n and visit[x][y]==0:
visit[x][y]=1
if self.mysum(x,y)<=k:
res += 1
dfs(x+1,y)
dfs(x-1,y)
dfs(x,y+1)
dfs(x,y-1)
dfs(0,0)
return res
def mysum(self,n:int,m:int)->int:
s = 0
while n!=0:
s += n%10
n=int(n/10)
while m!=0:
s += m%10
m =int(m/10)
return s
题14-1&14-2:剪绳子
法一:本菜鸡自己独立想到的,可喜可贺,PS:还比某人的要快哈哈哈哈
思想:长度为n的绳子分成m段,自然是均分得到的连乘结果最大,如果存在余数,则将余数分成r个1,再加到r个avg上,即,11米长的绳子分成3段,均分可以得到3个3米长的绳子,还余2米,则将这2米分别加到两个3米子绳子上,即最终得到的结果为【3,4,4】;而一共有m种分法,遍历取最大值即可
class Solution:
def cuttingRope(self, n: int) -> int:
maxmun = 0
for i in range(2,n+1):
res = n%i
avg = int((n-res)/i)
if res == 0:
mul = avg**i
else:
mul = avg**(i-res)*(avg+1)**res
if mul > maxmun:
maxmun = mul
return maxmun%1000000007
法二:动态规划
每次仅考虑将长度为i的绳子分成两段,则这个子问题的最优解就等于dp[i]=dp[k]*dp[i-k]
,剽窃王先生的描述:
定义:dp[i] 表示长度为i的绳子至少分割成两段(m>1)的最大连乘。
转移方程:dp[i]=dp[k]*dp[i-k]
,(其中0<k<i)
此时未考虑子问题不分割绳子的情况(即子问题仅有一段绳子),遂加上:
dp[i]=dp[k](i-k)
dp[i]=k*dp[i-k]
dp[i]=k*(i-k)
完整代码如下:
class Solution:
def cuttingRope(self, n: int) -> int:
dp = [0]*(n+1) #初始化
dp[1]=1
for i in range(2,n+1):
for j in range(1,int(i/2)+1): #避免重复计算dp[k]*dp[i-k]==dp[i-k]*dp[k]
#每次选取最优解即可
dp[i]=max(dp[i],dp[j]*dp[i-j],dp[j]*(i-j),j*dp[i-j],j*(i-j))
return dp[n]
题15:二进制中1的个数
法一:新姿势 bin函数可以返回int的二进制字符串,count可以查找某个值出现的次数,不仅可以查找字符串,也可以查找列表(面向对象的特性)
class Solution:
def hammingWeight(self, n: int) -> int:
return bin(n).count('1')
#bin返回int的二进制字符串;count用于查找字符串中某个子串/元素出现的次数。可指定start和end
其他方法:求余、左右移……
题16:数值的整数次方
求x的n次方,即快速幂,搬运王先生的描述:
将n次幂转换为(1+2+4+8+16+…)次幂。
即将n转为其二进制,若其二进制当前位数为1则乘上其对应的幂即可,为0则跳过。
负幂,先当作正幂算,最后用1去除以即可。
class Solution:
def myPow(self, x: float, n: int) -> float:
res,cur = 1,x
for i in bin(abs(n))[::-1]:
if i == '1':
res *= cur
cur *= cur
if n<0:
res = 1/res
return res
题17:打印从1到最大的n位数
python不存在整数溢出问题,所以很方便
class Solution:
def printNumbers(self, n: int) -> List[int]:
return [i for i in range(1,10**n)]
题18:删除链表的节点
链表的删除,已掌握,过
注意删除头节点的情况
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, head: ListNode, val: int) -> ListNode:
pre,now = head,head
while now != None:
if now.val == val:
if now==head:
head = head.next
break
else:
pre.next=now.next
break
else:
pre=now
now=now.next
return head