大厂面试高频题目——其他
数组
347. 前 K 个高频元素
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
思考
- 哈希+内置排序
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
num_dict = defaultdict(int)
for c in nums:
num_dict[c]+=1
index_dict = defaultdict(list)
for key in num_dict:
index_dict[num_dict[key]].append(key)
keys = list(index_dict.keys())
keys.sort(reverse=True)
cnt = 0
res = []
for key in keys:
res+=index_dict[key]
cnt=len(res)
if cnt == k:
break
return res
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
num_dict = defaultdict(int)
for c in nums:
num_dict[c]+=1
kvlist = []
for num,freq in num_dict.items():
kvlist.append((freq,num))
kvlist.sort(key=lambda x:x[0],reverse=True)
res = []
for item in kvlist[:k]:
res.append(item[1])
return res
- 哈希+最小堆
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
num_dict = defaultdict(int)
for c in nums:
num_dict[c]+=1
pri_que = [] #小顶堆
for num,freq in num_dict.items():
heapq.heappush(pri_que,(freq,num))
if len(pri_que)>k:
heapq.heappop(pri_que)
res = []
print(pri_que)
for item in pri_que:
res.append(item[1])
return res
215. 数组中的第K个最大元素
思考
堆排序(小顶堆,上面的是最小的,堆的大小维持K,则堆中保持的是前K大。)
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
pq = []
for c in nums:
heapq.heappush(pq,c)
if len(pq) > k:
heapq.heappop(pq)
#print(pq)
return pq[0]
快速选择排序
def quick_select(arr,low,high,k):
if low<=high:
pi = partition(arr,low,high)
if pi == len(arr) - k:
return arr[pi]
elif pi < len(arr) - k:
return quick_select(arr,pi+1,high,k)
else:
return quick_select(arr,low,pi-1,k)
def partition(a,low,high):
# 左闭右闭
pi_value = a[high]
i = low -1
for j in range(low,high):
if a[j] < pi_value:
i+=1
a[i],a[j] = a[j],a[i]
i+=1
a[i],a[high] = a[high],a[i]
return i
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
return quick_select(nums,0,len(nums)-1,k)
442. 数组中重复的数据
给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次 。请你找出所有出现 两次 的整数,并以数组形式返回。
你必须设计并实现一个时间复杂度为 O(n) 且仅使用常量额外空间的算法解决此问题。
思路
- 值i放在nums[i-1]里,如果不是这种情况,就一直交换。这种解法不确定while是否会陷入死循环。
class Solution:
def findDuplicates(self, nums: List[int]) -> List[int]:
# 值i放在nums[i-1]里
#[1,2,3,4,5]
for i in range(len(nums)):
while nums[i] != nums[nums[i]-1]:
#swap
p = nums[i]
#
nums[i] , nums[p-1] = nums[p-1],nums[i]
res = []
for i,num in enumerate(nums):
if num != i+1:
res.append(num)
return res
- nums本身当做哈希,出现过一次的值,以其值为下标的数组元素值取反,作为访问的标记。思想很妙,容易理解。
class Solution:
def findDuplicates(self, nums: List[int]) -> List[int]:
# nums[i] 当做哈希,取相反数表示值i-1被访问过
res = []
for i in range(len(nums)):
p = abs(nums[i])-1
if nums[p] < 0:
res.append(abs(nums[i]))
else:
nums[p] = -nums[p]
return res
33. 搜索旋转排序数组
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
思考
将数组一分为二,其中一定有一个是有序的,另一个可能是有序,也能是部分有序。
此时有序部分用二分法查找。无序部分再一分为二,其中一个一定有序,另一个可能有序,可能无序。就这样循环.
class Solution:
def search(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)-1
#[left,right]
mid = -1
while left<=right:
mid = int((left+right)/2)
if nums[mid] == target:
return mid
if nums[mid] >= nums[left]:
#左有序
if target >= nums[left] and target < nums[mid]:
# 二分
right = mid - 1
else:
left = mid + 1
else:
#右有序
if target > nums[mid] and target <= nums[right]:
left = mid + 1
else:
right = mid -1
return -1
34. 在排序数组中查找元素的第一个和最后一个位置
思考
两个二分搜索分别确定左右边界
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
def getRightBorder(nums, target):
left = 0
right = len(nums)-1
right_border = -2
while left<=right:
mid = int((left+right)/2)
if nums[mid] > target:
right = mid - 1
else:
left = mid + 1
right_border = left
return right_border
def getLeftBorder(nums, target):
left = 0
right = len(nums)-1
left_border = -2
while left<=right:
mid = int((left+right)/2)
if nums[mid] < target:
left = mid + 1
else:
right = mid - 1
left_border = right
return left_border
right_border = getRightBorder(nums,target)
left_border = getLeftBorder(nums, target)
print(left_border,right_border)
if left_border == -2 or right_border == -2 :
return [-1,-1]
if right_border-1 >= left_border+1:
return [left_border+1,right_border-1]
else:
return [-1,-1]
哈希
560. 和为 K 的子数组
- 暴力
固定left,逐个移动right ,会超时
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
count = 0
for i in range(len(nums)):
left = i
sum_ = 0
for j in range(left,len(nums)):
sum_+=nums[j]
if sum_ == k:
count+=1
return count
- 前缀和
会超时
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
count = 0
presum = [0] * (len(nums)+1)
for i in range(len(nums)):
presum[i+1] = presum[i] + nums[i]
for i in range(len(nums)):
left = i
for j in range(left,len(nums)):
#[left,right]的和
sum_ = presum[j+1] - presum[i]
if sum_ == k:
count+=1
return count
- 前缀和+哈希优化(类似两数之和,好难想到)
注意哈希初始化presum_dict[0]=1
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
count = 0
presum_dict = defaultdict(int)
presum_dict[0]=1
presum = 0
for i in range(len(nums)):
presum+=nums[i]
if presum - k in presum_dict:
count+=presum_dict[presum - k]
presum_dict[presum]+=1
return count
排序
215. 数组中的第K个最大元素
- 堆排序
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
pq = []
for c in nums:
heapq.heappush(pq,c)
if len(pq) > k:
heapq.heappop(pq)
return pq[0]
快速选择排序
def quick_select(arr,low,high,k):
if low<=high:
pi = partition(arr,low,high)
if pi == len(arr) - k:
return arr[pi]
elif pi < len(arr) - k:
return quick_select(arr,pi+1,high,k)
else:
return quick_select(arr,low,pi-1,k)
def partition(a,low,high):
# 左闭右闭
pi_value = a[high]
i = low -1
for j in range(low,high):
if a[j] < pi_value:
i+=1
a[i],a[j] = a[j],a[i]
i+=1
a[i],a[high] = a[high],a[i]
return i
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
return quick_select(nums,0,len(nums)-1,k)
快速排序
- 非原地排序
def quick_sort(arr):
if len(arr) <= 1:
return arr
else:
pivot = arr[0] # 选择第一个元素作为基准
less = [x for x in arr[1:] if x <= pivot] # 所有小于等于基准的元素
greater = [x for x in arr[1:] if x > pivot] # 所有大于基准的元素
# 递归排序子序列,并将结果与基准合并
return quick_sort(less) + [pivot] + quick_sort(greater)
# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
sorted_arr = quick_sort(arr)
print(sorted_arr)
2.原地排序
def quicksort_inplace(arr, low, high):
if low < high:
pi = partition(arr, low, high)
quicksort_inplace(arr, low, pi - 1) # Before pi
quicksort_inplace(arr, pi + 1, high) # After pi
def partition(arr, low, high):
pivot = arr[high] # 选择最右侧的元素作为基准
i = low - 1
for j in range(low, high):
if arr[j] < pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i] # 交换元素
arr[i + 1], arr[high] = arr[high], arr[i + 1] # 交换基准到正确的位置
return i + 1
# 示例数组
array = [3, 6, 8, 10, 1, 2, 1]
# 执行原地快速排序
quicksort_inplace(array, 0, len(array) - 1)
print(array)
哈希+链表
146. LRU 缓存
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
思考
这道题,代码量太大了,算是hard。尤其是手动实现双向链表及其操作。
class DListNode:
def __init__(self,key=0,value=0):
self.key = key
self.value = value
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.cache = {}
self.head = DListNode()
self.tail = DListNode()
self.head.next = self.tail
self.tail.prev = self.head
self.capacity = capacity
self.size = 0
def get(self, key: int) -> int:
if key not in self.cache:
return -1
# 先定位,再移动到头
node = self.cache[key]
self.moveToHead(node)
return node.value
def put(self, key: int, value: int) -> None:
if key not in self.cache:
node = DListNode(key,value)
self.cache[key] = node
self.addToHead(node)
self.size+=1
if self.size > self.capacity:
removed = self.removeTail()
# 删哈希对应的项
self.cache.pop(removed.key)
self.size-=1
else:
# 先定位,修改value,再移动到头部
node = self.cache[key]
node.value = value
self.moveToHead(node)
def addToHead(self, node):
node.prev = self.head
node.next = self.head.next
self.head.next = node
node.next.prev = node
def removeNode(self, node):
node.prev.next = node.next
node.next.prev = node.prev
def moveToHead(self, node):
#先删再插
self.removeNode(node)
self.addToHead(node)
def removeTail(self):
node = self.tail.prev
self.removeNode(node)
#要删哈希,所以返回
return node
二叉树
102. 二叉树层序遍历
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if root is None:
return []
result = []
queue = deque()
queue.append(root)
while queue:
level = []
for i in range(len(queue)):
node = queue.popleft()
level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(level)
return result
模拟
阿拉伯数字转中文字符串表达
思考
非常蛋疼的一道题,尤其是零的处理,面试感觉至少要写半小时
def num2ch(num):
num_map = {
'0': '零', '1': '一', '2': '二', '3': '三', '4': '四',
'5': '五', '6': '六', '7': '七', '8': '八', '9': '九'
}
one = (num%10000)
wan = int((num/10000)%10000)
yi = int(num/100000000)
wei_str = ['','十','百','千']
print(yi,wan,one)
def num2ch_4(num):
num = str(num)
temp = []
for i,c in enumerate(num[::-1]):
if c == '0':
temp.append(num_map[c])
else:
temp.append(num_map[c]+wei_str[i])
temp.reverse()
# 删除个位的零
res = ''.join(temp).rstrip('零')
# 删除连续的零
#print(res)
new_res = res[0]
for i in range(1,len(res)):
if res[i] != res[i-1]:
new_res+=res[i]
res = new_res
# 跨10**4,不足10**3的的数补个0
if len(num)<4:
res = '零'+res
return res
ch_str = ''
if yi!=0:
ch_str+=num2ch_4(yi)+'亿'
if wan!=0:
ch_str+=num2ch_4(wan)+'万'
if one!=0:
ch_str+=num2ch_4(one)
ch_str = ch_str.lstrip('零')
return ch_str
print(num2ch(123456789123))
print(num2ch(123005078920))
print(num2ch(10001))
print(num2ch(11001))
print(num2ch(10011001))
单调栈
739. 每日温度
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
思考
单调栈经典题目。
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
stack = []
res = [0] * len(temperatures)
stack.append((0,temperatures[0]))
for i in range(1,len(temperatures)):
while len(stack) > 0 and stack[-1][1] < temperatures[i]:
index,_ = stack.pop()
res[index] = i-index
stack.append((i,temperatures[i]))
return res
链表
143. 重排链表

思考
链表无法按下标访问,逐个遍历后放进数组里面,可以按索引访问,然后双指针一前一后依次添加。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reorderList(self, head: Optional[ListNode]) -> None:
"""
Do not return anything, modify head in-place instead.
"""
node_list = []
cur = head
while cur:
node_list.append(cur)
cur = cur.next
i = 0
j = len(node_list)-1
count = 0
last_index = 0
while count <= len(node_list)-1:
if count%2 == 0:
node_list[i].next = node_list[j]
last_index = i
i+=1
else:
node_list[j].next = node_list[i]
last_index = j
j-=1
count+=1
node_list[last_index].next = None
25. K 个一组翻转链表
给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
def reverseNode(head):
pre = None
cur = head
while cur:
temp = cur.next
cur.next = pre
pre = cur
cur = temp
return pre
class Solution:
def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
dummy = ListNode(0)
dummy.next = head
cur = dummy
pre = dummy
i = 0
while cur:
if i > 0 and i % k == 0:
temp = cur.next
cur.next = None
temp2 = pre.next
reverseNode(pre.next)
pre.next = cur
temp2.next = temp
cur = temp2
pre = temp2
cur = cur.next
i+=1
return dummy.next
浙公网安备 33010602011771号