面试常考编程

双指针

两数之和

两数之和

class Solution:# 字典 时间复杂度O(N) 空间复杂度O(N) 如果列表是排好序的可以使用双指针,时间复杂度O(N),空间复杂度为O(1)
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hashtable = dict()
        for i, num in enumerate(nums):
            if target - num in hashtable:
                return [hashtable[target - num], i]
            hashtable[nums[i]] = i
        return []
        #有序,双指针
        left,right = 0,len(numbers) - 1
        while left < right:
            if numbers[left] + numbers[right] == target:
                return [left+1,right+1]
            elif numbers[left] + numbers[right] < target:
                left+=1
            else:
                right-=1

二分

33. 搜索旋转排序数组(在无重复旋转数组上搜索一个target)

33. 搜索旋转排序数组(在无重复旋转数组上搜索一个target)
思路:二分,找到就返回,否则
1.左边递增,并且target在递增范围内,右边界更新
2.左边递增,target不在递增范围内,左边界更新
3.右边递增,target在递增范围内,左边界更新
4.右边递增,target不在递增范围内,右边界更新

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if not nums:return -1
        left,right = 0,len(nums)-1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] == target:
                return mid
            if nums[0] <= nums[mid]:#说明是递增的,没有旋转
                if nums[0] <=target <nums[mid]:
                    right=mid-1
                else:
                    left=mid+1
            else:#说明0,mid之间有旋转,mid右边是递增的
                if nums[mid]<target<=nums[len(nums) - 1]:
                    left = mid + 1
                else:
                    right = mid - 1
        return -1

153. 寻找旋转排序数组中的最小值(非重复)

如果当前的数比前一个数小,则该数为旋转,返回
如果当前数比第一个数大,左边界更新
否则,右边界更新
在这里插入图片描述

154.寻找旋转排序数组中的最小值 II(有重复)

如果当前数比右边界数小,更新右边界
否则如果当前数比右边界大,更新左边界
如果相等,右边界-1
在这里插入图片描述

50. Pow(x, n)(快速幂)

50. Pow(x, n)(快速幂)

class Solution:#迭代方法,时间复杂度O(logn)空间复杂度O(1)
    def myPow(self, x: float, n: int) -> float:
        def quickMul(N):
            ans = 1.0
            # 贡献的初始值为 x
            x_contribute = x
            # 在对 N 进行二进制拆分的同时计算答案
            while N > 0:
                if N % 2 == 1:
                    # 如果 N 二进制表示的最低位为 1,那么需要计入贡献
                    ans *= x_contribute
                # 将贡献不断地平方
                x_contribute *= x_contribute
                # 舍弃 N 二进制表示的最低位,这样我们每次只要判断最低位即可
                N //= 2
            return ans
        return quickMul(n) if n >= 0 else 1.0 / quickMul(-n)

动态规划

300. 最长上升子序列

300. 最长上升子序列
如果当前数大于存的最后一个数,直接添加
否则查找当前数在结果的替换位置,替换一下,同时更新当前位置的dp为查找到的位置+1
根据dp矩阵反向找具体序列

import bisect
class Solution:#时间复杂度O(nlogn) 空间复杂度o(n)
    def LIS(self , arr ):
        n = len(arr)
        dp = [1] * n
        save = [arr[0]]
        length = 1
        for i in range(1,n):
            if arr[i] > save[-1]:
                save.append(arr[i])
                length += 1
                dp[i] = length
            else:
                index =  bisect.bisect(save,arr[i])
                dp[i] = index + 1
                save[index] = arr[i]
        max_num = save[-1]
        max_index = arr.index(max_num)
        res = []
        for i in range(max_index,-1,-1):
            if res==[] or (arr[i] < res[-1] and dp[i]==length):
                res.append(arr[i])
                length -=1
        return res[::-1]

1143. 最长公共子序列(此题没要求具体序列,下面的代码可以返回具体序列)

1143. 最长公共子序列(此题没要求具体序列,下面的代码可以返回具体序列)
思路:生成(m+1)*(n+1)矩阵,即多了空字符
状态转移:
如果当前字符相等,dp[i][j]=dp[i-1][j-1]+1
不相等则,max(dp[i-1][j],dp[i][j-1])
根据dp结果找具体序列

class Solution:
    def LCS(self , s1 , s2 ):
        s1 = list(s1)
        s2 = list(s2)
        m = len(s1)
        n = len(s2)
        res = []
        dp = [[0]*(n+1) for i in range(m+1)]
        for i in range(1,m+1):
            for j in range(1,n+1):
                if s1[i-1] == s1[j-1]:
                    dp[i][j] = dp[i-1][j-1]+1
                else:
                    dp[i][j] = max(dp[i-1][j],dp[i][j-1])
        if dp[-1][-1] == 0:
            return -1
        i,j = m,n
        while i > 0 and j > 0:
            if s1[i-1] == s2[j-1]:
                res.append(s1[i-1])
                i-=1
                j-=1
                continue
            else:
                if dp[i][j-1] >= dp[i-1][j]:
                    j-=1
                else:
                    i-=1
        return ''.join(res[::-1])

最长公共子串(最长的连续的串,需要返回具体序列)

最长公共子串(最长的连续的串,需要返回具体序列)
思路:从头开始检查以当前字符结尾的串是否在另一个串出现,如果出现,max_len+1,不出现不更新,因为不出现的话,最远也只检查到当前最长的那个字符,例如
abcdefgre cdefgrefaa
检查到c时,最远也只检查到c即可

class Solution:
    def LCS(self , str1 , str2 ):
        if len(str1) > len(str2):
            str1, str2 = str2, str1
        max_len, res = 0, ''
        for i in range(len(str1)):
            if str1[i-max_len: i+1] in str2:
                res = str1[i-max_len:i+1]
                max_len += 1
        if not res:
            return -1
        else:
            return res

编辑距离

https://leetcode-cn.com/problems/edit-distance/solution/bian-ji-ju-chi-by-leetcode-solution/
本质不同的操作实际上只有三种:
在单词 A 中插入一个字符;
在单词 B 中插入一个字符;
修改单词 A 的一个字符

class Solution:
    def minDistance(self, word1, word2):
        n = len(word1)
        m = len(word2)
        # 有一个字符串为空串
        if n * m == 0:
            return n + m
        # DP 数组
        D = [ [0] * (m + 1) for _ in range(n + 1)]
        # 边界状态初始化
        for i in range(n + 1):
            D[i][0] = i
        for j in range(m + 1):
            D[0][j] = j
        # 计算所有 DP 值
        for i in range(1, n + 1):
            for j in range(1, m + 1):
                left = D[i - 1][j] + 1
                down = D[i][j - 1] + 1
                left_down = D[i - 1][j - 1] 
                if word1[i - 1] != word2[j - 1]:
                    left_down += 1
                D[i][j] = min(left, down, left_down)
        return D[n][m]

bfs\dfs

数据流中的中位数

Python 中 heapq 模块是小顶堆。实现 大顶堆 方法: 小顶堆的插入和弹出操作均将元素 取反 即可

from heapq import *
class MedianFinder:
    def __init__(self):
        #时间 查找中位数O(1),添加数字O(logn) 空间复杂度O(n)
        self.A=[]#小顶堆,最小数在头部,此存储的都是大的数,默认len(A)>=len(B)
        self.B = []#大顶堆,最大数在头部,此存储的都是小的数

    def addNum(self, num: int) -> None:
        if len(self.A)!=len(self.B):#说明A里个数较多,因此需往B里添加一个数,而往B里添加的应该是一个较小的数,因此首先将num加入到A中,之后pop出A的头,push到B
            heappush(self.B, -heappushpop(self.A, num))
        else:#说明两个个数相等,需往A中添加数,由于A是大的数的集合,因此需往A中添加大的数,因此将数添加到B后,让Bpop出大的数,push到A
            heappush(self.A, -heappushpop(self.B, -num))

    def findMedian(self) -> float:
        return self.A[0] if len(self.A) != len(self.B) else (self.A[0] - self.B[0]) / 2.0

检查是否为二叉搜索树的后序遍历序列

https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/solution/mian-shi-ti-33-er-cha-sou-suo-shu-de-hou-xu-bian-6/

class Solution:
    def verifyPostorder(self, postorder: [int]) -> bool:
        stack, root = [], float("+inf")
        for i in range(len(postorder) - 1, -1, -1):
            if postorder[i] > root: return False
            while(stack and postorder[i] < stack[-1]):
                root = stack.pop()
            stack.append(postorder[i])
        return True

两个树节点的最近公共祖先

class Solution:
    def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
        if not root or root == p or root == q:return root
        left = self.lowestCommonAncestor(root.left,p,q)
        right = self.lowestCommonAncestor(root.right,p,q)
        if left and right:return root
        if left : return left
        if right: return right

二叉树转双向链表

二叉树转双向链表

class Solution:
    def treeToDoublyList(self, root: 'Node') -> 'Node':
        def dfs(cur):
            if not cur: return
            dfs(cur.left) # 递归左子树
            if self.pre: # 修改节点引用
                self.pre.right, cur.left = cur, self.pre
            else: # 记录头节点
                self.head = cur
            self.pre = cur # 保存 cur
            dfs(cur.right) # 递归右子树
        if not root: return
        self.pre = None
        dfs(root)
        self.head.left, self.pre.right = self.pre, self.head
        return self.head

中序后序构建二叉树

在这里插入图片描述

前序中序构建二叉树

在这里插入图片描述

每K个反转链表

在这里插入图片描述

递归回溯

排序

数组中第K大的数

在这里插入图片描述

链表排序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

深度学习

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值