Python 实现各个基础算法模板

Python 实现各个基础算法模板

包括题目,思路,模板,应用

一、二分模板

题目地址

题目:给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。 

请你统计并返回 grid 中 负数 的数目。

思路:找到每排的第一个负数,后面就都是负数了,最后累计负数数目

模板:

def binary_search(nums, target):
    low = 0
    high = len(nums) - 1
    while low <= high:
        mid = (low + high) // 2

        if nums[mid] == target:
            return mid
        if nums[mid] > target:
            high = mid - 1
        else:
            low = mid + 1
    return low


a = [1, 3, 7, 9, 14, 20, 24]
print(binary_search(a, 0))  # 0
print(binary_search(a, 1))  # 0
print(binary_search(a, 2))  # 1
print(binary_search(a, 4))  # 2
print(binary_search(a, 8))  # 3

print(binary_search(a, 11))  # 4
print(binary_search(a, 16))  # 5
print(binary_search(a, 24))  # 6
print(binary_search(a, 29))  # 7

应用:

from typing import List


class Solution:
    def countNegatives(self, grid: List[List[int]]) -> int:
        res = 0
        m = grid.__len__()
        n = grid[0].__len__()
        for i in range(m):
            # 二分找到0的位置
            low, high = 0, n - 1
            while low < high:
                mid = (low + high) // 2
                if grid[i][mid] >= 0:
                    low = mid + 1
                else:
                    high = mid

            if grid[i][low] < 0:
                res += n - low
        return res


s = Solution()
print(s.countNegatives([[4, 3, 2, -1], [3, 2, 1, -1], [1, 1, -1, -2], [-1, -1, -2, -3]]))
# 8

二、递归模板

题目地址

题目:

在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。

请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。

你需要原地修改栈。

思路:

将N个盘子分为N,N-1两部分,将N-1个盘子看成一个整体,分三步完成移动即可完成

1. N-1部分由A->B

2. N部分由A->C

3. N-1部分由B->C

再把上述N-1部分分为N-1和N-2两部分,继续重复的分三步完成移动

模板:搞清楚递归退出条件是什么,问题怎么分解递归解决的

def fib(n):
    # 递归退出条件
    if n < 2:
        return n
    else:
        # 分解递归
        return fib(n-1) + fib(n-2)

print(fib(10))

应用:

class Solution:
    def hanota(self, A: List[int], B: List[int], C: List[int]) -> None:
        def hanoi(n,a,b,c):
            # 递归退出条件
            if n == 1:
                c.append(a.pop())
            else:
                # 分解递归
                hanoi(n-1,a,c,b)
                c.append(a.pop())
                hanoi(n-1,b,a,c)

        hanoi(len(A),A,B,C)

三、分治模板

四、贪心模板

五、回溯剪枝模板

题目地址

题目:

找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:1. 所有数字都是正整数。2. 解集不能包含重复的组合。 

思路:

主体步骤为先想办法递归遍历所有可能,再通过剪枝加速,筛选并记录正确的解

模板及应用:

class Solution:
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        def back(candidates, cur, target, length):
            # 剪枝判断
            if len(cur) > length or target < 0:
                return

            # 筛选目标解判断
            if len(cur) == length and target == 0:
                # 保存目标解
                res.append(cur.copy())
                return
            
            # 循环遍历所有可能分支
            for i in range(len(candidates)):
                # 这里也可剪枝
                # 若出现逆序,则剪枝,防止出现重复的情况例如 [1,2] [2,1]是一种
                if len(cur) > 0 and candidates[i] < cur[-1]:
                    continue
                
                # 为进入分支做准备
                cur.append(candidates[i])

                # 进入分支
                back(candidates[:i] + candidates[i + 1:], cur, target - candidates[i], length)
                # 恢复进入分支所做的准备, 使每次循环遍历的分支所处的条件一致
                cur.pop()
        
        # 算法准备及入口
        res = []
        nums = [i for i in range(1, 10)]
        back(nums, [], n, k)
        return res

s = Solution()
print(s.combinationSum3(3, 9))

六、二叉树遍历模板

# 前序优先遍历
def qianxu(p: TreeNode):
    res = []
    stack = []
    while (stack.__len__() != 0 or p):
        if p:
            res.append(p.val)
            stack.append(p)
            p = p.left
        else:
            p = stack.pop(-1)
            p = p.right
    return res


# 中序优先遍历
def zhongxu(p: TreeNode):
    res = []
    stack = []
    while (stack.__len__() != 0 or p):
        if p:
            stack.append(p)
            p = p.left
        else:
            p = stack.pop(-1)
            res.append(p.val)
            p = p.right
    return res


# 后序优先遍历
def houxu(p: TreeNode):
    res = []
    stack = []
    d = dict()
    while (p or stack.__len__() != 0):
        if p:
            stack.append(p)
            d.update({p.val: 1})
            p = p.left
        else:
            p = stack[-1]
            if d[p.val] == 2:
                stack.pop(-1)
                res.append(p.val)
                p = None
            else:
                d[p.val] = 2
                p = p.right

    return res

def houxu(self, root: Optional[TreeNode]) -> List[int]:
    res = []
    stack = []
    p = root
    # 保存前一个访问的节点
    prev = None
    while p or stack:
        # 找到最左边
        while p:
            stack.append(p)
            p = p.left

        node = stack.pop()
        if not node.right or node.right == prev:
            res.append(node.val)
            prev = node
            p = None
        else:
            stack.append(node)
            p = node.right
    return res


# 层次遍历,用队列
def cengci(p: TreeNode):
    res = []
    queue = [p]
    while (queue.__len__() != 0):
        p = queue.pop(0)
        res.append(p.val)
        if p.left:
            queue.append(p.left)
        if p.right:
            queue.append(p.right)
    return res

# 递归
# 先序
def preorder(root):
    if not root:
        return 
    print(root.val)
    preorder(root.left)
    preorder(root.right) 
# 中序
def inorder(root):
    if not root:
        return 
    inorder(root.left)
    print(root.val)
    inorder(root.right)
# 后序
def postorder(root):
    if not root:
        return 
    postorder(root.left)
    postorder(root.right)
    print(root.val)

平衡二叉树的二分搜索

    def exists(self, idx: int, d: int, node: TreeNode) -> bool:
        """
        Last level nodes are enumerated from 0 to 2**d - 1 (left -> right).
        Return True if last level node idx exists. 
        Binary search with O(d) complexity.
        """
        left, right = 0, 2**d - 1
        for _ in range(d):
            pivot = (left + right) // 2
            if idx <= pivot:
                node = node.left
                right = pivot
            else:
                node = node.right
                left = pivot + 1
        return node is not None

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值