分治法(二)

本文探讨了分治法和动态规划在解决特定算法问题中的应用,通过具体实例如Searcha2DMatrixII和DifferentWaystoAddParentheses,详细阐述了两种方法的实现过程及其优劣。分治法通过将问题分解为更小的子问题来简化解决方案,而动态规划则通过存储和复用子问题的解来避免重复计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2. 分治法解题

2.1 Search a 2D Matrix II

题目链接:https://leetcode.com/problems/search-a-2d-matrix-ii/description/
(1)遍历矩阵
对于这个问题,很自然地想到对矩阵进行遍历,但遍历的时间复杂度为O(m*n)。显然,这不是一个好的算法。

class Solution:
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        if len(matrix) == 0:
            return False
        row, column = 0, len(matrix[0]) -  1
        row_len = len(matrix) - 1
        while (row <= row_len) and (column >= 0):
            val = matrix[row][column]
            if target == val:
                return True
            elif target > val:
                row += 1
            else:
                column -= 1
        return False

(2)分治思想
由于行和列都是排好序的,显然在行列的遍历过程中可以使用二分搜索使得遍历的时间复杂度降低。
如何利用分治思想呢?其实就是在行或列搜索过程中使用二分查找法!

class Solution:
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        if len(matrix) < 1 or len(matrix[0]) < 1:
            return False
        
        for row in matrix:
            if row[0] > target:
                return False
            elif row[len(row) - 1] < target:
                continue
            else:
                l = 0
                r = len(row) - 1
                while l <= r:
                    mid = (l + r) // 2
                    if row[mid] > target:
                        r = mid - 1
                    elif row[mid] < target:
                        l = mid + 1
                    else:
                        return True
        return False

2.2 Different Ways to Add Parentheses

题目链接:https://leetcode.com/problems/different-ways-to-add-parentheses/description/
本题若直接对表达式进行组合,考虑的情况非常多,但是可以采用分治的思想将复杂的大问题化简为若干个小问题进行求解。
下面以表达式2 * 3 - 4 * 5为例进行分析。
在这里插入图片描述
其实就是化简为左右两部分,然后再对每一部分进行计算,直至子问题规模为1,即左右部分只有一个元素。

class Solution:
    def diffWaysToCompute(self, input):
        """
        :type input: str
        :rtype: List[int]
        """
        if input.isdigit():
            return [int(input)]
        
        res = []
        for i in range(len(input)):
            if input[i] in '+-*':
                res1 = self.diffWaysToCompute(input[:i])
                res2 = self.diffWaysToCompute(input[i+1 :])
                for j in res1:
                    for k in res2:
                        res.append(self.helper(j, k, input[i]))
        res.reverse()
        return res
    
    
    def helper(self, j, k, op):
        if op == '+':
            return j + k
        elif op == '-':
            return j - k
        else:
            return j * k      

在这里插入图片描述
显然,该方法有待改进。


2020年9月2日更新
现提供动态规划解法,至于DP核心思想后面再介绍,这里只介绍本题的DP步骤,再与分治法时间作一下对比。

  1. dp[i][j] 存储区间 [i,j] 内可能的结果数值,为一个列表
  2. 先初始化 dp[i][i]
  3. 建立转移方程: dp[i][j] = dp[i][k] X dp[k+1][j]( i <= k < j)(假设当前遍历的是 dp[i][k] X dp[k+1][j], 那么它们之间的运算符即为 operator[k],枚举 dp[i][k] 与 dp[k+1][j] 之间的所有结果进行运算即可。)
class Solution:
    def diffWaysToCompute(self, input: str) -> List[int]:
        nums, operator = self.split(input)
        n = len(nums)
        dp = [[list() for _ in range(n)] for _ in range(n)]
        for i in range(n-1, -1, -1):
            dp[i][i].append(nums[i])
            for j in range(i + 1, n):
                # 状态转移方程有k控制
                # 对于本题举例
                # dp[0][3] = dp[0][0] X dp[1][3]
                # dp[0][3] = dp[0][1] X dp[2][3]
                # dp[0][3] = dp[0][2] X dp[3][3]
                for k in range(i, j):
                    for a in dp[i][k]:
                        for b in dp[k+1][j]:
                            if operator[k] == '+':
                                dp[i][j].append(a + b)
                            if operator[k] == '-':
                                dp[i][j].append(a - b)
                            if operator[k] == '*':
                                dp[i][j].append(a * b)
        return sorted(dp[0][-1])

    def split(self, input: str):
        nums, operator, chars, i = [], [], list(input), 0
        op = ['+', '-', '*']
        while i < (length := len(input)):
            if chars[i] in op:
                operator.append(chars[i])
                i += 1
            else:
                val = []
                while i < length and '0' <= chars[i] <= '9':
                    val.append(chars[i])
                    i += 1
                nums.append(int(''.join(val)))
        return nums, operator

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值