###############判断是否为字符串
import collections
class Solution(object):
def CheckPermutation(self, s1, s2):
"""
:type s1: str
:type s2: str
:rtype: bool
"""
freq = collections.Counter(s1)
for i in range(len(s2)):
freq[s2[i]] -= 1
for k,v in freq.items():
if v != 0 :
return False
return True
############# 最小高度树
class Solution(object):
def sortedArrayToBST(self, nums):
"""
:type nums: List[int]
:rtype: TreeNode
"""
if not nums:
return
# mid = len(nums) //2
left = 0
right = len(nums) - 1
mid = left + (right-left) // 2
tree = TreeNode(nums[mid])
tree.left = self.sortedArrayToBST(nums[:mid])
tree.right = self.sortedArrayToBST(nums[mid+1:])
return tree
###################面试题 16.17. 连续数列
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
# if len(nums) == 1: return nums[0]
dp = [0] * len(nums)
dp[0] = nums[0]
# dp[1] = max(nums[0]+nums[1],nums[1])
max_dp = dp[0]
for i in range(1,len(nums)):
dp[i] = max((dp[i-1] + nums[i]),nums[i])
max_dp = max(max_dp,dp[i])
return max_dp
###############面试题 17.04. 消失的数字
import collections
class Solution(object):
def missingNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
freq = collections.Counter(nums)
for num in range(len(nums)+1):
if num not in freq:
return num
###############面试题 01.04. 回文排列
import collections
class Solution(object):
def canPermutePalindrome(self, s):
"""
:type s: str
:rtype: bool
"""
freq = collections.Counter(s)
prior = 1
for k,v in freq.items():
if freq[k] % 2 == 0:
continue
else:
prior -= 1
return prior >= 0
###############1213. 三个有序数组的交集
class Solution(object):
def arraysIntersection(self, arr1, arr2,arr3):
def cross(arr1,arr2):
i, j = 0, 0
res = []
while i < len(arr1) and j < len(arr2):
if arr1[i] < arr2[j]:
i += 1
elif arr1[i] > arr2[j]:
j += 1
else:
res.append(arr1[i])
i += 1
j += 1
return res
temp = cross(arr1,arr2)
res = cross(temp,arr3)
return res
##############1004. 最大连续1的个数 III
class Solution(object):
def longestOnes(self, nums, k):
# 指针,起点
i,j = 0,0
z_cnt = k
res = -1
while j < len(nums):
if nums[j] == 0: z_cnt -= 1
while z_cnt < 0:
if nums[i] == 0:
z_cnt += 1
i += 1
res = max(res,(j-i+1))
j += 1
return res
###########################179. 最大数
# 给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
# 注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数
# 输入:nums = [3,30,34,5,9]
# 输出:"9534330"
# 变相的排序算法
# 之前是如果x>y--->交换x,y
# 现在如果 x+y < y+x,交换x,y
# 可以直接用冒泡排序
# 1. def bubbleSort(arr):
# n = len(arr)
# for i in range(n):
# for j in range(n-i-1):
# if arr[j] > arr[j+1]:
# arr[j],arr[j+1] = arr[j+1],arr[j]
# print(arr)
# # 冒泡排序时间复杂度(O(n^2))
# 本题解法
# class Solution:
# def largestNumber(self, nums: List[int]) -> str:
# n = len(nums)
# nums = list(map(str, nums))
# for i in range(n):
# for j in range(i + 1, n):
# if nums[i] + nums[j] < nums[j] + nums[i]:
# nums[i], nums[j] = nums[j], nums[i]
#
# return str(int("".join(nums)))
############ 四数之和
class Solution:
def fourSum(self, nums,target):
quadruplets = list()
if not nums or len(nums) < 4:
return quadruplets
nums.sort()
length = len(nums)
for i in range(length - 3):
if i > 0 and nums[i] == nums[i - 1]:
continue
# if nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target:
# break
# if nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target:
# continue
for j in range(i + 1, length - 2):
if j > i + 1 and nums[j] == nums[j - 1]:
continue
# if nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target:
# break
# if nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target:
# continue
left, right = j + 1, length - 1
while left < right:
total = nums[i] + nums[j] + nums[left] + nums[right]
if total == target:
quadruplets.append([nums[i], nums[j], nums[left], nums[right]])
while left < right and nums[left] == nums[left + 1]:
left += 1
left += 1
while left < right and nums[right] == nums[right - 1]:
right -= 1
right -= 1
elif total < target:
left += 1
else:
right -= 1
return quadruplets
##############最长回文串/最长回文子串
class Solution(object):
def longestPalindrome(self, s):
# 双指针,中心扩散法(马拉车)
# 以每个字符串为中心,分别计算其长度
# right 包含在内
if not s or len(s) == 1:
return s
max_len = 1
res = s[0]
for i in range(1,len(s)): # 要考虑奇数 偶数的问题
left ,right = i,i
while left > 0 and s[left-1] == s[i]:
left -= 1
while right < len(s) - 1 and s[right+1] == s[i]:
right += 1
while left > 0 and right < len(s)-1 and s[left-1] == s[right+1]: #只要以中间为界限,左右如果相同,则进行相应的指针偏移
left -= 1
right += 1
if max_len < (right - left + 1):
max_len = right - left + 1
res = s[left:left+max_len]
return res
############# 跳跃游戏 I
class Solution(object):
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
if len(nums) == 1: return True
max_steps = 0
i = 0
while i <= max_steps: # max_step在for循环里是无法改变的
if i + nums[i] > max_steps:
max_steps = i + nums[i]
if max_steps >= len(nums) - 1:
return True
i += 1
return False
###############45. 跳跃游戏 II (左闭右开区间)
# 双指针,贪心算法,动态规划
# 思想就一句话:每次在上次能跳到的范围(end)内选择一个能跳的最远的位置(也就是能跳到max_far位置的点)
# 作为下次的起跳点 !
class Solution(object):
def jump(self, nums):
start = 0 # start end 则是当前的一个窗口
end = 1 # end 之所以是1,是因为当前窗口默认为第一个值
ans = 0 # 跳跃次数
while end < len(nums):
max_pos = 0
for i in range(start,end): # 可选区间
max_pos = max(max_pos,i + nums[i]) # 最大步长 # i 就是当前选择的点
# 更新 start end ans
start = end # 这一轮的start 就是上一轮的 end
end = max_pos + 1 # 结尾+1,是因为最后的一个数不用遍历
ans += 1
return ans
########################2. 两数相加
# Definition for singly-linked list.
class ListNode(object):
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
dummy = ListNode(-1)
pre = dummy
high = 0
while l1 and l2:
val = (l1.val + l2.val + high) % 10
high = (l1.val + l2.val + high) // 10
node = ListNode(val)
pre.next = node
pre = pre.next
l1 = l1.next
l2 = l2.next
while l1:
val = (l1.val + high) % 10
high = (l1.val + high) // 10
node = ListNode(val)
pre.next = node
pre = pre.next
l1 = l1.next
while l2:
val = (l2.val + high) % 10
high = (l2.val + high) // 10
node = ListNode(val)
pre.next = node
pre = pre.next
l2 = l2.next
if high:
pre.next = ListNode(high)
return dummy.next
#################无重复字符的最长子串
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
i,j = 0,0 # 双指针
max_len = 0
for i in range(len(s)):
j = i
temp = set()
while j < len(s) and s[j] not in temp:
temp.add(s[j])
j += 1
max_len = max(max_len,j-i)
return max_len
# 改进版2
# 3. 无重复字符的最长子串
class Solution(object):
def lengthOfLongestSubstring(self, s):
left = 0
right = 0
max_len = 0
temp = []
while right < len(s):
# 需要滑动左窗口,即不满足条件时
if s[right] not in temp:
temp.append(s[right])
else:
while s[left] != s[right]:
temp.remove(s[left])
left += 1
temp.remove(s[left])
left += 1
temp.append(s[right])
# 标准结局
max_len = max(max_len,right - left + 1)
right += 1
return max_len
########### 无重复字符的最长子串
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
i,j = 0,0
max_len = 0
while j < len(s):
while j < len(s) and len(set(s[i:j+1])) == len(s[i:j+1]): j+= 1 # 无重复
max_len = max(max_len,j-i)
i += 1
return max_len
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
i = 0
j = 0
max_len = 0
while j <= len(s) - 1:
if len(set(s[i:j+1])) == j - i + 1:
max_len = max(max_len,(j-i+1))
j += 1
if len(set(s[i:j+1])) != j - i + 1:
i += 1
return max_len
###################剑指 Offer 04. 二维数组中的查找
class Solution(object):
def findNumberIn2DArray(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
i = len(matrix) - 1
j = 0
while i >= 0 and j < len(matrix[0]):
if matrix[i][j] < target: j += 1
elif matrix[i][j] > target: i -=1
else:
return True
return False
##########################7. 整数反转
class Solution(object):
def reverse(self, x):
"""
:type x: int
:rtype: int
"""
new = 0
fuhaofu = 0
if x < 0:
x = - x
fuhaofu = 1
while x :
yu = x % 10
x = x // 10
new = new * 10 + yu
if fuhaofu:
new = - new
if new < - 2**31 or new > 2**31 - 1:
return 0
return new
###################### 9. 回文数
class Solution(object):
def isPalindrome(self, x):
"""
:type x: int
:rtype: bool
"""
if x < 0 : return False
x = str(x)
i = 0
j = len(x) - 1
while i < j :
if x[i] == x[j]:
i += 1
j -= 1
else:
return False
return True
############### 剑指 Offer 42. 连续子数组的最大和
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
max_num = -9999
dp = [0] * len(nums)
for i in range(len(nums)):
dp[i] = max(dp[i-1] + nums[i],nums[i])
max_num = max(max_num,dp[i])
return max_num
#######################剑指 Offer 11. 旋转数组的最小数字
class Solution(object):
def minArray(self, numbers):
"""
:type numbers: List[int]
:rtype: int
"""
left = 0
right = len(numbers) - 1
while left < right:
mid = left + (right - left) // 2
if numbers[mid] > numbers[right]:
left = mid + 1
elif numbers[mid] < numbers[right]:
right = mid
else:
right -= 1
return numbers[left]
#####################26. 删除有序数组中的重复项(快慢指针)
class Solution(object):
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums: return 0
slow,fast = 1,1
while fast < len(nums):
if nums[fast] != nums[fast-1]:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
##################### 78. 子集
# backtrack(路径,选择列表){
# //结束条件
# 将中间结果加入结果集
# for 选择 in 选择列表:
# //做选择,并将该选择从选择列表中移除
# 路径.add(选择)
# backtrack(路径,选择列表)
# //撤销选择
# 路径.remove(选择)
# }
class Solution(object):
def subsets(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
res = []
n = len(nums)
def helper(i,temp):
res.append(temp)
for j in range(i,n):
helper(j+1,temp+[nums[j]])
helper(0,[])
return res
############ 剑指 Offer 57 - II. 和为s的连续正数序列
class Solution(object):
def findContinuousSequence(self, target):
"""
:type target: int
:rtype: List[List[int]]
"""
i,j = 1,1
res = []
while i <= target//2:
temp_sum = sum(range(i,j))
if temp_sum < target:
j += 1
elif temp_sum > target:
i += 1
else:
res.append(list(range(i,j))) # 返回的数据并包括j
i += 1
return res
class Solution(object):
def findContinuousSequence(self, target):
"""
:type target: int
:rtype: List[List[int]]
"""
left = 1
right = 1
res = []
while right <= target//2 + 1:
summ = sum(range(left,right+1))
if summ < target : right += 1
elif summ > target : left += 1
else:
res.append(list(range(left,right+1)))
left += 1
right += 1
return res
# 剑指 Offer 61. 扑克牌中的顺子
class Solution(object):
def isStraight(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
nums = sorted(nums)
vote = 1
min_num = 999
for num in nums:
if num != 0:
min_num = num
break
for i in range(1,len(nums)):
if nums[i] == nums[i-1] and nums[i-1] != 0: return False
if nums[i] != nums[i-1] or nums[i-1] == 0:
vote += 1
return max(nums) - min_num < vote
# 剑指 Offer 28. 对称的二叉树
# Definition for a binary tree node.
class Solution(object):
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
def is_mirror(p,q):
if not p and not q : return True
if not p and q or not q and p or p.val != q.val: return False
return is_mirror(p.left,q.right) and is_mirror(p.right,q.left)
return is_mirror(root,root)
# 159. 至多包含两个不同字符的最长子串
class Solution(object):
def lengthOfLongestSubstringTwoDistinct(self, s):
"""
:type s: str
:rtype: int
"""
i = 0
max_len = 0
for i in range(len(s)):
j = i
temp = set()
while j < len(s):
temp.add(s[j]) # 先后关系
if len(temp) <= 2:
j += 1
else:
break
max_len = max(max_len,j-i)
return max_len
####################解答2
# 至多包含两个不同字符的最长子串
class Solution(object):
def lengthOfLongestSubstringTwoDistinct(self, s):
"""
:type s: str
:rtype: int
"""
i,j = 0,0
max_len = 0
while j < len(s):
while j < len(s) and len(set(s[i:j+1])) <= 2 : j += 1 # 不包含最后一个数字
max_len = max(max_len,j-i)
i += 1
return max_len
############ 零钱兑换
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
dp = [0] + [10001] * amount # 首先设置dp[0] = 0 , 这是为了满足amount 刚好等于coin的情况 , 容量大小为 amount + 1
for coin in coins:
for j in range(coin,amount+1):
dp[j] = min(dp[j],dp[j-coin]+1)
return dp[-1] if dp[-1] != 10001 else -1
#################################### 983. 最低票价
class Solution(object):
def mincostTickets(self, days, costs):
"""
:type days: List[int]
:type costs: List[int]
:rtype: int
"""
dp = [0 for _ in range(days[-1] + 1)] # 游玩最大的天数
days_index = 0 # 设定一个days指标,标记应该处理 days 数组中哪一个元素
for i in range(1,len(dp)):
if i != days[days_index]: # 若当前天数不是待处理天数,则其花费费用和前一天相同
dp[i] = dp[i-1]
else:
dp[i] = min(dp[max(0,i-1)] + costs[0]
,dp[max(0,i-7)] + costs[1]
,dp[max(0,i-30)] + costs[2])
days_index += 1
return dp[-1]
# 两个数组的交集
class Solution(object):
def intersect(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: List[int]
"""
nums1 = sorted(nums1)
nums2 = sorted(nums2)
l1 = 0
l2 = 0
res = []
while l1 < len(nums1) and l2 < len(nums2):
if nums1[l1] < nums2[l2]: l1 += 1
elif nums1[l1] > nums2[l2]: l2 += 1
else:
res.append(nums1[l1])
l1 += 1
l2 += 1
return res
# 350. 两个数组的交集 II
class Solution(object):
def intersect(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: List[int]
"""
nums1 = sorted(nums1)
nums2 = sorted(nums2)
l1 = 0
l2 = 0
res = []
while l1 < len(nums1) and l2 < len(nums2):
if nums1[l1] < nums2[l2]: l1 += 1
elif nums1[l1] > nums2[l2]: l2 += 1
else:
res.append(nums1[l1])
l1 += 1
l2 += 1
return res
# 11. 盛最多水的容器
# 双指针,贪心算法
# if x > y
# min(x,y) * h 若移动大的一边x,即使之后找到更大的值z,最后得到的面积也是min(z,y) * h = y*h
# min(x,y) * h 若移动小的一边y,如果之后找更大的值z,最后得到的面积则是min(x,z) * h = x * h
# 显然则是移动小的一边
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
left = 0
right = len(height) - 1
max_area = 0
while left < right:
max_area = max(max_area,min(height[left],height[right]) * (right - left))
if height[left] < height[right]:
left += 1
else:
right -= 1
return max_area
# 1062. 最长重复子串
class Solution(object):
def longestRepeatingSubstring(self, s):
"""
:type s: str
:rtype: int
"""
max_sub_length = 0
dp = [[0 for _ in range(len(s))] for _ in range(len(s))]
for i in range(len(s)):
for j in range(len(s)):
if i == 0 or j == 0:
if s[i] == s[j] and i != j:
dp[i][j] = 1
else:
dp[i][j] = 0
else:
if s[i] == s[j] and i != j:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = 0
max_sub_length = max(max_sub_length,dp[i][j])
return max_sub_length
# 718. 最长重复子数组
class Solution(object):
def findLength(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: int
"""
res = 0
dp = [[0 for _ in range(len(nums2))] for _ in range(len(nums1))]
for i in range(len(nums1)):
for j in range(len(nums2)):
if i == 0 or j == 0:
if nums1[i] == nums2[j]:
dp[i][j] = 1
else:
dp[i][j] = 0
else:
if nums1[i] == nums2[j]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = 0
res = max(res,dp[i][j])
return res
# 面试题 17.16. 按摩师
class Solution(object):
def massage(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums) == 0: return 0
if len(nums) == 1: return nums[0]
if len(nums) == 2: return max(nums[0],nums[1])
dp = [0 for _ in range(len(nums))]
dp[0] = nums[0]
dp[1] = max(nums[0],nums[1])
dp[2] = max(nums[1],nums[0] + nums[2])
for i in range(3,len(nums)):
dp[i] = max(dp[i-2] + nums[i],dp[i-1])
return dp[-1]
# 42. 接雨水
class Solution(object):
def trap(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums) == 0: return 0
max_value = 0
# 1. 找出柱子的最大高度
max_index = nums.index(max(nums))
# 2. 以最大高度为界,处理左半部分,满足高低的便能接到雨水
# for left in range(max_index): # 为什么没有跳出循环,当大于边界时不时跳出循环而是继续执行原有的循环
left = 0 # 左半边柱子当前最高的
for i in range(left,max_index+1):
if nums[left] > nums[i]:
max_value += (nums[left] - nums[i])
else:
left = i
# 3. 处理右半部分
# right 为右边柱子当前最高
right = len(nums) - 1
for j in range(right,max_index-1,-1):
if nums[right] > nums[j]:
max_value += (nums[right] - nums[j])
else:
right = j
return max_value
# 187. 重复的DNA序列
class Solution(object):
def findRepeatedDnaSequences(self, s):
"""
:type s: str
:rtype: List[str]
"""
i = 0
j = 9
dict = {}
res = set()
while j < len(s):
sub_string = s[i:j+1]
if sub_string not in dict:
dict[sub_string] = 1
else:
res.add(sub_string)
i += 1
j += 1
return list(res)
# 452. 用最少数量的箭引爆气球
class Solution(object):
def findMinArrowShots(self, points):
"""
:type points: List[List[int]]
:rtype: int
"""
# 排序 +贪心
points = sorted(points,key=lambda x : x[0])
arrow_cnt = 1
curr_right = points[0][1]
for i in range(1,len(points)):
next_left = points[i][0]
next_right = points[i][1]
if next_left <= curr_right: # 能射穿气球,更新
if next_right < curr_right: # 当下一个气球的右边端点《该气球的右端点时,需要更新公共端点
curr_right = next_right
else:
curr_right = points[i][1]
arrow_cnt += 1
return arrow_cnt
# 435. 无重叠区间
class Solution(object):
def eraseOverlapIntervals(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: int
"""
intervals = sorted(intervals,key=lambda x: x[0])
cancle_cnt = 0
curr_right = intervals[0][1]
for i in range(1,len(intervals)):
next_left = intervals[i][0]
if curr_right > next_left: # 移除重叠区间,不需要更新右端点
if curr_right > intervals[i][1]: # 更新右端点,判断是否立下一个右端点为当前的右端点
curr_right = intervals[i][1]
cancle_cnt += 1
else: # 不移除重叠区间,右端点不需要更新
curr_right = intervals[i][1]
return cancle_cnt
# # 567. 字符串的排列
# 主要统计滑动窗口的长度,以及相应字符串的数量
class Solution(object):
def checkInclusion(self, s1, s2):
"""
:type s1: str
:type s2: str
:rtype: bool
"""
# 统计s1的字段长度
len_s1 = len(s1)
i = 0
j = i + len_s1 - 1
def cnt_s(s1):
dict_s1 = {}
for i in range(len(s1)):
if s1[i] not in dict_s1:
dict_s1[s1[i]] = 1
else:
dict_s1[s1[i]] += 1
return dict_s1
dict_s1 = cnt_s(s1)
while j < len(s2):
temp = s2[i:j+1]
dict_s2 = cnt_s(temp)
if dict_s1 == dict_s2:
return True
i += 1
j += 1
return False
# 剑指 Offer 38. 字符串的排列
# 回溯法
class Solution:
def permutation(self, s: str) -> List[str]:
c, res = list(s), []
def dfs(x):
if x == len(c) - 1:
res.append(''.join(c)) # 添加排列方案
return
dic = set()
for i in range(x, len(c)):
if c[i] in dic: continue # 重复,因此剪枝
dic.add(c[i])
c[i], c[x] = c[x], c[i] # 交换,将 c[i] 固定在第 x 位
dfs(x + 1) # 开启固定第 x + 1 位字符
c[i], c[x] = c[x], c[i] # 恢复交换
dfs(0)
return res
# 1. 终止条件
# 2. 剪枝
# 3. 倒退一步
class Solution(object):
def permutation(self, s):
"""
:type s: str
:rtype: List[str]
"""
res = []
s = list(s)
def dfs(x):
if x == len(s):
res.append(''.join(s))
return
dictt = {}
for i in range(x,len(s)): # x可以理解为放置字符串的位置
if s[i] in dictt:
continue
else:
dictt[s[i]] = 1
s[x],s[i] = s[i],s[x]
dfs(x+1)
s[i],s[x] = s[x],s[i]
dfs(0)
return res
# 全排列(数字)
class Solution:
def permute(self, nums) :
c, res = nums, []
def dfs(x):
if x == len(c):
# 后面的交换会影响res.append的c 因此为了不受后面的影响,应造一个空间,注意要进行深拷贝(若是字符串则没有这个影响)
tmp = [ci for ci in c]
res.append(tmp) # 添加排列方案
return
dic = set()
for i in range(x, len(c)):
if c[i] in dic: continue # 重复,因此剪枝
dic.add(c[i])
c[i], c[x] = c[x], c[i] # 交换,将 c[i] 固定在第 x 位
dfs(x + 1) # 开启固定第 x + 1 位字符
c[i], c[x] = c[x], c[i] # 恢复交换
dfs(0)
return res
# 地下城游戏
class Solution:
def calculateMinimumHP(self, dungeon):
n, m = len(dungeon), len(dungeon[0])
BIG = 10**9
dp = [[BIG] * (m + 1) for _ in range(n + 1)]
dp[n][m - 1] = dp[n - 1][m] = 1
for i in range(n - 1, -1, -1):
for j in range(m - 1, -1, -1):
minn = min(dp[i + 1][j], dp[i][j + 1])
dp[i][j] = max(minn - dungeon[i][j], 1)
return dp[0][0]
# 64. 最小路径和
class Solution(object):
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
m = len(grid)
n = len(grid[0])
dp = [[10**9]*(n+1) for j in range(m+1)]
dp[m][n-1] = 0
dp[m-1][n] = 0
for i in range(m-1,-1,-1):
for j in range(n-1,-1,-1):
dp[i][j] = min(dp[i+1][j],dp[i][j+1]) + grid[i][j]
return dp[0][0]
# 62. 不同路径
class Solution(object):
def uniquePaths(self, m, n):
"""
:type m: int
:type n: int
:rtype: int
"""
dp = [[0] * n for _ in range(m)]
for i in range(m):
for j in range(n):
if i == 0 or j == 0:
dp[i][j] = 1
else:
dp[i][j] = dp[i-1][j]+ dp[i][j-1]
return dp[-1][-1]
# 473. 火柴拼正方形
class Solution(object):
def makesquare(self, matchsticks):
"""
:type matchsticks: List[int]
:rtype: bool
"""
matchsticks = sorted(matchsticks,reverse=True)
if sum(matchsticks) % 4 != 0: return False
if len(matchsticks) < 4 : return False
buckets = [0] *4
edge = sum(matchsticks) // 4
def dfs(x):
if x == len(matchsticks):
return True
for i in range(len(buckets)):
if matchsticks[x] + buckets[i] > edge: # 剪枝
continue
buckets[i] += matchsticks[x]
if dfs(x+1): return True # 放置下一根火柴看是否能放得下
buckets[i] -= matchsticks[x] # 如果放不下下一根火柴,则说明之前的放置规则有误,即取消前一步的操作
return False
return dfs(0)
# 424. 替换后的最长重复字符
# 维护一个滑动窗口,滑动窗口内的即是满足条件的数据
class Solution(object):
def characterReplacement(self, s, k):
"""
:type s: str
:type k: int
:rtype: int
"""
word_cnt = {}
max_len = 0
left = 0
right = 0 # right包含当前数据
while right < len(s):
if s[right] not in word_cnt:
word_cnt[s[right]] = 1
else:
word_cnt[s[right]] += 1
if max(word_cnt.values()) + k < right - left + 1: # 调整窗口的条件
word_cnt[s[left]] -= 1
left += 1
max_len = max(max_len,right-left+1)
right += 1
return max_len
# leetcode 198. 打家劫舍
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums) == 1: return nums[0]
if len(nums) == 2: return max(nums[0],nums[1])
dp = [0] * len(nums)
dp[0] = nums[0]
dp[1] = max(nums[0],nums[1])
for i in range(2,len(nums)):
dp[i] = max(dp[i-1] , dp[i-2] + nums[i])
return dp[-1]
# 剑指 Offer 52. 两个链表的第一个公共节点
# 当headA 和 headB 无公共节点时,None即是它们的公共节点
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
# headA 走到尽头时,回到headB的起点(headB的起点,不曾改变过,还是最初的样子)
node1,node2 = headA,headB
while headA!=headB:
if headA:
headA = headA.next
else:
headA = node2
if headB:
headB = headB.next
else:
headB = node1
return headA
# 剑指 Offer 53 - I. 在排序数组中查找数字 I
# 主要利用二分查找法
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
if len(nums) == 0 : return 0
index = self.binary_search(nums,target)
if index == 'not exists': return 0 # 不存在于数组中(这样排除返回的索引可能是0)
left = index
right = index
while left > 0 and nums[left-1] == nums[index]: left -= 1
while right < len(nums) - 1 and nums[right+1] == nums[index]: right += 1
return right - left + 1
def binary_search(self,nums,target):
left = 0
right = len(nums) - 1
while left <= right: # 注意[1] 1 的情况
mid = left + (right-left)//2
if nums[mid] > target:
right = mid - 1 # 左右边界相应的偏移
elif nums[mid] < target:
left = mid + 1
else:
return mid
return 'not exists'
# 剑指 Offer 40. 最小的k个数
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
def quick_sort(arr,left,right):
pivot = left
i,j = left,right
if i >= j : return
while i < j :
while i < j and arr[j] >= arr[pivot]: j -= 1
while i < j and arr[i] <= arr[pivot]: i += 1
arr[i],arr[j] = arr[j],arr[i]
arr[pivot],arr[i] = arr[i],arr[pivot]
quick_sort(arr,left,i-1)
quick_sort(arr,i+1,right)
return arr
left = 0
right = len(arr) - 1
return quick_sort(arr,left,right)[:k]
# V2(第二版)
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
def quick_sort(left,right,arr):
pivot = left
i = left # left, right 为边界值
j = right
if i >= j : return # 递归结束条件(i,j相遇)
while i < j: # i < k 否则会边界溢出
while i < j and arr[j] >= arr[pivot]: j -= 1
while i < j and arr[i] <= arr[pivot] : i += 1
arr[i],arr[j] = arr[j],arr[i]
arr[pivot],arr[i] = arr[i],arr[pivot]
quick_sort(left,i-1,arr)
quick_sort(i+1,right,arr)
return arr
left = 0
right = len(arr) - 1
return quick_sort(left,right,arr)[:k]
# # 剑指 Offer 49. 丑数 /*在多想想*/
那就是记录每个丑数是否已经被乘2, 乘3, 乘5了,
具体的做法是设置3个索引a, b, c,分别记录前几个数已经被乘2, 乘3, 乘5了
class Solution(object):
def nthUglyNumber(self, n):
"""
:type n: int
:rtype: int
"""
dp = [0] * n
dp[0] = 1
index1,index2,index3 = 0,0,0
for i in range(1,n):
temp_index1 = dp[index1] * 2
temp_index2 = dp[index2] * 3
temp_index3 = dp[index3] *5
dp[i] = min(dp[index1]*2,dp[index2]*3,dp[index3]*5)
if temp_index1 == dp[i]: index1 += 1
if temp_index2 == dp[i]: index2 += 1
if temp_index3 == dp[i]: index3 += 1
return dp[-1]
# 263. 丑数
class Solution(object):
def isUgly(self, n):
"""
:type n: int
:rtype: bool
"""
if n == 0 : return False
while n % 2 == 0:
n /= 2
while n % 3 == 0:
n /= 3
while n % 5 == 0:
n/= 5
return n == 1
# 313. 超级丑数,用数组来管理,(primes[i],index[i] 都表示在规定队列中的一个数而已)
class Solution(object):
def nthSuperUglyNumber(self, n,primes):
"""
:type n: int
:rtype: int
"""
dp = [0] * n
dp[0] = 1
m = len(primes)
indexs = [0] * m # 多指针
for i in range(1,n):
dp[i] = min(dp[indexs[j]]*primes[j] for j in range(m))
for j in range(m):
if dp[indexs[j]] *primes[j] == dp[i]:
indexs[j] += 1
return dp[-1]
# 剑指 Offer 50. 第一个只出现一次的字符
class Solution(object):
def firstUniqChar(self, s):
"""
:type s: str
:rtype: str
"""
dict = {}
for i in range(len(s)):
if s[i] not in dict:
dict[s[i]] = 1
else:
dict[s[i]] += 1
for i in range(len(s)):
if dict[s[i]] == 1:
return s[i]
return " "
# 剑指 Offer 45. 把数组排成最小的数
class Solution(object):
def minNumber(self, nums):
"""
:type nums: List[int]
:rtype: str
"""
for j in range(len(nums)):
for i in range(len(nums) - 1, j, -1):
if str(nums[i-1]) + str(nums[i]) > str(nums[i]) + str(nums[i-1]):
nums[i],nums[i-1] = nums[i-1],nums[i]
return ''.join([str(num) for num in nums])
# 面试题 16.11. 跳水板
class Solution(object):
def divingBoard(self, shorter, longer, k):
"""
:type shorter: int
:type longer: int
:type k: int
:rtype: List[int]
"""
if k == 0 : return []
if shorter == longer: return [shorter * k]
res = []
for i in range(k,-1,-1):
temp = shorter*i + longer* (k-i)
res.append(temp)
return res
# 剑指 Offer 14- I. 剪绳子
class Solution(object):
def cuttingRope(self, n):
"""
:type n: int
:rtype: int
"""
if n <=2 : return 1
if n == 3 : return 2
dp = [0] * (n+1)
dp[1] = 1
dp[2] = 2
dp[3] = 3
for i in range(4,n+1):
for j in range(i//2+1):
dp[i] = max(dp[i],dp[j] * dp[i-j]) # 存储的是绳子的最大乘积
return dp[-1]
class Solution(object):
def cuttingRope(self, n):
"""
:type n: int
:rtype: int
"""
if n <= 2: return 1
if n == 3: return 2
dp = [0] * (n + 1) # n + 1
dp[1] = 1 # 储存的是子最优化的长度(即子,可分可不分)
dp[2] = 2
dp[3] = 3
for i in range(4,n+1):
for j in range(1,i//2+1):
dp[i] = max(dp[i],dp[j] * dp[i-j])
return dp[-1]
# 128. 最长连续序列
class Solution(object):
def longestConsecutive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
hashh = {}
max_len = 0
for num in nums:
if num not in hashh:
hashh[num] = 1
else:
hashh[num] += 1
for num in set(nums): # 数组是无序的
left = num
right = num
# 判断此数是否是连续子序列的头部,如果不是则遍历下个数字
if not hashh.__contains__(right-1):
while hashh.__contains__(right+1): # 不满足时,计算序列长度,并进行下一轮的循环
right = right + 1
max_len = max(max_len,right - left + 1)
return max_len
class Solution(object):
def longestConsecutive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums) == 0: return 0 # 特殊值
nums = list(sorted(set(nums))) # 去重
left = 0
right = 1
max_window = 1
while right < len(nums):
if nums[right] - nums[left] + 1 == right - left + 1:
max_window = max(max_window,right - left+1)
right += 1
else:
left = right
return max_window
# 15. 三数之和 (重点是去重)
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums = sorted(nums)
res = []
for i in range(len(nums)):
if(i>0 and nums[i]==nums[i-1]): # 外部去重-1, -1, 0, 1, 2], -1, 0, 1, 2] 出现重复,这里是去重
continue
target = 0 - nums[i]
left = i + 1
right = len(nums) - 1
while left < right:
if nums[left] + nums[right] > target:
right = right - 1
elif nums[left] + nums[right] < target:
left = left +1
else:
res.append((nums[i],nums[left],nums[right]))
while(left<right and nums[left]==nums[left+1]): # 内部去重L,R
left=left+1
while(left<right and nums[right]==nums[right-1]):
right=right-1
left += 1
right -= 1
return res
# 647. 回文子串
class Solution(object):
def countSubstrings(self, s):
"""
:type s: str
:rtype: int
"""
res = len(s)
for i in range(len(s)):
left,right = i,i
while left > 0 and s[left-1] == s[i]:
left -= 1
res += 1
# while right < len(s) - 1 and s[right+1] == s[i]:
# right += 1
while left > 0 and right < len(s) - 1 and s[left-1] == s[right+1]:
left -= 1
right += 1
res += 1
return res
# 17. 电话号码的字母组合 (栈 + 回溯)
# //对于当前输入的第index号数字(digits[index]),
# 枚举其对应的所有字母(M[digits[index]][i])
class Solution(object):
def letterCombinations(self, digits):
"""
:type digits: str
:rtype: List[str]
"""
if not digits: return []
M = {
"2": "abc",
"3": "def",
"4": "ghi",
"5": "jkl",
"6": "mno",
"7": "pqrs",
"8": "tuv",
"9": "wxyz",
}
current = []
res = []
def dfs(x):
if x == len(digits):
res.append(''.join(current))
return
num = digits[x]
for letter in M[num]:
print('letter: ',letter)
current.append(letter)
dfs(x+1)
current.pop()
dfs(0)
return res
# 20. 有效的括号
class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool
"""
if len(s) < 1: return True
# 右半边符号多的情况
dictt = {')':'(','}':'{',']':'['}
temp = ['?'] # temp[-1] 使栈不为空
for letter in s:
if letter not in dictt: # 若出现符号的右半边则要判断是否能抵消
temp.append(letter)
else:
if temp[-1] == dictt[letter]: temp.pop()
else: return False # 一旦出现不匹配情况则返回False,']'
return len(temp) == 1
# 34. 在排序数组中查找元素的第一个和最后一个位置
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
if len(nums) < 1: return [-1,-1]
left = 0
right = len(nums) - 1
while left < len(nums) and nums[left] != target:left += 1
while right >= 0 and nums[right] != target: right -= 1
if left == len(nums) : left = -1
if right == -1 : right = -1
return[left,right]
# 19. 删除链表的倒数第 N 个结点
# 返回head,删除第一个元素的时候会有问题
class ListNode(object):
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
if not head: return
pre = ListNode(-1)
pre.next = head
dummy = pre
curr = pre
for i in range(n):
curr = curr.next
while curr.next:
dummy = dummy.next
curr = curr.next
dummy.next = dummy.next.next
return pre.next
# 21. 合并两个有序链表
from typing import List
class ListNode(object):
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
dummy = ListNode(-1)
curr = dummy
while l1 and l2 :
if l1.val <= l2.val:
curr.next = l1
l1 = l1.next
curr = curr.next
else:
curr.next = l2
l2 = l2.next
curr = curr.next
if l1:
curr.next = l1
if l2:
curr.next = l2
return dummy.next
# 33. 搜索旋转排序数组
# 「旋转数组中找目标值」 转化成了 「有序数组中找目标值」
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
left = 0
right = len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
# if nums[mid] == target: return mid
# 若nums[mid] 和 target不在同一侧时,将他们转化为同一侧(涉及到的三个变量Nums[0],target,nums[mid])
# 最后转化为在有序数组中找目标值
# 先判断target,nums[mid]分别在那侧,从而进行转化
if target >= nums[0]: #说明target在左侧
if nums[mid] < nums[0]: # 说明nums[mid]在右侧,设想若是在一条直线上,mid所在位置的nums[mid]的大小,从而进一步比较nums[mid]与target的大小
nums[mid] = 2**10
else:
if nums[mid] >= nums[0]:
nums[mid] = -2**10
if nums[mid] > target:
right = mid - 1
elif nums[mid] < target:
left = mid + 1
else:
return mid
return -1
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
left = 0
right = len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if target >= nums[0]: # 关键是区分nus[mid] 和 target之间的位置关系,通过nums[0]进行比较
if nums[mid] < nums[0]:
nums[mid] = 2**10
else:
if nums[mid] >= nums[0]:
nums[mid] = -2**10
if nums[mid] > target:
right = mid - 1
elif nums[mid] < target:
left = mid + 1
else:
return mid
return -1
# 56. 合并区间
class Solution(object):
def merge(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: List[List[int]]
"""
if len(intervals) < 1: return []
if len(intervals) == 1 : return intervals
intervals = sorted(intervals,key = lambda x : x[0])
res = []
curr_left = intervals[0][0]
curr_right = intervals[0][1]
for i in range(len(intervals)-1):
next_left = intervals[i+1][0]
next_right = intervals[i+1][1]
if curr_right >= next_left: # 能合并(分两种情况,更新右端点,不更新右端点)
if curr_right < next_right: # 更新右端点的情况
curr_right = next_right
else:
res.append([curr_left,curr_right])
curr_left = next_left # 不可以合并区间,更新新的区间,却保留上一个合并区间
curr_right = next_right
if i == len(intervals) - 2: res.append([curr_left,curr_right]) # 最后更新的一个区间没有保存
# res.append([curr_left,curr_right])
return res
class Solution(object):
def merge(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: List[List[int]]
"""
intervals = sorted(intervals,key=lambda b:b[0])
res = []
left = intervals[0][0]
right = intervals[0][1]
for i in range(1,len(intervals)):
if right >= intervals[i][0]: # 这里的条件是递进,而不是and
if right < intervals[i][1]:
right = intervals[i][1]
else:
res.append([left,right])
left = intervals[i][0]
right = intervals[i][1]
res.append([left,right])
return res
# 我们只要递归调用 inorder(root.left) 来遍历 \textit{root}root 节点的左子树,然后将 \textit{root}root 节点的值加入答案,再递归调用inorder(root.right) 来遍历 \textit{root}root 节点的右子树即可,递归终止的条件为碰到空节点。
# 94. 二叉树的中序遍历
class Solution(object):
def __init__(self) -> None:
super().__init__()
self.res = []
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root : return
self.inorderTraversal(root.left)
self.res.append(root.val)
self.inorderTraversal(root.right)
return self.res
# 剑指 Offer 04. 二维数组中的查找
class Solution(object):
def findNumberIn2DArray(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
i = len(matrix) - 1
j = 0
while i >= 0 and j < len(matrix[0]):
if matrix[i][j] > target : i -= 1
elif matrix[i][j] <target : j += 1
else: return True
return False
# 剑指 Offer 56 - I. 数组中数字出现的次数
class Solution(object):
def singleNumbers(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
dictt = {}
res = []
for num in nums:
if num not in dictt:
dictt[num] = 1
else:
dictt[num] = 0
for keyy in dictt:
if dictt[keyy] == 1:
res.append(keyy)
return res
# Definition for singly-linked list.
# 剑指 Offer 25. 合并两个排序的链表
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
dummy = ListNode(-1)
curr = dummy
while l1 and l2:
if l1.val < l2.val:
curr.next = l1
l1 = l1.next
curr = curr.next
else:
curr.next = l2
l2 = l2.next
curr = curr.next
if l1:
curr.next = l1
if l2:
curr.next = l2
return dummy.next
# 剑指 Offer 26. 树的子结构
class Solution(object):
def isSubStructure(self, A, B):
"""
:type A: TreeNode
:type B: TreeNode
:rtype: bool
"""
if not A or not B : return False # 特例处理
def recur(A,B):
if not B : return True # 递归终止条件,当B遍历完了
if not A or A.val != B.val : return False # 递归终止条件,当A遍历完了或A值不等于B值时
return recur(A.left,B.left) and recur(A.right,B.right)
return recur(A,B) or self.isSubStructure(A.left,B) or self.isSubStructure(A.right,B)
# recur() 函数相当于只是单纯的判断是否是子结构,相当于递归结束的一个判断
# return recur(A,B) or recur(A.left,B) or recur(A.right,B)
# 能判断B树是A树左子树的子结构,但并没有完全递归到,万一B树是A树左子树的左子树的子结构呢?
class Solution(object):
def isSubStructure(self, A, B):
"""
:type A: TreeNode
:type B: TreeNode
:rtype: bool
"""
if not A or not B : return False
def is_Same(A,B):
if not B: return True
if not A or A.val != B.val: return False
# 如果A,B 都不为空,且头节点都相同
return is_Same(A.left,B.left) and is_Same(A.right,B.right)
return is_Same(A,B) or self.isSubStructure(A.left,B) or self.isSubStructure(A.right,B)
# 剑指 Offer 27. 二叉树的镜像
class Solution(object):
def mirrorTree(self, root):
"""
:type root: TreeNode
:rtype: TreeNode
"""
if not root: return
temp = root.left
root.left = self.mirrorTree(root.right)
root.right = self.mirrorTree(temp)
return root
# 剑指 Offer 13. 机器人的运动范围 (到达目的地,往右走或者往下走)
class Solution(object):
def digitsum(self,n):
ans = 0
while n:
ans += n % 10
n //= 10
return ans
def movingCount(self, m, n, k):
vis = set([(0, 0)]) # 初始化(是否可达,将可达的格子记录在vis中,回溯到前一步是否可以到达)
for i in range(m):
for j in range(n):
if ((i - 1, j) in vis or (i, j - 1) in vis) and self.digitsum(i) + self.digitsum(j) <= k: # 递推法,可到达的范围
vis.add((i, j))
return len(vis)
class Solution(object):
def movingCount(self, m, n, k):
"""
:type m: int
:type n: int
:type k: int
:rtype: int
"""
def cal_sum(m,n):
summ = 0
while m :
yu = m % 10
m = m // 10
summ += yu
while n:
yu1 = n % 10
n = n // 10
summ += yu1
return summ
vias = set([(0,0)]) # 只是在列表外面加一个set,为了防止重复
for i in range(m):
for j in range(n):
if ((i-1,j) in vias or (i,j-1) in vias) and cal_sum(i,j) <= k :
vias.add((i,j))
return len(vias)
# 剑指 Offer 12. 矩阵中的路径
class Solution:
def exist(self, board, word):
def dfs(i, j, k):
if not 0 <= i < len(board) or not 0 <= j < len(board[0]) or board[i][j] != word[k]: return False # 剪枝(此路不通)
if k == len(word) - 1: return True # 此路已通
board[i][j] = '' # 这也算是其中剪枝的一种(表示这步已经走过,不能往回走,此路不通)
res = dfs(i + 1, j, k + 1) or dfs(i - 1, j, k + 1) or dfs(i, j + 1, k + 1) or dfs(i, j - 1, k + 1) # 接下来的一步该往哪里走(可以往四个方向走),返回结果,判断是否有走的通的
board[i][j] = word[k] # 还原网格(代表着此路不通,继续执行dfs(1,0,0))
return res
for i in range(len(board)):
for j in range(len(board[0])):
if dfs(i, j, 0): return True # 首先确定第一步该往哪里走
return False
# 从尾到头打印链表
class Solution(object):
def reversePrint(self, head):
"""
:type head: ListNode
:rtype: List[int]
"""
res = []
p = None # 指向新链表
while head:
q = head.next # 指向旧链表
head.next = p
p = head
head = q
while p:
res.append(p.val)
p = p.next
return res
# 剑指 Offer 29. 顺时针打印矩阵
# 先把最前面的元素提取了。然后将剩下元素逆时针90度,再依次循环进行。
class Solution(object):
def spiralOrder(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[int]
"""
res = []
while matrix:
res += matrix.pop(0)
matrix = list(zip(*matrix))[::-1] # 旋转矩阵
return res
# 剑指 Offer 29. 顺时针打印矩阵
# 根据题意,需要特判,对于空矩阵直接返回空数组。
# 接下来:
# 定义出二维数组的左右上下四个边界,left、right、top、bottom;
# 循环打印:
# 沿着top,从左向右打印,top++;
# 沿着right,从上向下打印,right--;
# 沿着bottom,从右向左打印,bottom++;
# 沿着left,从下向上打印,left++;
# 注:在沿着下边界和左边界打印时,要确保left <= right,top <= bottom。
class Solution(object):
def spiralOrder(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[int]
"""
if not matrix: return []
res = []
top = 0
right = len(matrix[0]) - 1
bottom = len(matrix) - 1
left = 0
while top <= bottom and left <= right:
for i in range(left,right+1):
res.append(matrix[top][i])
top += 1
if top > bottom: break # 否则会影响后续操作,做重复任务(内部消除边界对后面的影响,若没有这步,则可能出现top > bottom)
for i in range(top,bottom+1):
res.append(matrix[i][right])
right -= 1
if left > right: break # 否则会影响后续操作,做重复任务(内部消除边界对后面的影响)
for i in range(right,left-1,-1):
res.append(matrix[bottom][i])
bottom -= 1
for i in range(bottom,top-1,-1):
res.append(matrix[i][left])
left += 1
return res
# #剑指 Offer 07. 重建二叉树
class Solution(object):
def buildTree(self, preorder, inorder):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
if not preorder: return None
root = TreeNode(preorder[0])
root_index = preorder[0]
inorder_root_index = inorder.index(root_index)
left_tree_inorder = inorder[:inorder_root_index]
right_tree_inorder = inorder[inorder_root_index+1:]
left_tree_preorder = preorder[1:inorder_root_index+1]
right_tree_preorder = preorder[inorder_root_index+1:]
root.left = self.buildTree(left_tree_preorder,left_tree_inorder)
root.right = self.buildTree(right_tree_preorder,right_tree_inorder) # 这里一定不要写错
return root
# 剑指 Offer 16. 数值的整数次方
class Solution(object):
def myPow(self, x, n):
"""
:type x: float
:type n: int
:rtype: float
"""
if x== 0 : return 0
res = 1
if n < 0: x , n = 1/x , -n
while n :
if n & 1: res *= x # 判断 n & 1 二进制最右一位是否为 1 ;
x *= x
n >>= 1 # n 右移一位(可理解为删除最后一位)。
return res
# 剑指 Offer 18. 删除链表的节点
class Solution(object):
def deleteNode(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
dummy = ListNode(-1)
curr = dummy
dummy.next = head
while head:
if head.val != val:
head = head.next
curr = curr.next
else:
curr.next = curr.next.next
break
return dummy.next
# 华为2016校园招聘上机笔试题
# 输入包括多组测试数据。
# 每组输入第一行是两个正整数N和M(0 < N <= 30000,0 < M < 5000),分别代表学生的数目和操作的数目。
# 学生ID编号从1编到N。
# 第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩
# 接下来又M行,每一行有一个字符C(只取‘Q’或‘U’),和两个正整数A,B,当C为'Q'的时候, 表示这是一条询问操作,他询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少
# 当C为‘U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
# 此题坑人的地方有两处:
# 1,不止输入一组n m ;
# 2,AB之间,可能A>B
while True:
try:
NM = [int(i) for i in input().split(' ')]
N = NM[0]
M = NM[1]
scores = []
scores = [int(i) for i in input().split(' ')]
lines = []
for i in range(M):
line = [j for j in input().split(' ')]
lines.append(line)
res = []
for line in lines:
C = line[0]
A = int(line[1])
B = int(line[2])
if C == 'U':
scores[A-1] = B
if C == 'Q':
if A > B:
max_score = max(scores[B-1:A])
elif A < B:
max_score = max(scores[A-1:B])
else:
max_score = scores[A-1]
res.append(max_score)
for ress in res:
print(ress)
except:
break
# 253. 会议室 II
# 临界条件: 最早结束时间不能大于最早开始时间(最早结束时间小于开始时间,则只需要一个房间),否则都需要房间
# 利用小根堆
# 堆: 栈 + 排序
import heapq
class Solution(object):
def minMeetingRooms(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: int
"""
intervals = sorted(intervals,key=lambda k:k[0])
rooms = []
heapq.heappush(rooms,intervals[0][1])
for i in range(1,len(intervals)):
if rooms[0] < intervals[i][0]:
heapq.heappop(rooms)
heapq.heappush(rooms,intervals[i][1])
return len(rooms)
1002. 查找常用字符
class Solution(object):
def commonChars(self, A):
"""
:type words: List[str]
:rtype: List[str]
"""
res = []
key = set(A[0])
for k in key:
minimum = min(a.count(k) for a in A)
res += minimum*k
return res
# 14. 最长公共前缀
# #zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
# 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
class Solution(object):
def longestCommonPrefix(self, strs):
"""
:type strs: List[str]
:rtype: str
"""
res = ''
for i in zip(*strs):
if len(set(i)) == 1:
res += i[0]
else:
break
return res
# 剑指 Offer 09. 用两个栈实现队列
class CQueue(object):
def __init__(self):
self.A = []
self.B = []
def appendTail(self, value):
"""
:type value: int
:rtype: None
"""
self.A.append(value)
def deleteHead(self):
"""
:rtype: int
"""
if self.B : return self.B.pop()
if self.A:
while self.A:
self.B.append(self.A.pop())
return self.B.pop()
return -1
# 剑指 Offer 05. 替换空格
# 在python中,字符串是不可变对象,不能通过下标的方式直接赋值修改
# 要注意索引是不是包括0
class Solution(object):
def replaceSpace(self, s):
"""
:type s: str
:rtype: str
"""
# 特殊情况,都是空格
s = list(s)
# 1. 扩展空间
i = len(s) - 1
cnt = 0
while i >= 0:
if s[i] == ' ':
cnt += 1
i -= 1
ss = [' '] * (len(s) + 2*cnt)
# 2. 代替
i = len(ss) - 1 # 指向新空间的地址
j = len(s) - 1
while j >= 0 :
while j >= 0 and s[j] != ' ': # 找到第一个空格
ss[i] = s[j]
i -= 1
j -= 1
# 找到空格
while j >= 0 and s[j] == ' ':
ss[i] = '0'
ss[i-1] = '2'
ss[i-2] = '%'
i = i - 3
j = j - 1
# print('s: ',s)
# print('ss: ',ss)
return ''.join(ss)
# 剑指 Offer 32 - II. 从上到下打印二叉树 II
# 用队列实现的层序遍历
import collections
from typing import List
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def levelOrder(self, root):
res = [] # 存放最后的结果
queue = collections.deque()
# print(queue)
if not root:
return []
queue.append(root)
while queue:
tmp = [] # 存放每一层的结果
for _ in range(len(queue)): # 最外部一层的长度 len(queue)
root = queue.popleft() # 将最左边的元素取出一个元素(这里是把root取出来),从队列的一端出去
tmp.append(root.val)
if root.left:
queue.append(root.left) # 取出root的同时,把root的left,right 加进来,此时queue 的len 为2
if root.right:
queue.append(root.right)
res.append(tmp)
return res
# 剑指 Offer 50. 第一个只出现一次的字符
# 解法一(84,94)
# 使用哈希算法
# 解法二(62,26)
# 使用队列,利用先进先出的特点
import collections
class Solution(object):
def firstUniqChar(self, s):
"""
:type s: str
:rtype: str
"""
if len(s) < 1: return ' '
hashh = {}
for letter in s:
if letter not in hashh:
hashh[letter] = 1
else:
hashh[letter] += 1
for letter in s:
if hashh[letter] == 1:
return letter
return ' '
class Solution(object):
def firstUniqChar(self, s):
queue = collections.deque()
first = {}
for i,letter in enumerate(s):
if letter not in first: # 第一次出现(利用哈希表判断是否是第一次出现)
first[letter] = i
queue.append((letter,i)) # 队列记录第一次出现的字母和索引
else:
first[letter] = -1
while queue and first[queue[0][0]] == -1 : # 如果队列不为空,且该队列的队头不是第一次出现的话,则将其出队
queue.popleft()
return queue[0][0] if queue else ' '
# 139. 单词拆分
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
dp = [False] * (len(s) + 1)
dp[0] = True
for i in range(len(s)):
for j in range(i+1,len(s)+1):
if dp[i] and s[i:j] in wordDict:
dp[j] = True
return dp[-1]
# 剑指 Offer 58 - I. 翻转单词顺序
class Solution:
def reverseWords(self, s: str) -> str:
s = s.strip() # 删除首尾空格
i = j = len(s) - 1
res = []
while i >= 0:
while i >= 0 and s[i] != ' ': i -= 1 # 搜索首个空格
res.append(s[i + 1: j + 1]) # 添加单词
while s[i] == ' ': i -= 1 # 跳过单词间空格
j = i # j 指向下个单词的尾字符(进行新一轮的循环)
return ' '.join(res) # 拼接并返回
# 832. 翻转图像
# 30 18
class Solution(object):
def flipAndInvertImage(self, image):
"""
:type image: List[List[int]]
:rtype: List[List[int]]
"""
for row in range(len(image)):
image[row] = image[row][::-1]
for row in range(len(image)):
for column in range(len(image[0])):
image[row][column] = 1 - image[row][column]# 异或运算
return image
# 68 15
class Solution(object):
def flipAndInvertImage(self, image):
"""
:type image: List[List[int]]
:rtype: List[List[int]]
"""
for row in range(len(image)):
image[row] = image[row][::-1]
for column in range(len(image[row])):
image[row][column] = 1 - image[row][column] # 异或运算
return image
# 63,27
# 34. 在排序数组中查找元素的第一个和最后一个位置
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
if len(nums) < 1: return -1,-1 # 特殊值
left = 0
right = left
while left < len(nums) and nums[left] != target:
left += 1
right = left
while right < len(nums) and nums[right] == target:
right += 1
if left == len(nums): return -1,-1 # 找不到
return left,right
# 32,46
# 由于二分是从中间开始找起的,所以找的必然是条件区间中靠近中心的的边界值。
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
left = 0
right = len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] > target:
right = mid - 1
elif nums[mid] < target:
left = mid + 1
else:
left = mid
right = mid
while left > 0 and nums[left-1] == target:
left -= 1
while right < len(nums) - 1 and nums[right+1] == target:
right += 1
return left,right
return -1,-1
# 哈啰练习题
m,n = input().split(' ')
m = int(m)
n = int(n)
res = []
for i in range(m):
temp = []
row = input().split(' ')
for j in range(n):
temp.append(int(row[j]))
res.append(temp)
BIG = 10 ** 9
dp = [[BIG] * (n+1) for _ in range(m+1)]
dp[n][m-1] = dp[n-1][m] = 1
for i in range(m-1,-1,-1):
for j in range(n-1,-1,-1):
minn = min(dp[i+1][j],dp[i][j+1])
dp[i][j] = max(minn - res[i][j],1)
print(dp[0][0])
# 74. 搜索二维矩阵
class Solution(object):
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
up = len(matrix) - 1
right = 0
while up >= 0 and right <= len(matrix[0]) - 1:
if matrix[up][right] > target:
up -= 1
elif matrix[up][right] < target:
right += 1
else:
return True
return False
# 剑指 Offer 40. 最小的k个数
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
# 指针,边界要分清,还有一个是哨兵
def quick_sort(arr,left,right):
if left >= right: return # 递归的终止条件
pivot = left
i,j = left,right
while i < j:
while i < j and arr[j] >= arr[pivot]: j-= 1 # 必须先遍历右边? 从左边开始的话,无法保证使基数左边的数据都比基数小
while i < j and arr[i] <= arr[pivot]: i += 1
arr[i],arr[j] = arr[j],arr[i]
arr[pivot],arr[i] = arr[i],arr[pivot]
quick_sort(arr,left,i-1) # 划分成的两部分不包括基数
quick_sort(arr,i+1,right)
return arr
left = 0
right = len(arr) - 1
return quick_sort(arr,left,right)
arr = [3,2,1]
k = 2
solution = Solution()
print(solution.getLeastNumbers(arr,k))
# 于是,j 也会停留在数字7 那个位置,于是问题来了。当你最后交换基数6与7时,不对呀!!。
# 问题在于当我们先从在边开始时,那么 i 所停留的那个位置肯定是大于基数6的,而在上述例子中,为了满足 i
# 但最后交换回去的时候,7就到了左边,不行,因为我们原本 交换后数字6在边应该是全部小于6,右边全部大于6.但现在不行了。
# 于是,我们必须从右边开始,也就是从基数的对面开始。
# https://blog.csdn.net/w282529350/article/details/50982650
while True:
try:
NM = [i for i in input().split(' ')]
N = int(NM[0])
M = int(NM[1])
scores = [int(i) for i in input().split(' ')]
for row in range(M):
ops = [i for i in input().split(' ')]
opt = ops[0]
A = int(ops[1])
B = int(ops[2])
if opt =='U':
scores[A-1] = B
if opt == 'Q':
if A < B:
print(max(scores[A-1:B]))
elif A > B:
print(max(scores[B-1:A]))
else:
print(scores[A-1])
except:
break
# 华为2016校园招聘上机笔试题
# 最高分是多少
import sys
dct = {}
for line in sys.stdin:
ele = line.split('\\')[-1].strip('\n')
if ele in dct:
dct[ele] += 1
else:
dct[ele] = 1
lst = sorted(dct.items(),key=lambda d: d[1],reverse=True)
count = 0
for key in lst:
if count > 7:
break
count += 1
if len(key[0].split(' ')[0]) > 16 :
print(key[0].split(' ')[0][-16:],key[0].split(' ')[1],key[1])
else:
print(key[0].split(' ')[0],key[0].split(' ')[1],key[1])
# 美团笔试题1 淘汰分数
def choose_m(n,x,y,ais): #使晋级人数最多,淘汰人数最少
ais = sorted(ais)
left = x # 区间
right = y
i = left # 至少淘汰人数
# j = n - i # 晋级人数
while i <= right: #满足条件的情况下,那么什么时候会不满足条件
# 1、判断人数是否在区间内
# 2、判断当前分数线,是否存在两个人成绩是一样的
if n - i <= right and n-i >= left and ais[i]!= ais[i-1]:
minn = ais[i-1]
break
i += 1
return minn
def main():
row1 = [int(i) for i in input().split(' ')]
n = row1[0]
x = row1[1]
y = row1[2]
scores = [int(i) for i in input().split(' ')]
print(choose_m(n,x,y,scores))
main()
# 正则序列
# n = 5
# nums = [-1,2,3,10,100]
n = int(input())
nums = [int(i) for i in input().split(' ')]
sum = 0
nums = sorted(nums)
for i in range(1,(n+1)):
sum += abs(nums[i-1] - i)
print(sum)
# 美团笔试3 公司食堂
# 理解题意,小美和小团所在公司的食堂有N张餐桌,从左到右摆成一排,每张餐桌有2张餐椅供至多2人用餐,
# 无论男女,当有多张餐桌供职员选择时,他会选择最靠左的餐桌用餐(取小根堆的堆顶)
import heapq
people = [0,1,1,0,2]
M = 6
genders = 'MFMMFF'
heap0 = []
heap1 = []
for i,person in enumerate(people,start=1):
if person == 0:
heapq.heappush(heap0,i) # 可以坐1个人座位的位置
if person == 1:
heapq.heappush(heap1,i)
for gender in genders:
f1 = heap1[0] if heap1 else 0 # 1个人的座位的个数,最左边的位置(优先坐这个位置,不过也要考虑是否存在)
f0 = heap0[0] if heap0 else 0 # 0个人座位的个数
if gender == 'M':
if f1: # 如果是男性,且1个人的座位还有,则坐这个位置,此时最左边1个人的位置变少了
print(f1)
heapq.heappop(heap1)
else:
print(f0) # 否则选择的是空位置,不仅最左边的空位置没了,而且1个人的位置多了一个
heapq.heappush(heap1,heapq.heappop(heap0))
else:
if f0:
print(f0)
heapq.heappush(heap1,heapq.heappop(heap0))
else:
print(f1)
heapq.heappop(heap1)
# 美团笔试3 公司食堂
# 理解题意,小美和小团所在公司的食堂有N张餐桌,从左到右摆成一排,每张餐桌有2张餐椅供至多2人用餐,
# 无论男女,当有多张餐桌供职员选择时,他会选择最靠左的餐桌用餐(取小根堆的堆顶)
import heapq
people = [0,1,1,0,2]
M = 6
genders = 'MFMMFF'
heap0 = []
heap1 = []
for i,person in enumerate(people,start=1):
if person == 0:
heapq.heappush(heap0,i) # 可以坐1个人座位的位置
if person == 1:
heapq.heappush(heap1,i)
for gender in genders:
f1 = heap1[0] if heap1 else 0 # 1个人的座位的个数,最左边的位置(优先坐这个位置,不过也要考虑是否存在)
f0 = heap0[0] if heap0 else 0 # 0个人座位的个数
if gender == 'M':
if f1: # 如果是男性,且1个人的座位还有,则坐这个位置,此时最左边1个人的位置变少了
print(f1)
heapq.heappop(heap1)
else:
print(f0) # 否则选择的是空位置,不仅最左边的空位置没了,而且1个人的位置多了一个
heapq.heappush(heap1,heapq.heappop(heap0))
else:
if f0:
print(f0)
heapq.heappush(heap1,heapq.heappop(heap0))
else:
print(f1)
heapq.heappop(heap1)
# 230. 二叉搜索树中第K小的元素
# 树的中序遍历
class Solution(object):
def kthSmallest(self, root, k):
"""
:type root: TreeNode
:type k: int
:rtype: int
"""
res = []
def dfs(root):
if root != None:
dfs(root.left)
res.append(root.val)
dfs(root.right)
dfs(root)
return res[k-1]
# 1029. 两地调度
class Solution(object):
def twoCitySchedCost(self, costs):
"""
:type costs: List[List[int]]
:rtype: int
"""
costs = sorted(costs,key = lambda x: x[0] - x[1])
# print(costs)
n = len(costs) // 2
total = 0
for i in range(n):
total += costs[i][0] + costs[i+n][1]
return total
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
class Solution(object):
def exchange(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
left = 0
right = len(nums) - 1
while left < right:
while left < right and nums[left]%2 != 0: left += 1 # 找到偶数
while left < right and nums[right] % 2 == 0 : right -= 1
nums[left],nums[right] = nums[right],nums[left]
return nums
# 剑指 Offer 40. 最小的k个数
# 快速排序
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
# 指针,边界要分清,还有一个是哨兵
def quick_sort(arr,left,right):
if left >= right: return # 递归的终止条件
pivot = left
i,j = left,right
while i < j:
while i < j and arr[j] >= arr[pivot]: j-= 1 # 必须先遍历右边? 从左边开始的话,无法保证使基数左边的数据都比基数小
while i < j and arr[i] <= arr[pivot]: i += 1
arr[i],arr[j] = arr[j],arr[i]
arr[pivot],arr[i] = arr[i],arr[pivot]
quick_sort(arr,left,i-1) # 划分成的两部分不包括基数
quick_sort(arr,i+1,right)
return arr
left = 0
right = len(arr) - 1
return quick_sort(arr,left,right)
arr = [3,2,1]
k = 2
solution = Solution()
print(solution.getLeastNumbers(arr,k))
# 于是,j 也会停留在数字7 那个位置,于是问题来了。当你最后交换基数6与7时,不对呀!!。
# 问题在于当我们先从在边开始时,那么 i 所停留的那个位置肯定是大于基数6的,而在上述例子中,为了满足 i
# 但最后交换回去的时候,7就到了左边,不行,因为我们原本 交换后数字6在边应该是全部小于6,右边全部大于6.但现在不行了。
# 于是,我们必须从右边开始,也就是从基数的对面开始。
# https://blog.csdn.net/w282529350/article/details/50982650
while True:
try:
NM = [i for i in input().split(' ')]
N = int(NM[0])
M = int(NM[1])
scores = [int(i) for i in input().split(' ')]
for row in range(M):
ops = [i for i in input().split(' ')]
opt = ops[0]
A = int(ops[1])
B = int(ops[2])
if opt =='U':
scores[A-1] = B
if opt == 'Q':
if A < B:
print(max(scores[A-1:B]))
elif A > B:
print(max(scores[B-1:A]))
else:
print(scores[A-1])
except:
break
# 华为2016校园招聘上机笔试题
# 最高分是多少
import sys
dct = {}
for line in sys.stdin:
ele = line.split('\\')[-1].strip('\n')
if ele in dct:
dct[ele] += 1
else:
dct[ele] = 1
lst = sorted(dct.items(),key=lambda d: d[1],reverse=True)
count = 0
for key in lst:
if count > 7:
break
count += 1
if len(key[0].split(' ')[0]) > 16 :
print(key[0].split(' ')[0][-16:],key[0].split(' ')[1],key[1])
else:
print(key[0].split(' ')[0],key[0].split(' ')[1],key[1])
# 美团笔试题1 淘汰分数
def choose_m(n,x,y,ais): #使晋级人数最多,淘汰人数最少
ais = sorted(ais)
left = x # 区间
right = y
i = left # 至少淘汰人数
# j = n - i # 晋级人数
while i <= right: #满足条件的情况下,那么什么时候会不满足条件
if n - i <= right and n-i >= left and ais[i]!= ais[i-1]:
minn = ais[i-1]
break
i += 1
return minn
def main():
row1 = [int(i) for i in input().split(' ')]
n = row1[0]
x = row1[1]
y = row1[2]
scores = [int(i) for i in input().split(' ')]
print(choose_m(n,x,y,scores))
main()
# 正则序列
# n = 5
# nums = [-1,2,3,10,100]
n = int(input())
nums = [int(i) for i in input().split(' ')]
sum = 0
nums = sorted(nums)
for i in range(1,(n+1)):
sum += abs(nums[i-1] - i)
print(sum)
# 公司食堂
import heapq
T = int(input())
while T:
T -= 1
N = int(input())
people = [int(i) for i in input()]
M = int(input())
genders = input()
heap0 = []
heap1 = []
for i,person in enumerate(people,start=1):
if person == 0:
heapq.heappush(heap0,i) # 可以坐1个人座位的位置
if person == 1:
heapq.heappush(heap1,i)
for gender in genders:
f1 = heap1[0] if heap1 else 0 # 1个人的座位的个数,最左边的位置(优先坐这个位置,不过也要考虑是否存在)
f0 = heap0[0] if heap0 else 0 # 0个人座位的个数
if gender == 'M':
if f1:
print(f1)
heapq.heappop(heap1)
else:
print(f0)
heapq.heappush(heap1,heapq.heappop(heap0))
else:
if f0:
print(f0)
heapq.heappush(heap1,heapq.heappop(heap0))
else:
print(f1)
heapq.heappop(heap1)
# heapq.heappush(heap, item)
# heap为定义堆,item增加的元素
# heapq.heappop(heap)
# 删除并返回最小值,因为堆的特征是heap[0]永远是最小的元素,所以一般都是删除第一个元素。
# 美团2021校招笔试-编程题(通用编程试题,第9场) 糕点
# 来源:牛客网
# 模拟一下,在保证a
# (1) 已经烤好的蛋糕中,重量最小的比a轻,或者重量最大的比b重,肯定无法满足要求。
# (2) 已经烤好的蛋糕重量都在区间[a,b]中
# i) 已经有a和b两个重量,可以满足要求。
# ii) 已经有a或b之中的一个重量,并且还能现烤的蛋糕数不少于1,那就肯定还能够烤一个需要的重量;否则不能满足要求。
# iii) 需要的两个重量都没有,并且能还能现烤的蛋糕数不少于2,那就肯定可以把需要的两个重量都烤了;否则不能满足要求。
while True:
try:
s1 = list(map(int,input().split(' ')))
s2 = list(map(int,input().split(' ')))
n,m,a,b = s1
if a > b: a,b = b,a
cake1,cake2 = min(s2),max(s2)
if cake1 < a or cake2 > b: print('No')
if cake1 == a and cake2 == b: print('Yes')
if cake1 == a or cake2 == b:
if n-m >= 1: print('Yes')
else: print('No')
if cake1 < a and cake2 > b:
if n-m>= 2: print('Yes')
else: print('No')
except:
break
# 美团2021校招笔试-编程题(通用编程试题,第9场)
# [编程题]晋级人数
s1 = list(map(int, input().split(' ')))
s2 = list(map(int, input().split(' ')))
n,x = s1
scores = sorted(s2,reverse=True)
num = 0
for score in scores:
if score >= scores[x-1] and score != 0:
num += 1
print(num)
# 美团3 回转寿司
# 题目要求环形数组的连续子数组的最大和,我们先不要去管数组是环形的情况,利用动态规划求解连续子数组的最大和以及最小和。
# (1) 不考虑环形得到的最大值:题中允许寿司首尾相连的环形数组情况,因此常规求得的连续子数组的最大和就是我们排除这种情况之外的所有情况中的最大和。
# (2) 只考虑环形得到的最大值:而对于首尾相连的情况,我们可以这样考虑,如果常规求得的连续子数组的和达到了最小,那么总和减去这个最小值就等于首尾相连情况的最大值了。
# 因此最大的美味值就是(1)和(2)两种情况中大的那个。
# ---------------------------------------------------------------------------------------------------------------------------
# 接下来说一下动态规划如何求解连续子数组的最大和:
# 状态定义:dp[i]表示以 i 结尾的连续子数组的最大和
# 状态转移方程:dp[i] = max(array[i], dp[i-1]+array[i])
# 状态转移方程的意思是:如果选择了当前元素i,而dp[i-1]为负数,表明之前的和做的是负贡献,会使得整体的和变小,因此这时候选择从array[i]重新开始计算和。
# 考虑到我们并不需要求得dp数组中所有的值,而是只需要最大值,所以还可以对空间复杂度进行优化。每次计算得到其中一个dp[i]时,就更新当前的最大值,而dp[i]之前的取值(dp[0],dp[1],...,dp[i-1])已经用过,所以不需要再保留了,仅用一个变量代替dp数组即可。
# 求解连续子数组的最小和只要将以上的max改成min就可以了......
T= int(input())
while T:
T -= 1
N = input()
nums = [int(i) for i in input().split(' ')]
maxx = nums[0]
minn = nums[0]
dpmax = nums[0]
dpmin = nums[0]
for i in range(1,len(nums)):
dpmax = max(dpmax+nums[i],nums[i]) # 不断连续的连续数组最大和
maxx = max(maxx,dpmax) # 记录当前连续数组中的最大和,有可能断开
dpmin = min(dpmin+nums[i],nums[i])
minn = min(dpmin,minn)
print(max(maxx,sum(nums)-minn))
# [编程题]偏爱字母
N = input()
s = input()
sum = 0
max_sum = 0
for i in range(len(s)):
if s[i] == 'E': sum += 1
if s[i] == 'F': sum -= 1
sum = max(sum,0)
max_sum = max(max_sum,sum)
print(max_sum)
# 72. 编辑距离
class Solution(object):
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
m = len(word1)
n = len(word2)
dp = [[0] * (n+1) for _ in range(m+1)]
for i in range(m+1):
dp[i][0] = i
for j in range(n+1):
dp[0][j] = j
for i in range(1,m+1):
for j in range(1,n+1):
left = dp[i][j-1] + 1 # 来源处
down = dp[i-1][j] + 1
left_down = dp[i-1][j-1]
if word1[i-1] != word2[j-1]:
left_down = left_down + 1
dp[i][j] = min(left,down,left_down)
return dp[m][n]