题目1 Leetcode33 搜索旋转排序数组
描述:给定一个整数数组 nums
,数组中值互不相同。给定的 nums
是经过升序排列后的又进行了「旋转」操作的。再给定一个整数 target
。
要求:从 nums
中找到 target
所在位置,如果找到,则返回对应下标,找不到则返回 -1
。
说明:
- 旋转操作:升序排列的数组 nums 在预先未知的第 k 个位置进行了右移操作,变成了
[nums[k]], nums[k+1], ... , nums[n-1], ... , nums[0], nums[1], ... , nums[k-1]
。
def findmins(A, left, right):
index = right
while left<right:
index = (left+right)//2
if A[index] > A[right]:
left = index+1
else:
right = index
return left
def binaryfind(A, left, right, target):
while left<=right:
index = (left+right)//2
if A[index]==target:
return index
if A[index]<target:
left = index+1
else:
right = index-1
return -1
class Solution:
def search(self, nums: List[int], target: int) -> int:
# 先找到最小值的坐标,然后再比对最小值和target的大小
# 如果target比nums[len-1]大,则只在最小值左边找
# 如果target比nums[len-1]小,则只在最小值右边找
l_nums = len(nums)
index = findmins(nums, 0, l_nums-1)
if target>nums[l_nums-1]:
return binaryfind(nums, 0, index-1, target)
elif target<nums[l_nums-1]:
return binaryfind(nums, index, l_nums-1, target)
else:
return l_nums-1
题目2 Leetcode162 寻找峰值
描述:给定一个整数数组 nums
。
要求:找到峰值元素并返回其索引。必须实现时间复杂度为 �(log�) 的算法来解决此问题。
说明:
class Solution:
def findPeakElement(self, nums: List[int]) -> int:
# 找峰值,峰值两边的数都比它小,而非峰值的右边数一定比它大
# 如果mid左小右小则输出mid
# 如果mid右大左小则说明处在升序中,左侧可以抛弃
# 如果mid右大左大则说明处在谷底,左右侧可以择一抛弃
# 如果mid右小左大则说明处在降序,右侧可以抛弃
# 综上,右边小的情况下,抛弃右边,右边大的情况下,抛弃左边
left = 0
right = len(nums)-1
ans = 0 # 答案先默认是0
def get_mid(index,A):
if index == -1 or index == len(A):
return float('-inf')
return A[index]
while left<=right:
mid = (left+right)//2
if get_mid(mid-1,nums)<get_mid(mid,nums) and get_mid(mid,nums)>get_mid(mid+1,nums):
ans = mid
break
if get_mid(mid,nums)>get_mid(mid+1,nums): # 右边小
right = mid-1
elif get_mid(mid,nums)<get_mid(mid+1,nums): # 右边大
left = mid+1
return ans
题目3 Leetcode04 寻找两个正序数组的中位数
描述:给定两个正序(从小到大排序)数组 nums1
、nums2
。
要求:找出并返回这两个正序数组的中位数。
这题写到最后都是云里雾里,靠着题解艰难copy完的,三天后重做一次。
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
# 分两种情况 1.合并后长度为奇数 2.合并后长度为偶数
# 奇数情况下,中位数就是最中间的那个数;偶数情况下,中位数是中间的两个数除以2
# 思路:将A数组从i=(left+right)//2处分成两份,B数组从j=(n+m+1)//2-i处分开
# A数组和B数组分成的两份A_1+B_1和A_2+B_2各自相加后,长度是相等的
# 找中位数就是找A_1+B_1的max值和A_2+B_2的min值
# 如果max<=min且m+n为偶数,则这两个数除以2就是中位数,m+n为奇数则中位数是max
# 如果max>min,则说明这样划分会使左边的数组过大,更新right=mid-1
if len(nums1)>len(nums2): # 保证nums2是更长的列表
return self.findMedianSortedArrays(nums2, nums1)
l_1, l_2 = len(nums1), len(nums2)
Inf = 2**40
left, right = 0, l_1
mid1, mid2 = 0, 0
while left<=right:
# 前一部分包含 nums1[0 .. i-1] 和 nums2[0 .. j-1]
# 后一部分包含 nums1[i .. l_1-1] 和 nums2[j .. l_2-1]
i = (left + right)//2
j = (l_1 + l_2 + 1)//2 - i
# nums_imax, nums_i, nums_jmin, nums_j
# 分别表示 nums1[i-1], nums1[i], nums2[j-1], nums2[j]
nums_imax = (-Inf if i == 0 else nums1[i - 1])
nums_i = (Inf if i == l_1 else nums1[i])
nums_jmin = (-Inf if j == 0 else nums2[j - 1])
nums_j = (Inf if j == l_2 else nums2[j])
if nums_imax <= nums_j:
mid1, mid2 = max(nums_imax, nums_jmin), min(nums_i, nums_j)
left = i + 1
else:
right = i - 1
return mid1 if (l_1 + l_2)%2 else (mid1 + mid2)/2
题目4 Leetcode240 搜索二维矩阵 II
描述:给定一个 �×� 大小的有序整数矩阵 matrix
。matrix
中的每行元素从左到右升序排列,每列元素从上到下升序排列。再给定一个目标值 target
。
要求:判断矩阵中是否可以找到 target
,如果可以找到 target
,返回 True
,否则返回 False
。
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
# 就这个数据规模,遍历都遍历完了
# 对每一行做一次二分查找吧
def binaryfind(A, left, right, target):
while left<=right:
mid = (left+right)//2
if A[mid]==target:
return True
elif A[mid]>target:
right = mid-1
else:
left = mid+1
return False
for x in matrix:
if binaryfind(x, 0, len(x)-1, target):
return True
return False
题目5 Leetcode 69 x 的平方根
题目要求不使用内置函数,求出x的平方根,并且向下取整。
很明显我们可以从0到x+1遍历,找到满足条件后的值后直接输出。
class Solution:
def mySqrt(self, x: int) -> int:
if x==1 or x==0:
return x
for i in range(0,x+1):
if i*i == x:
return i
elif i*i > x:
return i-1
但是这题还是可以用二分查找的算法的,用正常遍历的思想,时间复杂度是O(n)级别的,换成O(logn)的二分查找明显 明显
class Solution:
def mySqrt(self, x: int) -> int:
left = 0
right = x+1
while left<right:
mid = (left+right)//2
if mid*mid == x:
return mid
elif mid*mid > x:
right = mid-1
else:
left = mid+1
return left-1 if left**2 > x else left
题目6 Leetcode283 移动零
描述:给定一个数组 nums
。
要求:将所有 0
移动到末尾,并保持原有的非 0
数字的相对顺序。
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
lenth = len(nums)
i = 0
while i < lenth:
if nums[i]==0:
nums.pop(i)
lenth -= 1
nums.append(0)
i -= 1
i += 1
题目7 Leetcode415 字符串相加
描述:给定两个字符串形式的非负整数 num1
和num2
。
要求:计算它们的和,并同样以字符串形式返回。
class Solution:
def addStrings(self, num1: str, num2: str) -> str:
# 先把长的数字放到num1中
if len(num2)>len(num1):
return self.addStrings(num2,num1)
l_1 = len(num1)-1
l_2 = len(num2)-1
# 先对末尾进行加减
jin = (int(num1[l_1]) + int(num2[l_2])) // 10
num = (int(num1[l_1]) + int(num2[l_2])) % 10
num1 = num1[:l_1] + str(num)
l_1 -= 1
l_2 -= 1
while l_2>=0 or jin:
if l_2>=0:
num = (int(num1[l_1]) + int(num2[l_2]) + jin) % 10
jin = (int(num1[l_1]) + int(num2[l_2]) + jin) // 10
num1 = num1[:l_1] + str(num) + num1[l_1+1:]
elif l_1>=0 and jin:
num = (int(num1[l_1]) + jin) % 10
jin = (int(num1[l_1]) + jin) // 10
num1 = num1[:l_1] + str(num) + num1[l_1+1:]
elif l_1<0 and jin:
num1 = str(jin) + num1[:]
jin = 0
l_1 -= 1
l_2 -= 1
return num1
题目8 Leetcode239 滑动窗口最大值
描述:给定一个整数数组 nums
,再给定一个整数 k
,表示为大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。我们只能看到滑动窗口内的 k
个数字,滑动窗口每次只能向右移动一位。
要求:返回滑动窗口中的最大值。
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
ans = []
# 设置一个list temp
# temp最开始装着第一个区间内最大元素的下标
# 后面开始滑动区间,每滑动一个元素,就用该元素和temp末尾的元素对比
# 删去temp中比该元素小的的元素后,将该元素插入temp末尾,并删除已经脱离区间的元素
temp = []
for i in range(k):
while temp and nums[i]>=nums[temp[-1]]:
temp.pop()
temp.append(i)
ans.append(nums[temp[0]])
for i in range(k,len(nums)):
while temp and nums[i]>=nums[temp[-1]]:
temp.pop()
temp.append(i)
while temp[0]<i-k+1:
temp.pop(0)
ans.append(nums[temp[0]])
return ans
题目9 Leetcode03 无重复字符的最长子串
描述:给定一个字符串 s
。
要求:找出其中不含有重复字符的最长子串的长度。
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
son = ''
l = 0
for x in s:
if x not in son:
son += x
else:
while x in son:
son = son[1:]
son += x
l = max(l,len(son))
return l
题目10 Leetcode76 最小覆盖子串
描述:给定一个字符串 s
、一个字符串 t
。
要求:返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
class Solution:
def minWindow(self, s: str, t: str) -> str:
# 如何匹配t是否是s的子串呢?
# 建立两个字典,记录字符串中的的情况
def check(dic_a, dic_b):
for x in dic_b.keys():
if x not in dic_a:
return False
elif dic_a[x] < dic_b[x]:
return False
return True
son = ''
temp = '' # 滑动窗口
dic_s = {}
dic_t = {}
for x in t:
if x in dic_t:
dic_t[x] += 1
else:
dic_t[x] = 1
for x in s:
dic_s[x] = 0
for x in s:
temp += x
dic_s[x] += 1
if check(dic_s, dic_t):
if son == '':
son = temp[:]
while check(dic_s, dic_t):
if len(son) > len(temp):
son = temp[:]
dic_s[temp[0]] -= 1
temp = temp[1:]
return son
题目11 Leetcode718 最长重复子数组
描述:给定两个整数数组 nums1
、nums2
。
要求:计算两个数组中公共的、长度最长的子数组长度。
class Solution:
def findLength(self, nums1: List[int], nums2: List[int]) -> int:
l_1 = len(nums1)
l_2 = len(nums2)
d = [[0 for _ in range(l_2+1)] for _ in range(l_1+1)] # 状态矩阵初始全为0
# d[i][j]是 以nums1[i]和nums2[j]结尾的元素最长子串长度
# if nums1[i]==nums2[j]: d[i][j]=d[i-1][j-1]+1
# else: d[i][j]=0
ans = 0
for i in range(1, l_1+1):
for j in range(1, l_2+1):
if nums1[i-1]==nums2[j-1]: # i-1和j-1都是为了fang
d[i][j] = d[i-1][j-1] + 1
if d[i][j]>ans:
ans = d[i][j]
return ans
题目12 Leetcode83 删除排序链表中的重复元素
描述:给定一个已排序的链表的头 head
。
要求:删除所有重复的元素,使每个元素只出现一次。返回已排序的链表。
# 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]:
newhead = head
if head==None or head.next==None:
return head
while head and head.next : # 最后一个节点和空节点就不用考虑了
while head.next and head.val == head.next.val: # 循环删除相同的值
head.next = head.next.next
head = head.next
return newhead
题目13 Leetcode82 删除排序链表中的重复元素 II
描述:给定一个已排序的链表的头 head
。
要求:删除原始链表中所有重复数字的节点,只留下不同的数字。返回已排序的链表。
# 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]:
cur = ListNode(0)
cur.next = head
ans = cur
while cur:
now = cur.next
flag = 0
while now and now.next and now.val==now.next.val:
now.next=now.next.next
flag = 1
if flag and not cur.next.next == None:
cur.next = cur.next.next
elif flag and cur.next.next == None:
cur.next = None
else:
cur = cur.next
return ans.next