人菜还要学算法

更新 2021-07-18

菜渣如我,现场手推论实在不在行,思考一番感觉用逆向方式或许还行,记一下方式

  1. 读题,读举例,先把时空复杂度等条件过滤掉,思索暴力解;
  2. 思考合适的 数据结构与算法,以此为准 推断各种可能出现的各个最小单位结果(如 out.append(l[n]))
  3. 以上一步的结果推断各种情况作为条件前置,递归/遍历/布尔判断等等组合(机写可以调整位置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

つづく

posted @ 2021-07-08 01:19  Json-Eri  阅读(68)  评论(0)    收藏  举报