人菜还要学算法
更新 2021-07-18
菜渣如我,现场手推论实在不在行,思考一番感觉用逆向方式或许还行,记一下方式
- 读题,读举例,先把时空复杂度等条件过滤掉,思索暴力解;
- 思考合适的 数据结构与算法,以此为准 推断各种可能出现的各个最小单位结果(如 out.append(l[n]))
- 以上一步的结果推断各种情况作为条件前置,递归/遍历/布尔判断等等组合(机写可以调整位置debug等,手写时把第二步的写一边先吧)
以上
B站现场面试
1、手写算法有序列表合并
合并有序数组
按上述描述走,暴力法就是合并再排序,时空复杂度根据选什么排序决定
以下是初次优化,输出数组顺序添加 比较值中取小的数,双指针
def combine(l1, l2):
"""正序,时间空间均为O(m+n)"""
out = []
len1 = len(l1)
len2 = len(l2)
p1, p2 = 0, 0
while p1 < len1 or p2 < len2:
if p1 >= len1:
out.append(l2[p2])
p2 += 1
continue
elif p2 >= len2:
out.append(l1[p1])
p1 += 1
continue
if l1[p1] <= l2[p2]:
out.append(l1[p1])
p1 += 1
else:
out.append(l2[p2])
p2 += 1
return out
二次优化,l1扩展len2,逆序添加 比较值中取大的数,双指针逆排序
(...现场当时开始被要求空间O(1)条件困住了,循序渐进说想法等会好点应该)
def combine_reverse(l1, l2):
"""逆序
"""
len1 = len(l1)
len2 = len(l2)
p1, p2 = len1-1, len2-1
l1.extend([float("-inf")]*len2)
tail = len1 + len2 -1
while p1 >= 0 or p2 >= 0:
# for tail in range(len1+len2-1, 0, -1):
if p2 < 0:
l1[tail] = l1[p1]
p1 -= 1
elif p1 < 0:
l1[tail] = l2[p2]
p2 -= 1
elif l1[p1] > l2[p2]:
l1[tail] = l1[p1]
p1 -= 1
else:
l1[tail] = l2[p2]
p2 -= 1
tail -= 1
return l1
2、两链表的交接点
摘自评论区大神一句话:【错的人就算走过了对方的路也还是会错过】
悟了!互相走一遍对方的路,能遇到的就是缘!
时间O(m+n)
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
A, B = headA, headB
while A != B:
A = A.next if A else headB
B = B.next if B else headA
return A
二分法
#!/usr/bin/python
# -*- coding: utf-8 -*-
from functools import wraps
from random import randrange
class Dichotomy:
def __init__(self, arr, target, not_then_return):
self.arr = arr
self.target = target
self.not_then_return = not_then_return
def __dichotomy(self):
left, right = 0, len(self.arr) - 1
ret = None
while left <= right:
m = (left + right) // 2
if self.comp(self.arr[m], self.target):
ret = m
right = m - 1
else:
left = m + 1
return ret
def wrap_solve(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
_id = self.__dichotomy()
return func(_id, self.arr, self.not_then_return, *args, **kwargs) if _id \
else self.not_then_return
return wrapper
def __call__(self, func_comp, func_solve, *args, **kwargs):
self.comp = func_comp
return self.wrap_solve(func_solve)(*args, **kwargs)
if __name__ == '__main__':
arr = sorted([randrange(50) for i in range(20)])
target = 233
not_then_return = float('-inf')
print(Dichotomy(arr=arr, target=target, not_then_return=not_then_return)(
func_comp=lambda i, _target: i**2 > _target,
func_solve=lambda i, _arr, n_t_r: (i, _arr[i]) if i != n_t_r else n_t_r))
栈
def dailyTemperatures(temperatures: iter):
stack = list()
out = [0] * len(temperatures)
for i, per_temp in enumerate(temperatures):
while len(stack):
_ = stack.pop()
if per_temp > _[1]:
index = _[0]
out[index] = i - index
else:
stack.append(_)
break
stack.append((i, per_temp))
return out
双向队列
from collections import deque
def dequeue(nums: iter, k):
"""保持一个最大为K的dequeue(简称dq)
1、保证最左为dq中的最大值
2、以栈形式比较大小
2.1、每当有新的最大值时,栈比较出掉对比当前小的值
2.2、当len(dq) > k,以队列方式出掉值
"""
dq = deque()
ans = []
for i in range(len(nums)):
# 只要当前遍历的元素的值比队尾大,让队尾出队列,
# 最终队列中的最小元素是大于当前元素的
while dq and dq[-1] < nums[i]:
dq.pop()
# 当前遍历的元素入队列, 此时队列中的元素一定是有序的,队列头部最大
dq.append(nums[i])
if i >= k - 1: # 超过k个才开始真正运算ans
# 如果窗口即将失效(下一次循环要失效)的值与当前对列头部的值相同,那么将对头的值出队列,
# 注意只pop一次,可能两个4,相邻同时是最大值,
ans.append(dq[0])
# 从队列中删除即将失效的数据
if nums[i + 1 - k] == dq[0]:
dq.popleft()
return ans

浙公网安备 33010602011771号