概述
(1)5-1-面试题39. 数组中出现次数超过一半的数字
我想到的解法:哈希表和排序,但是对比评论和题解发现自己的也不是最优的。【摩尔投票法】最优
方法一:哈希表 time O(N) space O(N) -> O(N/2)
class Solution:
def majorityElement(self, nums: List[int]) -> int:
#哈希表 O(N)
dic = {}
if len(nums)%2 ==0:n = len(nums)//2
else: n = len(nums)//2 +1
for i in nums:
dic[i] = dic.get(i,0) + 1
##### 不用等到dic 建立完全在判断 O(N/2)
#if dic[i] >= n:return i
#####
for key in dic:
if dic[key] >= n:
return key
方法二:排序,找中位数 time O(NlogN) space O (1)
想到了排序,但是没有考虑到出现超过一半的数字就是“众数”,也没有想到中间的那个数就是众数,排序结束之后,用双指针来找到了众数。-,-蠢哭。
class Solution:
def majorityElement(self, nums: List[int]) -> int:
#排序 O(NlogN)
nums.sort()
if len(nums)%2 ==0:n = len(nums)//2
else: n = len(nums)//2 +1
return nums[n]
方法三:摩尔投票法(最优解法) time O(N) space O(1) 链接是一个好理解的解释。
摩尔投票法本质思想就是利用 众数记为 +1 ,把其他数记为 -1 ,将它们全部加起来,显然和大于 0和抵消相减。
class Solution:
def majorityElement(self, nums: List[int]) -> int:
votes = 0 ## 来自Leetcode @Krahets
for num in nums:
if votes == 0: x = num ## 重新开始拟定一个众数
if num == x: ## 相同+1 不同-1
votes += 1
else: votes -= 1
return x #最后没有被消掉的肯定是众数
(2)5-2-面试题12. 矩阵中的路径
考点:DFS+剪枝
很明确的知道这个题就是用DFS的方法来做,遇到不满足的点的时,返回到上一节点处,继续找下一个可行解,直到所有的点都不能满足要求的时候停止。但是寻找过程中,不会写如何返回上一个节点(剪枝操作-回溯),因此卡住了。
DFS的框架就是 递归框架。从一个状态下一个可行状态转换。
框架:
def DFS(parameter1,parameter2): #
## visited = True
if 条件 满足:
DFS(parameter1,parameter2) #在往下继续遍历
## 如果不满足 返回相应的结果
## 状态恢复
## visited = False ## 回溯
return resluts
因为这个题只能走一次,所以遍历每个点的时候,都要有一个 visited 来判断。
如果 满足条件【边界范围 未被访问 board等于word】 -> 进入下一个 DFS()
如果 不满足条件 :该状态 重置 , return Fasle
如果 已经到了最后一个word点了,return True。
这个题还有一点不同的是,他是一步返回一个判断结果和 遍历到最后 返回一个结果还不太一样。【有点懵】
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
m,n = len(board),len(board[0])
visited = [[False for i in range(n)] for j in range(m)]
## DFS
def DFS(i,j,k):
visited[i][j] = True
if k == len(word): return True ##结束探测
k += 1
## 上下左右,如果满足就继续往下走了
if i+1<m and not visited[i+1][j] and board[i+1][j]==word[k-1]:
if DFS(i+1,j,k):
return True
if j+1<n and not visited[i][j+1] and board[i][j+1]==word[k-1] :
if DFS(i,j+1,k):
return True
if i-1>=0 and board[i-1][j]==word[k-1] and not visited[i-1][j]:
if DFS(i-1,j,k):
return True
if j-1>=0 and board[i][j-1]==word[k-1] and not visited[i][j-1]:
if DFS(i,j-1,k):
return True
visited[i][j] = False ##如果没有往下走,那么回溯,把访问信息清空
return False
for i in range(m):
for j in range(n):
if board[i][j] == word[0]:
if DFS(i,j,1) :return True
return False
(3)5-3-面试题45. 把数组排成最小的数
考点:“排序”变种 ->将数字(单个字符串)按照一定的规则重新排列,组成长字符串。
刚开始想的是,“30” “3”,那么3不是放在 “30”的前面,就是放在“30”的后面,然后可以当成是DP,来做。
但是 由于存在 1,4,2 -> '124' 发现并不能用DP来做。[DP的状态转换条件个数是一定的]
然后就不会做了。 想的是 当 ans = [ '30','3'] 时,'34' 从0,1,2三个位置分别插入,然后在比较每次插入时,数字组合的大小,但是这样太麻烦了,而且存在着很多int() 和 str() 的来回转换。
规则就是从 产生的字符串最小来的,假设 x,y是两个字符串'30','3'。
如果 x+y > y+x : x>y 反之 x+y<y+x: x<y
-> '30'+'3' < '3'+'30' :'30' <'3' ,排序的时候,'3'应该放在'30'后面,按照从小到大的规则。
规则出来了,之后就是基本排序的方法【快排】的模板套进去了。
class Solution:
def minNumber(self, nums: List[int]) -> str:
def judge(x,y): #
if int(x+y) > int(y+x):
return True# x>y
else:
return False # x<y
num = [ str(nums[i]) for i in range(0,len(nums))]
for i in range(0,len(nums)): # O(N^2) 冒泡
min_ = num[i]
for j in range(i+1,len(nums)):
if not judge(num[j],min_) : #按照规则去比较大小
temp = min_
min_ = num[j]
num[j] = temp
num[i] = min_
return ''.join(num)
# O(NlogN)
i,j = 0,len(nums)-1
def get(num,low,high):
temp = num[low]
while(low<high):
while(low<high and judge(num[high],temp)): high-=1
num[low] = num[high]
while(low<high and not judge(num[low],temp)):low+=1
num[high] = num[low]
num[low] =temp
return low
def quick_sort(num,low,high):# O(NlogN)
if low<high:
index = get(num,low,high)
quick_sort(num,low,index-1)
quick_sort(num,index+1,high)
quick_sort(num,i,j)
return ''.join(num)
下面的这个也是快排,但是来自此处。
比我快的原因:
(1)python中可以直接用 “<” 比大小,不用再去写judge函数去判断。[c中不能直接用关系运算符比字符串大小]
(2)get 和 quick_sort() 是可以合并的,这样节省了temp的开销,且没有来回调用get()的问题。
class Solution:
def minNumber(self, nums: List[int]) -> str:
def fast_sort(l , r):
if l >= r: return
i, j = l, r
while i < j:
while strs[j] + strs[l] >= strs[l] + strs[j] and i < j: j -= 1
while strs[i] + strs[l] <= strs[l] + strs[i] and i < j: i += 1
strs[i], strs[j] = strs[j], strs[i]
strs[i], strs[l] = strs[l], strs[i]
fast_sort(l, i - 1)
fast_sort(i + 1, r)
strs = [str(num) for num in nums]
fast_sort(0, len(strs) - 1)
return ''.join(strs)
利用排序的另外一种方法(python)利用sort() 函数中的cmp,自定义规则,然后排序。曾经写过博客,然而并没有实际用过。这里也写一下。 代码也是摘自上面的题解连接。其中sort() 时间复杂度 O(NlogN)
class Solution:
def minNumber(self, nums: List[int]) -> str:
def sort_rule(x, y): # 比较x,y大小
a, b = x + y, y + x
if a > b: return 1 # x+y >y+x -----> x>y
elif a < b: return -1 ## 小于
else: return 0 ##等于
strs = [str(num) for num in nums]
strs.sort(key = functools.cmp_to_key(sort_rule)) ##比较规则,按照定义的比较规则去排序
return ''.join(strs)
(4)5-4-面试题09. 用两个栈实现队列
考点:队列先进先出,栈先进后出(队列和栈的相关知识) python list.pop() #默认删除最后一个元素
我的思路:一个栈用来存储元素S1,当需要删除时,判断S1是否空,不空那么把栈顶元素赋值给ans(return),将剩下的元素给S2。S1置空,再将S2元素返回进去。 23.64%(时间)
大佬们的思路:一个栈只存储S1,一个只用来删除S2。若S2不空,直接删除最后一个元素。若空,判断S1是否为空,若空 return -1。否则将S1 [1,2,3] 从栈顶依次删除,放入S2 [3,2,1]。(这样保证了S2的栈顶是S1的栈底,也就是队列的先进先出)。删除时,删除的是1。S1再放的时候,还是满足的,只不过这样不能保证某个状态下,根据某一个栈就能把所有元素取出。[用一个栈保证栈底是栈顶] 74.83%
为什么我的慢?因为我 有一个来回折腾S1和S2的过程。S1置空虽然是直接覆盖的,但是按照正常的来说,是应该逐个删除的。
class CQueue:
def __init__(self):
# 一个栈用来存储 # 一个栈是删除工具
self.S1 = []
self.S2 = []
def appendTail(self, value: int) -> None:
self.S1.append(value)
def deleteHead(self) -> int:
# mine
if len(self.S1) == 0 :return -1
ans = self.S1[0]
self.S2 = []
for i in self.S1[1:]: #从栈顶从新开始
self.S2.append(i)
self.S1 = self.S2
return ans
## others
if self.S2 : return self.S2.pop() #删除S2栈顶
elif not self.S1: return -1
else:
while self.S1: # 将S1倒叙存入S2,
self.S2.append(self.S1.pop())
return self.S2.pop()
(5)5-5-面试题59 - I. 滑动窗口的最大值
考点:双端队列(单调队列) 可以和单调栈做个对比。->面试题63. 股票的最大利润
思路:时间主要浪费在求解滑动窗口内的最大值O(k)。如何才能使时间变成O(1)呢?考虑用空间换时间。辅助的操作就是栈和队列了。
暴力法:
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
ans = []
i,n = 0,len(nums)
while(i<n and i+k < n+1): ## O(nk)
ans.append(max(nums[i:i+k])) #O(k)
i += 1
return ans
双端队列:时间 O(N) 空间 O(k) 双端队列大小和窗口大小相同。
保证队列中是递减的,那么每一轮滑动过程中,Q[0]就是最大值。当进行下一轮滑动时,首先让最左端的最大的这种情况排除,然后在每次放入一个,使窗口向右滑动。
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
if not nums or k == 0: return []
deque = collections.deque()
for i in range(k): # 未形成窗口
while deque and deque[-1] < nums[i]: deque.pop()
deque.append(nums[i])
res = [deque[0]]
for i in range(k, len(nums)): # 形成窗口后
if deque[0] == nums[i - k]: deque.popleft() ##不理解的一句话
while deque and deque[-1] < nums[i]: deque.pop()
deque.append(nums[i])
res.append(deque[0])
return res
对于 if deque[0] == nums[i - k]: deque.popleft() 因为每一次都往后挪一个,所以上一轮的第一个元素就应该挪出去,如果Q中最大就是上一轮的第一个元素。那么如果存在于这一轮会对结果产生影响。如果Q[0]不是上一轮中的第一个元素,那么肯定的是上一轮中的第一个元素已经挪出去了。因此判断的是这一轮的Q[0]和上一轮的第一个元素的比较。【比较绕的一个点】
因为 nums[i - k]
是这轮要去挪出去的,所以要和这个元素比较。
(6)5-6-面试题64. 求1+2+…+n
考点 :位运算和逻辑运算的使用
方法一:利用and的逻辑运算规则实现。 终止递归条件是 逻辑与。
class Solution:
def sumNums(self, n: int) -> int:
# if n==0:return 0
def get_res(n):
return n and n + get_res(n - 1) # 递归形式
# 变量都不为0时(n>0),返回后面的那个
# 当变量为0时候(n=0)返回0
return get_res(n)
方法二:位运算。
按照求和公式,可以很快的想到:,除以2可以利用 >> 实现。然后 不知道如何做了。
利用快速乘法或者快速幂类的思想,利用移位运算符解决问题。知识盲点已经补充,见链接。
class Solution:
def sumNums(self, n: int) -> int:
temp = n+1
ans = 0
#循环14遍
(n & 1) && (ans += temp)
n >>= 1
temp <<= 1
return ans >> 1
(7)5-7-面试题15. 二进制中1的个数
考点:位运算 & 和 "<< " ">>"
class Solution:
def hammingWeight(self, n: int) -> int: #log(N)
res = 0
while n:
res += n & 1
n >>= 1
return res
第二种思路来自此处:
利用 n&(n−1) time is O(N) space is O(1)
class Solution:
def hammingWeight(self, n: int) -> int:
res = 0
while n:
res += 1
n &= n - 1
return res
(8)5-8-面试题66. 构建乘积数组
考点:用空间换时间,略微带一些找规律。这个题 O(N^2)通过不了。然后降低时间复杂度,有两条路可走:(1)用空间换时间,创建[栈/队列/数组]等来解决。(2)双指针、排序等方法来优化时间复杂度。
这个题,就属于第一种方法。
首先建立一个S1 = [A0, A0*A1,A0*A1*A2,....,A0*A1*...A(n-2)] #不包括 An-1情况
S2 = [A(n-1), A(n-1)*A(n-2),....,A(n-1)*A(n-2)*...A(1)] # 不包括A0情况
B = [S2[n-2],S1[0]*S2[n-3],....,S1[n-1]*S2[0],S1[n-2]]
class Solution:
def constructArr(self, a: List[int]) -> List[int]: ##自己的垃圾代码
B = [1 for i in range(len(a))]
n = len(a)
S1 = [1 for i in range(n-1)]
S2 = [1 for i in range(n-1)]
for i in range(0,n-1):
if i==0:
S1[i] = a[i]
else:S1[i] = a[i]*S1[i-1]
for i in range(0,n-1):
if i==0: S2[i] = a[n-i-1]
else:S2[i] = S2[i-1]*a[n-i-1]
for i in range(0,n):
if i == 0:B[i] = S2[n-i-2]
elif i == n-1:B[i] = S1[i-1]
else:
B[i] = S1[i-1] * S2[n-i-2]
return B
看了评论和题解,发现了几个比较好的思想。因为如果暴力里面,肯定是下面这样的。
for i in range(len(a)):
for j in range(len(a)):
if j!=i:
b[i] *= a[j]
降低复杂度,直接从j = i的地方(对角线)分开不就好了? 画一下矩阵。
先把j=i前面的相乘赋给B[j],再把j=i后面的相乘 乘到 B[j]中。 想法来自:Leetcode此题评论 @Leslie zjz
B = [1 for i in range(len(a))]
n = len(a)
i,temp = 0,1
while(i<n):
B[i] = temp
temp *= a[i]
i += 1
i,temp=n-1,1
while(i>=0):
B[i] *= temp
temp *= a[i]
i -= 1
return B
(9)5-9-面试题48. 最长不含重复字符的子字符串
暴力解法:
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:## O(N^2) O(N)
if len(s) <= 1: return len(s)
stack,max_ = [],0
for i in range(0,len(s)):
stack = []
stack.append(s[i])
for j in range(i+1,len(s)):
if s[j] not in stack:
stack.append(s[j])
else:
break
max_ = max(len(stack),max_)
return max_
(10)5-10-面试题10- I. 斐波那契数列
考点:求余问题。递归、DP解法。 和青蛙跳台阶一样。
这个题在最初DP问题中就有了,直接写就行了。
class Solution:
def fib(self, n: int) -> int:
a,b = 0,1 # O(N)
if n == 0:return 0
if n == 1:return 1
for i in range(2,n+1):
a,b = b%1000000007,(a+b)%1000000007
return b
递归会超时。 可以利用 functools.lru_cache来解决。
from functools import lru_cache
class Solution:
def fib(self, n: int) -> int:
@lru_cache(None)
def t(n): # 超时间 O(n)
if n==0:return 0
if n==1:return 1
return (t(n-1)+t(n-2))%1000000007
return t(n)
还有一个利用数学归纳法证明之后,再做的题解,链接。
(11)5-11-面试题17. 打印从1到最大的n位数
看了一下评论这个题没有什么意义,剑指里面考的是大数问题。而且python没有特别强调的溢出问题,所以不用python说了,第二遍看c刷剑指再补充。
class Solution:
def printNumbers(self, n: int) -> List[int]:
l = []
for i in range(1,10**n): ##10**n
l.append(i)
return l
(12)5-12-面试题56 - I. 数组中数字出现的次数
考点: 异或[位运算] 。真真想不到,即使以前做类似的了。
O(2N) O(N) -> 哈希表
知识点:(1)a^b 按照相同为0不同为1,求解每一位二进制
(2)a^a = 0 ;a^0 = a; a ^ b ^ c = a ^ c ^ b [交换律]
(3) (a^b)^c = a^(b^c) 结合律
(4)A ^ B ^ B = A ^ 0 = A ---> A ^ B = C 则 C ^ B = A (自反性)
四道关联题的整理与解析来自此处。
136 ->除了某个数字之外,所有数据都出现了2次。找到这个数字。
136举例: 0^a^b^c^c^a = 0^a^a^c^c^b = a^a^c^c^b = b【主要利用交换律】 O(N) O(1)
single_number = 0
for i in nums:
single_number ^= num # 0
return single_number
面试题56 - II. 数组中数字出现的次数 II-> 除了一个数字出现一次,其他都出现了三次。找到出现一次的数字。
Map -> O(N) O(N)
class Solution:
def singleNumber(self, nums: List[int]) -> int:
## 哈希
dic ={} #O(n) O(n)
for i in nums:
dic[i] = dic.get(i,0)+1
for key,value in dic.items():
if value == 1:
return key
数学方法:
return (sum(set(nums))*3-sum(nums))//2 # O(N)?
从二进制出发,找规律。
[4,3,4,4] 1 0 0 4
0 1 1 3
1 0 0 4
1 0 0 4
4 1 1 +
可以看出,出现三次的二进制数每位相加后都是3的倍数,所以 把每一位相加,然后 是3n+1的。除以3之后,就是答案。
ans = 0
i = 0 ## num 最大不超过32位
while(i<32): ## 常数次time is 32
count = 0
index = 1<<i # 来衡量从右到左的每一位
for j in nums: ## time is O(N)
if j & index != 0 : # 该位 存在1
count += 1
if count%3 == 1 :# 判断该位置是否是单独数字产生
ans += index
# ans |= index
i += 1
return ans ## O(32n) ->O(n)
数字电路和DFA的方法。题解点击此处。 [偷懒,不看了]
645. 错误的集合 数组里面有唯一重复的一个数字还有一个缺失的数字,重复数字里面有一个本应该是缺失的数字,找出这个两个数字。
用 异或 来找出缺失的数字。
由于限定了数组从1~n。那么将 1~n做异或。再将结果与给定数组做异或。即可得到缺失的数组的异或。
然后再利用异或结果,把这 例子样本 和 标准样本 两个数字分开。
然后分开之后,可以发现。缺失数组中除了缺失的都是成对的。而多了的那个中,除了多了的,也都是成对的。所以在分别异或。就分开了 缺失和重复。题解来自此处。
class Solution:
def findErrorNums(self, nums: List[int]) -> List[int]:
ans = 0
for number in nums:
ans = number ^ ans
for i in range(1,len(nums)+1):
ans ^= i
h = 1
while(ans & h ==0): h <<= 1 #区分界限
# h = ans&(-ans)
a,b = 0,0
for number in nums:
if number &h ==0:
a ^= number
else:
b ^= number
for i in range(1,len(nums)+1):
if i&h ==0: a^= i
else:b^=i
if b in nums: return [b,a]
else: return [a,b]
本道题。题解来自此处。如果可以将两个不同的数字分组,那么两组不同的分别异或就可以得到最终答案。
以一个规则分组:可以利用奇偶性将相同的数组分组。不管怎么样,相同的一定会分到同一组。
如何去分组 里面两个不同的,是关键!因为将所有的数字进行异或,肯定存在结果中某一位为1。那么就以这个去分组。
打个简单的比方,就像区分两幅画,那就是以画中的某一个不同点去区分。因为 a^b 不同,所以异或有一位为1,那么 把这位数字找见[找见最低位为1的],再分别与a b异或,那么肯定得到不同的结果。
class Solution:
def singleNumbers(self, nums: List[int]) -> List[int]:
ans = 0
for number in nums:
ans ^= number # 为了找不同的那位
h = 1 ## h 01 10 100 1000 这样的形式
while( ans & h == 0):
# print(ans & 1) ans >>= 1 ->把每一位最低位值取出,不太一样注意区分
h <<= 1 # 找 最低位为1 的
# 用h来做划分
a,b = 0,0
for number in nums:
if number & h == 0:
# 这个规则对于划分相同的没什么影响,不管怎么样相同的一定会在一起
a ^= number
else:
b ^= number
return [a,b]
总结一下:感觉这类题,出现某某数字中除了a、b等只出现了一次。可以考虑位运算(异或 与)。如果是出现了a、b两种数字,找出这两个数字,那么先想的一定是如何把这两个数字分开。如果是只出现了一次,那么可以直接使用异或(找二进制数)的规律了。 像数字 2 4 6 等中只出现了一次,那么直接异或就行了。如果是 3,5,7等中只出现了一次。那么就是数组中数字出现的次数 II中的这种思路。
(13)5-13-面试题44. 数字序列中某一位的数字
考点:机智的找规律
(14)5-14-面试题16. 数值的整数次方
考点:快速幂 我自己已经写过专门的博客,不在总结了。
class Solution:
def myPow(self, x: float, n: int) -> float:
'''temp = 1
if n <0: b=-n
else: b=n
while(b):
if b & 1:
temp *= x
x *= x
b >>= 1
if n>=0:return temp
else:return 1/temp '''
temp = 1
if n <0:x,n=1/x,-n ## 这里很巧妙 两种的时间复杂度差不多
while(n):
if n& 1:
temp *= x
x *= x
n >>= 1
return temp
(15)5-15-面试题45. 把数组排成最小的数
考点:DP算法 因为刷过了小青蛙跳台阶,所以这个题就很容易的想到是DP的方法。
只不过有两个限制条件:
(1) 当前位置和前一个位置组成的数字>25,这种情况下 f[n] = f[n-1]
(2)当前位置和前一个位置组成的数字=当前位置数字,这种情况,f[n] =f[n-1]
(3)否则 当前位置的方案数 f[n] = f[n-1]+f[n-2] n>=2
f[1] =1 f[0]=1 没有num也是一种情况。
所以就有了下面的代码:
class Solution:
def translateNum(self, num: int) -> int:
# 转成 list O(N) O(N)
if num == 0: return 1
l = []
while(num):
l.append(num%10)
num //= 10
l = l[::-1]
f = [0 for i in range(len(l)+1)]
f[0] = 1
f[1] = 1
for i in range(2,len(l)+1):
if l[i-1]+l[i-2]*10 >25:
f[i] = f[i-1]
elif l[i-1]+l[i-2]*10 == l[i-1]:
f[i] = f[i-1]
else:
f[i] = f[i-1]+f[i-2]
return f[len(l)]
上面代码 time is O(2N) space is O(2N)
所以,可以将f搞没。然后 if l[i-1]+l[i-2]*10 >25 和 l[i-1]+l[i-2]*10 == l[i-1] 是可以合并的,简化if判断。
class Solution:
def translateNum(self, num: int) -> int:
# 转成 list O(N) O(N)
if num == 0: return 1
l = []
while(num):
l.append(num%10)
num //= 10
l = l[::-1] ## 可以简化成 s = str(num)
a,b = 1,1
for i in range(2,len(l)+1):
if l[i-1]+l[i-2]*10 >25 or l[i-2] == 0:
a = b
else: ## if '10' <= s[i-2:i] <'25'
a,b=b,a+b
return b
代码: time is O(2N) space is O(N)
看了一眼解题发现大神的思路是从右往左来查看,效果是一样的。然后呢再利用由于list时的求从右往左的每一位,来简化运算,使得space is O(1)。思路来源于此处
下面代码 time is O(N) space is O(N) 。
class Solution:
def translateNum(self, num: int) -> int:
s = str(num)
a = b = 1
for i in range(len(s) - 2, -1, -1):
if if "10" <= s[i:i + 2] <= "25":
a,b= b,a+b
else:
a = b
return b
再简化:time is O(N) space is O(1)
class Solution:
def translateNum(self, num: int) -> int:
a = b = 1
y = num % 10
while num != 0:
num //= 10
x = num % 10
tmp = 10 * x + y ##每次求解两位
c = a + b if 10 <= tmp <= 25 else a ##如果tmp 满足条件就是两种方案 否则为1
a, b = c, a # 做一次更新,a,b
y = x #把此次的个位数留下来,坐下一次循环使用
return a
最后
以上就是幸福大象为你收集整理的Python-Leetcode-剑指offer(五月上做题整理)的全部内容,希望文章能够帮你解决Python-Leetcode-剑指offer(五月上做题整理)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复