datawhale-leetcode打卡:001-012题
这次这十二个题目属于是极限肝出来的,有两个参考了一下题解,还是很有意思。我会按照我个人的感觉去写这个东西。
螺旋矩阵(leetcode 054)
这个题目比较恶心的就是跑圈的过程怎么描述。首先,顺时针一圈下来是先从左到右,顶到最右边i<m,好再往下,顶到最下边i<n,好现在i--往回排,最后j--走完一圈以后圈数+1进入下一圈。我本来打算用一个变量记录圈数但是有点不好实现,然后参考了一下题解,发现别人的解法其实也比较简单就是记录左右上下四个边界就可以了。边界越界的话就判定做完了。这个题参考了一下题解,有点小难度,我把代码放过来:
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
l, r, t, b, res = 0, len(matrix[0]) - 1, 0, len(matrix) - 1, []
while True:
for i in range(l, r + 1):
res.append(matrix[t][i]) # left to right
t += 1
if t > b:
break
for i in range(t, b + 1):
res.append(matrix[i][r]) # top to bottom
r -= 1
if l > r:
break
for i in range(r, l - 1, -1):
res.append(matrix[b][i]) # right to left
b -= 1
if t > b:
break
for i in range(b, t - 1, -1):
res.append(matrix[i][l]) # bottom to top
l += 1
if l > r:
break
return res
旋转图像(leetcode 0048)
这个题目我以前做过,其实道理很简单。首先将矩阵倒排,然后求转置就可以了。转置本质上是一个交换元素的过程,所以可以常量空间。倒排的话,有现成的方法可以排序。
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
matrix.reverse()
n=len(matrix)
for i in range(n):
for j in range(i,n):
t=matrix[j][i]
matrix[j][i]=matrix[i][j]
matrix[i][j]=t
return matrix
数组中第K个最大的元素(leetcode 215)
这个题本质上就是一个排序,然后索引就好了。属于送分题。
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
return sorted(nums)[::-1][k-1]
排序数组(leetcode 912)
还是数组排序,基本属于送分。
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
return sorted(nums)
合并两个有序数组(leetcode 088)
这个题目不要看它还是在排序,这个题目有点阴险的。阴险之处在于它没有返回值,直接修改参数num1。C语言里面有指针,C++有引用,但是python传的参数通常不太能直接修改。但是对于数组没必要上深拷贝,使用[:]就可以改动实参值了,这是一个小技巧,也是为什么跑了好几次都没跑过的地方。
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
nums1[:]=sorted(nums1[0:m]+nums2[0:n])
多数元素(leetcode 169)
这个题本质考的就是一个数组计数,类似于wordcount。用字典就可以实现,遍历数据然后创建键值对挨个+1就行。最后通过items遍历找最大的那个就行。当然这个题目还有另外一种解法,但是我这里有一个明确的想法就按这个想法来做。
class Solution:
def majorityElement(self, nums: List[int]) -> int:
count={}
N=len(nums)
for n in nums:
if n not in count.keys():
count[n]=1
else:
count[n]+=1
for c in count.items():
if c[1]>int(N/2):
return c[0]
只出现一次的数字(leetcode 136)
这个题其实原理和上一题一样,可以用字典计数的方法做,但是这个题字典计数就慢了。首先可以对数组进行排序,如果只出现一次,那么它和前后两者都不一样。什么?它没有前?那就是首元素了。没有后?那就是末元素了。分类讨论就行。
class Solution:
def singleNumber(self, nums: List[int]) -> int:
nums.sort()
res=None
for i in range(len(nums)):
if i==0:
if nums.count(nums[i])==1:
return nums[i]
elif i==len(nums)-1:
if nums.count(nums[i])==1:
return nums[i]
else:
if nums[i]!=nums[i-1] and nums[i]!=nums[i+1]:
return nums[i]
合并区间(leetcode 56)
这个题其实参考了一下题解,因为最开始想用栈写结果各种bug。其实这个题目用贪心就可以,每次都把元素追加到结果的末尾。如果待追加元素的左极限刚好在结果最末尾的区间之内,那么这两个元素是可以合并的,否则就添加进来就可以。
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
intervals.sort()
ans = [intervals[0]]
for s, e in intervals[1:]:
if ans[-1][1] < s:
ans.append([s, e])
else:
ans[-1][1] = max(ans[-1][1], e)
return ans
最大数(leetcode 179)
这道题最开始我本来想通过字符串排序获得答案,还想这个题是不是太容易了。但是事实比我想的复杂,这个方法得不到正确结果。例如,30和3拼出来的最大数应该是330而非303,所以不仅要按字符串排还需要按位数来看。但是分组按位数来排序好像也不对,我就不知道怎么弄了。最后看了一下题解,这道题其实也是贪心的一种。
本题的贪心策略的正确性证明包括以下两个命题:
- 反身性:对于任意的数字x,有 xx=xx。
- 传递性:假设对于任意的数字x y z,如果 xy<yx, yz<zy ,那么 xz<zx 一定成立。
反身性这个显然。那么传递性呢?其实是可以证明的。
代码如下
class Solution:
def largestNumber(self, nums: List[int]) -> str:
def rule(x,y):
a,b=x+y,y+x
if a<b:
return 1
elif a>b:
return -1
else:
return 0
new=[str(i) for i in nums]
new.sort(key=cmp_to_key(rule))
# return ''.join(new[::-1])
return ''.join(new)
二分查找(leetcode 704)
这个题也比较简单,基本送分,用index函数就可以。
class Solution:
def search(self, nums: List[int], target: int) -> int:
try:
return nums.index(target)
except:
return -1
第一个和最后一个位置(leetcode 34)
这个题仍然用index。但是有一个问题,index返回第一次出现这个元素的位置,那么最后一次出现的位置就需要进行倒排。倒排最后一次出现的位置,进行镜像对称就可以得到最后一次出现的位置了。比如说,倒排最后出现的下标是i,那么镜像一下就变为n-1-i。
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
try:
i1=nums.index(target)
i2=len(nums)-1-nums[::-1].index(target)
return [i1,i2]
except:
return [-1,-1]
旋转排序数组的最小值(leetcode 153)
这个题说所谓旋转,其实就是循环右移。它是由两个递增序列拼接而成,你的目的就是找到二者的分界点是哪一个。那其实找分界点就是:比左边大,比右边更大的节点。你可以使用二分查找的方式,也可以使用遍历查找的方式。
class Solution:
def findMin(self, nums: List[int]) -> int:
for i in range(1,len(nums)-1):
if nums[i]>nums[i-1] and nums[i]>nums[i+1]:
return nums[i+1]
return min(nums[0],nums[-1])
(这个题目还有一个偷巧的方法,min(nums)一步到位哈哈哈,但是太猥琐了我就算了)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?