算法:记忆化搜索

文章目录

记忆化搜索的原理其实很简单,简单来说就是对暴力搜索的一些优化,因此整体上来讲难度不高

记忆化搜索

所谓记忆化搜索,直白来说就是一个带有备忘录的递归

如何实现记忆化搜索?

  1. 添加一个备忘录
  2. 递归每次返回的时候,都把结果放在备忘录当中
  3. 每次进行递归前,都到备忘录中看一看

下面用一个经典题目诠释记忆化搜索的意义

斐波那契数列

  1. 递归
cpp 复制代码
class Solution 
{
public:
    // 递归
    int fib(int n) 
    {
        if(n == 0 || n == 1) return n;
        return fib(n - 1) + fib(n - 2);
    }
};
  1. 动态规划
cpp 复制代码
class Solution 
{
public:
    // 动态规划
    int fib(int n) 
    {
        if(n == 0 || n == 1)
            return n;
        vector<int> v(n + 1);
        v[0] = 0, v[1] = 1;
        for(int i = 2; i <= n; i++)
            v[i] = v[i - 1] + v[i - 2];
        return v[n];
    }
};
  1. 记忆化搜索
cpp 复制代码
class Solution 
{
public:
    // 记忆化搜索
    int memo[31];
    int fib(int n) 
    {
        // 先到备忘录中看看
        if(memo[n] != 0)
            return memo[n];
        if(n == 0 || n == 1)
        {
            memo[n] = n;
            return memo[n];
        }
        return fib(n - 1) + fib(n - 2);
    }
};

从上面这个例题能感觉出来,记忆化搜索其实就是在递归的基础上进行了一些优化,没有什么本质性的新增内容,基于这个原因,用下面的例题来进一步学习记忆化搜索

例题

不同路径


暴力搜索

cpp 复制代码
class Solution 
{
public:

    int dfs(int m, int n, int p, int q)
    {
        if(m > p || n > q) return 0;
        if(m == p && n == q) return 1;
        return dfs(m + 1, n, p, q) + dfs(m, n + 1, p, q);
    }

    int uniquePaths(int m, int n) 
    {
        return dfs(0, 0, m - 1, n - 1);
    }
};

采用记忆化搜索进行一定程度的优化

cpp 复制代码
class Solution 
{
public:
    int arr[101][101];
    int dfs(int m, int n, int p, int q)
    {
        if(arr[m][n] != 0) return arr[m][n];
        if(m > p || n > q) return 0;
        if(m == p && n == q) return 1;
        int down = dfs(m + 1, n, p, q);
        int right = dfs(m, n + 1, p, q);
        arr[m + 1][n] = down;
        arr[m][n + 1] = right;
        return down + right;
    }

    int uniquePaths(int m, int n) 
    {
        return dfs(0, 0, m - 1, n - 1);
    }
};

最长递增子序列

暴力搜索

cpp 复制代码
class Solution
{
public:
	vector<int> path;
	int maxSize;
	int lengthOfLIS(vector<int>& nums)
	{
		dfs(0, nums, INT_MIN);
		return maxSize;
	}

	void dfs(int pos, vector<int>& nums, int prev)
	{
		maxSize = max(maxSize, (int)path.size());

		for (int i = pos; i < nums.size(); i++)
		{
			if (nums[i] > prev)
			{
				path.push_back(nums[i]);
				dfs(i + 1, nums, nums[i]);
				path.pop_back();
			}
		}
	}
};

记忆化搜索

cpp 复制代码
class Solution 
{
public:
    int memo[2501];

    int lengthOfLIS(vector<int>& nums) 
    {
        int ret = 0;
        for(int i = 0; i < nums.size(); i++)
        {
            ret = max(ret, dfs(i, nums));
        }
        return ret;
    }

    int dfs(int pos, vector<int>& nums)
    {
        if(memo[pos] != 0) return memo[pos];
        int ret = 1;
        for(int i = pos + 1; i < nums.size(); i++)
        {
            if(nums[i] > nums[pos])
            {
                ret = max(ret, dfs(i, nums) + 1);
            }
        }
        memo[pos] = ret;
        return ret;
    }
};

猜数字大小


暴力搜索

cpp 复制代码
class Solution 
{
public:
    int getMoneyAmount(int n) 
    {
        return dfs(1, n);
    }

    int dfs(int begin, int end)
    {
        if(begin >= end) return 0;
        int res = INT_MAX;
        // 选一个节点作为根节点
        for(int i = begin; i <= end; i++)
        {
            // 找左子树花费的钱
            int left = i + dfs(begin, i - 1);
            // 找右子树花费的钱
            int right = i + dfs(i + 1, end);
            res = min(res, max(left, right));
        }
        return res;
    }
};

记忆化搜索优化

cpp 复制代码
class Solution 
{
public:
    vector<vector<int>> memo;
    int getMoneyAmount(int n) 
    {
        memo.resize(n + 1, vector<int>(n + 1));
        return dfs(1, n);
    }

    int dfs(int begin, int end)
    {
        if(begin >= end) return 0;
        if(memo[begin][end] != 0) return memo[begin][end];
        int res = INT_MAX;
        // 选一个节点作为根节点
        for(int i = begin; i <= end; i++)
        {
            // 找左子树花费的钱
            int left = i + dfs(begin, i - 1);
            // 找右子树花费的钱
            int right = i + dfs(i + 1, end);
            res = min(res, max(left, right));
        }
        memo[begin][end] = res;
        return res;
    }
};

矩阵中的最长递增路径


记忆化搜索

cpp 复制代码
class Solution 
{
public:
    int m, n;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    vector<vector<int>> memo;
    int longestIncreasingPath(vector<vector<int>>& matrix) 
    {
        m = matrix.size();
        n = matrix[0].size();
        memo.resize(m, vector<int>(n));
        int res = 0;
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                res = max(res, dfs(i, j, matrix));
            }
        }
        return res;
    }

    // 从第i行和第j列的这个元素开始的最长递增路径
    int dfs(int i, int j, vector<vector<int>>& matrix)
    {
        if(memo[i][j] != 0) return memo[i][j];
        int ret = 1;
        // 长度等于其四周的元素的最长递增路径
        for(int k = 0; k < 4; k++)
        {
            int x = i + dx[k], y = j + dy[k];
            // 如果坐标合法并且是递增
            if(x >= 0 && x < m && y >= 0 && y < n && matrix[x][y] > matrix[i][j])
            {
                ret = max(ret, 1 + dfs(x, y, matrix));
            }
        }
        memo[i][j] = ret;
        return ret;
    }
};
相关推荐
Jasmine_llq12 分钟前
《AT_arc081_d [ARC081F] Flip and Rectangles》
算法·动态规划(dp)·贪心思想扩展 / 收缩边界·预处理转换网格状态·二维数组遍历实现逐点计算
Desirediscipline2 小时前
#define _CRT_SECURE_NO_WARNINGS 1
开发语言·数据结构·c++·算法·c#·github·visual studio
范纹杉想快点毕业2 小时前
C语言550例编程实例说明
算法
小O的算法实验室2 小时前
2026年SEVC SCI2区,面向无人机路径规划的领域专用算子进化算法,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
weixin_477271692 小时前
同人象:(两军停战谈判结盟的现场直播)马王堆帛书《周易》原文及甲骨文还原周朝生活现象《函谷门
算法·图搜索算法
nudt_qxx2 小时前
CUDA编程模型与硬件执行层级对应关系
linux·人工智能·算法
m0_531237173 小时前
C语言-分支与循环语句练习2
c语言·开发语言·算法
AIpanda8883 小时前
什么是AI销冠系统和AI提效软件系统?主要区别和应用场景是什么?
算法
程序员酥皮蛋3 小时前
hot 100 第三十三 33.排序链表
数据结构·算法·链表
蚊子码农3 小时前
算法题解记录-2452距离字典两次编辑以内的单词
开发语言·算法·c#