【ONE·基础算法 || 记忆化搜索】

在这里插入图片描述

总言

  主要内容:编程题举例,熟悉理解记忆化搜索类题型(对比递归、动态规划理解运用)。
  
  
  
  

文章目录

  • 总言
  • 1、记忆化搜索
    • 1.1、基本介绍
    • 1.2、细节理解(记忆搜索化、递归、动态规划……)
  • 2、斐波那契数(easy)
    • 2.1、递归版
    • 2.2、记忆化搜索版
    • 2.3、动态规划版
  • 3、不同路径(medium)
    • 3.1、递归版(DFS)
    • 3.2、记忆化搜索版
    • 3.3、动态规划版
  • 4、最长递增子序列(medium)
    • 4.1、记忆化搜索版
    • 4.2、动态规划版
  • 5、猜数字大小II(medium)
    • 5.1、题解
  • 6、矩阵中的最长递增路径(hard)
    • 6.1、题解
  • Fin、共勉。

  
  
  
  
  

1、记忆化搜索

1.1、基本介绍

  1)、记忆搜索化是什么?主要用来解决什么问题的?
  为了探究记忆搜索化的用途,我们以下述第一道题:斐波那契数为例,进行说明。

  递归版的斐波那契数写法见下述:由递归展开图可知,假如我们要计算 d ( 5 ) d(5) d(5),则需要先计算 d ( 4 ) d(4) d(4) d ( 3 ) d(3) d(3),而在计算 d ( 3 ) d(3) d(3) 时还需要计算 d ( 2 ) d(2) d(2) d ( 1 ) d(1) d(1) 。这会带来一个问题: d ( 4 ) d(4) d(4) d ( 3 ) d(3) d(3) d ( 2 ) d(2) d(2) d ( 1 ) d(1) d(1) 都进行了多次计算,即出现了大量重复计算的子问题。

在这里插入图片描述

  那么,有什么方法对其进行优化?
  
  回答:为了避免此类重复计算,在递归时,我们可以使用一个备忘录(本质是一个数组或哈希表)来保存已经计算过的状态及其对应的结果。 这样,在后续递归过程中,每次调用可先检查一下所需的结果是否已经被计算并保存过? 若是,则直接从备忘录中返回所需结果;若否,则进行递归计算,同时将结果保存在备忘录中,以便后续使用。如此,就避免了重复计算问题。(也可以把它理解为一种剪枝操作)

在这里插入图片描述

  这也就是记忆搜索化。一种结合了搜索和动态规划思想的算法策略。其核心思想是在搜索过程中,对于已经计算过的状态或子问题的解进行保存,当再次遇到相同的状态或子问题时,直接使用之前保存的结果,从而避免重复计算,提高算法效率。
  
  
  
  
  2)、如何实现记忆搜索化?(一般性流程步骤 )

  1、在常规的递归基础上,添加一个备忘录 (一个哈希表或数组,用于存储已经计算过的子问题的结果,以<参数,返回值>的键值对形式)
  2、递归每次返回的时候,将结果放到备忘录里面。
  3、在每次进入递归的时候,先检查备忘录里面是否存在所需计算结果。

  
  
  
  
  
  

1.2、细节理解(记忆搜索化、递归、动态规划……)

  1)、 所有的递归(暴搜、 深搜) ,都能改成记忆化搜索吗?
  回答:不是,只有在递归的过程中,出现了大量完全相同的问题时,才能用记忆化搜索的方式优化。

  ①记忆化搜索的优化效果主要体现在能够避免重复计算相同的子问题。 因此,只有当递归过程中存在大量重复的子问题,即 “子问题重叠”现象时,采用记忆化搜索才是有意义的。
  ②如果递归算法中的子问题都是唯一的,或者重复的子问题数量很少,那么使用记忆化搜索可能并不会带来明显的性能提升,甚至可能由于记忆化存储结构的开销而降低效率。
  
  
  

  2)、 动态规划 与 记忆化搜索
  本质: ①均属于暴力解法(暴搜),②不过在其基础上进行了一定的优化(通过把已经计算过的值存起来的方式)。
  实际上,《算法导论》中,将记忆化搜索与常规的动态规划都视为动态规划的一种形式,只是前者搜索时是以递归的方式进行的,而后者则是递推(循环)的方式。
  
  实际写代码时,选哪种方式好?
  在实际编写代码时,选择自顶向下(记忆化搜索)还是自底向上(动态规划)的方式取决于多个因素,包括问题的特性、代码的可读性、性能需求以及个人的编程习惯。
  (暴搜→记忆化搜索→动态规划)在优化级别上,在很多情况下,将暴力搜索(暴搜)优化为记忆化搜索已经足够满足性能需求,而且这样的优化通常比完全重写为动态规划版本更加简单和直接。因此,在实际应用中,如果记忆化搜索已经足够好,那么可能没有必要再进一步将其改写为动态规划版本。
  
  
  

  3)、 带备忘录的递归 vs 带备忘录的动态规划 vs 记忆化搜索
  回答:根据2)可知,它们本质都是一回事。都利用了“记忆”或“存储”已经计算过的结果来避免重复计算,从而提高算法效率。只不过,它们在实现和应用上存在细节上的差别。
  
  
  

  4)、 自顶向下和 vs 自低向上
  自顶向下和自底向上的方法代表了两种不同的思考策略,它们的核心区别在于处理问题的顺序

  自顶向下(Top-Down) 方法通常从问题的最高层次(即整体或宏观层面)开始,逐步细化到更低层次的具体细节。这种方法的一个典型例子是递归算法和记忆化搜索。 在递归算法中,我们首先尝试解决整个问题,然后将其分解为更小的子问题。如果子问题已经被解决过(通过记忆化),则直接返回结果;否则,递归地解决子问题。这种方法的优势在于直观易理解,但如果不加记忆化,可能会导致大量的重复计算。
  
  自底向上(Bottom-Up) 方法则相反,它从问题的最低层次(即微观层面)开始,逐步构建出更高层次的解决方案。动态规划是这种方法的典型代表。 在动态规划中,我们首先解决所有可能的子问题,并将它们的解存储在表格或数组中。然后,通过组合这些子问题的解来构建出原问题的解。这种方法避免了重复计算,但可能需要更多的存储空间来保存中间结果。
  
  
  
  
  
  
  
  

2、斐波那契数(easy)

  题源:链接。

在这里插入图片描述
  
  

2.1、递归版

  1)、一些说明
  在上述我们介绍过记忆化搜索、递归相关理论部分的知识,这里是具体实现(动态规划相关专题会另写博文介绍,这里不做展开)。
  下述版本重点在于理解递归版如何到记忆化搜索版,理解学习记忆化搜索的具体实现细节,对比递归版理解自顶向下和自底向上。
  
  2)、题解

class Solution {
    
public:
    int fib(int n) {
        return DFS(n);
    }

    // 使用递归的方式
    int DFS(int n)
    {
        if(n == 0 || n == 1)
            return n;

        return DFS(n-1) + DFS(n-2);
    }
};

  
  
  
  

2.2、记忆化搜索版

  a、 加上⼀个备忘录;
  b、 每次进⼊递归的时候,去备忘录里看看;
  c、 每次返回的时候,将结果加入到备忘录中

class Solution {
    // 使用一个备忘录:用于存储曾经获取的结果值
    int memo[31];// 题目条件:0 <= n <= 30
    
public:
    int fib(int n) {
        memset(memo,-1,sizeof(memo));//void * memset ( void * ptr, int value, size_t num );
        return DFS(n);
    }
    
    // 记忆化搜索版
    int DFS(int n)
    {
        // 递归到当前层时:先查找备忘录,看该值是否已经计算过
        if(memo[n] != -1) return memo[n];

        // 来到此处,说明备忘录中没记录过该值,可以递归计算
        if(n == 0 || n == 1)
        {
            memo[n] = n;// 递归返回前,先将数据记录入备忘录中
            return n;
        }

        memo[n] = DFS(n-1) + DFS(n-2);// 递归返回前,先将数据记录入备忘录中
        return memo[n];
    }
};

  
  
  
  

2.3、动态规划版

  无非是将递归的那一套转换成了动态规划的那一套(这种先暴搜→再记忆化搜索→再改为动态规划的方式,不是任何动态规划都能用这个思路推导得出的。
  a、递归含义 → 状态表示;
  b、函数体 → 状态转移方程;
  c、递归出口 → 初始化。

class Solution {
public:
	// 动态规划版
    int fib(int n) {

        int dp[31];// 确定状态表示:dp[i]第i个斐波那契数
        dp[0] = 0, dp[1] = 1;// 初始化状态

        for(int i = 2; i <= n; ++i)
        {
            dp[i] = dp[i-1] + dp[i-2];//根据状态转移方程,填入数据
        }

        return dp[n];// 确定返回值。
    }
};

  
  
  
  
  
  
  
  
  
  

3、不同路径(medium)

  题源:链接。

在这里插入图片描述
  
  

3.1、递归版(DFS)

  1)、思路分析
在这里插入图片描述

  在普通递归版本中: 将要求位置传入递归函数中DFS(i,j),不管其过程如何,最终会为我们返回到达(i,j)位置的路径总数:有DFS(i,j) = DFS(i-1,j) + DFS(i, j-1)
  
  
  
  2)、题解
  简单的DFS、递归: 能解,但会超时。
  这种是正着的写法,上述思路解析介绍的是倒着的写法。

class Solution {
    int ret = 0;// 记录最终返回结果
    int x;
    int y;
public:
    int uniquePaths(int m, int n) {
        x = m -1, y = n-1;//下标实则为m-1,n-1
        DFS(0,0);// 从(0,0)开始,向右或向下,走到(m-1,n-1)位置
        return ret;
    }

    void DFS(int i, int j)
    {   
        // 若当前i,j位置即终点位置,统计一次路径。
        if(i == x && j == y)
        {
            ++ret;
            return;
        }

        // 向右遍历
        if(j+1 <= y) DFS(i,j+1);
        // 向下遍历
        if(i+1 <= x) DFS(i+1,j);
    }
};

  另一种写法:本质一样,只是这里是DFS采用了返回值的形式。

class Solution {

public:
    int uniquePaths(int m, int n) {
        return DFS(m-1,n-1);
    }

    int DFS(int i, int j)
    {
        
        if(i < 0 || j < 0) return 0;// 越界的情况
        if(i == 0 && j == 0) return 1;// 此时在起点位置,路径只有一条


        // 要计算当前能到达(i,j)位置的路径,只需要计算出能到达(i-1,j)和(i,j-1)两处的路径即可
        return DFS(i-1,j) + DFS(i,j-1);
    }
};

  
  
  

3.2、记忆化搜索版

  1)、分析
  能否将上述暴搜改为记忆化搜索版本?关键在于递归过程中是否出现重复的子问题。
  回答:可以改成记忆搜索化版本。这里在求终点的路径时,自顶向下递归调用过程中,会多次经过同一位置DFS(a,b)。因此,我们可以用一个备忘录将每次经过的DFS(a,b)存储,以便后续递归调用时直接返回。
在这里插入图片描述
  由于这里是二维数组(i,j),而备忘录以<可变参数,返回值>的键值对形式出现,这里的可变参数是元素下标位置。
  

  
  
  2)、题解
  这里,用于充当备忘录的二维数组memo可以写成类成员变量的形式,也可以写在函数中作为参数传递。

class Solution {
    vector<vector<int>> memo;
public:
    int uniquePaths(int m, int n) {
        // 初始化
        memo = vector<vector<int>>(m,vector<int>(n));// 这里我们从(0,0)作为原点计算。
        memo[0][0] = 1;
        return DFS(m-1,n-1);
    }

    int DFS(int i, int j)
    {
        // 越界处理
        if(i < 0 || j < 0) return 0;

        if(memo[i][j] != 0)// 记忆化搜索:先在备忘录中寻找当前值是否曾经计算过。
        {
            return memo[i][j];
        }

        // 要计算当前能到达(i,j)位置的路径,只需要计算出能到达(i-1,j)和(i,j-1)两处的路径即可
        memo[i][j] = DFS(i,j-1) + DFS(i-1,j);// 记忆化搜索:返回前,先将值存入备忘录
        return memo[i][j];
    }
};

  
  
  
  
  

3.3、动态规划版

  状态表示:二维数组,dp[i][j],以(i,j)位置为结尾,表示到达(i,j)位置时的路径总数。
  状态转移方程:dp[i][j] = dp[i-1][j] + dp[i][j-1]
  细节点:这里需要注意 i == 0 (首行)或者 j == 0 (首列)的时候,会发生越界行为。 根据题目描述可推测得,从(0,0)到这些位置无非只有一条路径可走(要么一直往右走、要么一直往下走),因此,对于这一行一列,可以单独拎出处理:dp[i][j] = 1

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp(m, vector<int>(n));//m×n矩阵
        dp[0][0] = 1 ;// 起始点位置:这里以(0,0)为起点
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(i == 0 && j == 0) continue;
                if(i == 0 || j == 0) dp[i][j] = 1;
                else
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m-1][n-1];//根据最初定的起点来确定终点
    }
};

  若不想初始化处理首行、首列。此时要避免越界行为,可以开辟(m+1)×(n+1)的矩阵,以(1,1)位置作为起始点。相当于此时i == 0的行和j==0的列是空出来的(引入虚拟节点的写法):

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp(m + 1, vector<int>(n + 1));// m+1行,n+1列矩阵
        dp[1][1] = 1;// 起始点位置:这里以(1,1)为起点
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= n; j++) {
                if (i == 1 && j == 1)
                    continue;
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];//实则本质相同,在处理首行、首列时,仍旧只是一条路径
            }
        return dp[m][n];
    }
}

  
  
  
  
  
  
  

4、最长递增子序列(medium)

  题源:链接。

在这里插入图片描述  
  

4.1、记忆化搜索版

  1)、思路分析
  
在这里插入图片描述

  
  2)、题解

class Solution {
    vector<int> memo;// 备忘录:用于记忆化搜索
public:
    int lengthOfLIS(vector<int>& nums) {
        memo.resize(nums.size());
        int maxsize = 0;
        for(int i = 0; i < nums.size(); ++i)
        {
            maxsize = max(DFS(nums,i),maxsize);
            // 不确定以哪一个位置为起点才是最长的递增子序列,因此这里要一一对比一边
        }
        return maxsize;
    }

    // pos位置的元素为子序列上一层选定的序列值
    int DFS(vector<int>& nums, int pos)
    {
        // 若当前选择pos的最大子序列曾记录在备忘录内,则直接获取返回
        if(memo[pos]) return memo[pos];

        // 若备忘录中无记录,则递归查找当前最大子序列
        int maxsize = 1;// 选择下一层递归序列值:pos位置处的决策可以有很多分支,我们只要其中长度最大的分支
        for(int i = pos + 1; i < nums.size(); ++i)
        {   
            if(nums[i] > nums[pos])// 满足严格递增,可选该值
            {
                int ret =  DFS(nums,i) + 1;// 获取从该值往下递归的结果+将当前pos也算入
                maxsize = max(ret,maxsize);// 只记录最大子序列
            }
        }
        memo[pos] = maxsize;// 将当前pos选出的最大子序列记录入备忘录中
        return memo[pos];
    }
};

  
  
  
  

4.2、动态规划版

  1)、思路分析
  确定状态表示: dp[pos]表示以pos位置为起点的最长递增子序列长度。
  填表顺序: 根据题目,要确定当前pos位置的序列,需要依赖[pos+1, n-1]区间内的元素。因此,这里的填表顺序为从后往前填。
  状态转移方程: dp[pos] = max(dp[pos], dp[pos + i] + 1)。由于一个位置处的子序列有多个,而dp[pos]只需要最长递增子序列,因此这里实则是要遍历[pos+1, n-1],比较获取其中最长的递增序列长度,+1即可获得到当前序列的最长长度。
  
  2)、题解

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        // 动态规划
        int n = nums.size();
        vector<int> dp(n,1);// 初始化状态表示:自身位置处序列个数为1

        int maxsize = 0;// 用于统计最长子序列

        // 根据题目,要知道i位置处的最长子序列,则需要知道其后续[i+1,n)位置处的子序列(即,i后应该选谁)
        for(int i = n-1; i >= 0; --i)///所以这里的填表顺序是从右到左
        {
            for(int j = i + 1 ; j < n; ++j)//找[i+1,n)中最长的子序列,+i位置即可获取i处最长子序列
            {
                if(nums[j] > nums[i])
                {
                    dp[i] = max(dp[i],dp[j] + 1);
                }
            }
            maxsize  = max(dp[i],maxsize);//dp[i]统计的是i位置处的最长子序列,maxsize记录的是0~n-1中最长子序列
        }
        return maxsize;
    }
};

  
  
  
  
  
  
  

5、猜数字大小II(medium)

  题源:链接。

在这里插入图片描述
  
  

5.1、题解

  1)、思路分析
  此时实则在模拟猜数字的过程。可将整体分为如下:
  1)、对[1,n]个数,在猜数字时可以随机选择其中任意一个数字作为起始决策值。由此,可获得n棵决策树。当我们选择不同的策略,最终花费的金额各不相同,根据题目要求,要选出能获胜的最小现金数,这就意味着我们要在所有决策树中找最优解(金额最小的决策树)
在这里插入图片描述

  2)、对单棵决策树,由于题目中目标数字是随机的,我们要保证无论给定的是哪一个目标值(即无论哪一条分支),我们的金额都能支付得起,如此才能胜券在握。这就意味着我们要支付的金额为当前单棵决策树的分支最大值。
在这里插入图片描述
  
  是否可以使用记忆化搜索?
  如下图,在递归过程中,每次选出一个数i,若其不满足目标值,则需要在左右区间选数,这里区间[left,right]在选数时会出现重复,故可以使用备忘录。只不过这里备忘录我们记录的是左右两区间,故需要一个二维数组。
在这里插入图片描述

  
  
  2)、题解

class Solution {
    vector<vector<int>> memo;// 备忘录
public:
    int getMoneyAmount(int n) {
        memo = vector<vector<int>>(n+1,vector<int>(n+1,0));
        return DFS(1,n);
    }

    // 在区间为[left,right]中,选择位置选择一个数,作为决策树的起始位置
    int DFS(int left, int right)
    {
        if(left >= right)
        {
            return 0;// 选中数字(猜对),无需支付金额;
        }
        if(memo[left][right]) return memo[left][right];

        int minmoney = INT_MAX;// 用于记录所有决策树方案中,所得金额最小的决策方案(因为要是最小值,所以用INT的最大值标记一下)
        for(int i = left; i <= right; ++i)// 选择数i作为起始决策位置
        {
            int x = DFS(left,i-1);// 若数i猜大了:在[left,i-1]继续选数
            int y = DFS(i+1,right);// 若数i猜小了:在[i+1,right]继续选数
            int ret = max(x,y) + i;// 对单颗决策树,要确保金额能满足即使最糟糕情况也能获胜(故而选择最大分支值+还需要加上当前i位置的金额值)
            minmoney = min(minmoney, ret);// 对所有决策树,选择一个使用金额最小的决策方案。
        }
        memo[left][right] = minmoney;
        return minmoney;
    }
};

  
  
  
  
  
  
  
  
  

6、矩阵中的最长递增路径(hard)

  题源:链接。

在这里插入图片描述

  
  

6.1、题解

  1)、思路分析
  此题即常规的DFS+一个备忘录。DFS遍历四周的方法我们在先前章节中介绍过,可以使用备忘录是因为对于每个位置(i,j),都有反复经过的可能,因此使用一个二维数组作为备忘录,memo[i][j]表示在[i][j]位置处的最长递增路径长度。
  
  2)、题解

class Solution {
    int memo[201][201];
    int m,n;
public:
    int longestIncreasingPath(vector<vector<int>>& matrix) {
        m = matrix.size(); n = matrix[0].size();
        int ret = 0;//用于记录所有起始点中,最长的一条路径。
        for(int i = 0; i < m; ++i) // 选择某一点作为路径起始点
        {
            for(int j = 0; j < n; ++j)
            {
                ret = max(DFS(matrix,i,j),ret);
            }
        }
        return ret;
    }

    int dx[4] = {-1, 1, 0, 0};
    int dy[4] = {0, 0, -1, 1};
    int DFS(vector<vector<int>>& matrix, int i, int j)
    {
        //  如果备忘录中记录过(i,j)位置的最长递增路径,直接返回
        if(memo[i][j] != 0) return memo[i][j];

        // 若没记录过,则向四周移动寻找最长递增路径
        int maxpath = 1;// 用于统计这四个方向中,路径递增且最长的一次
        for(int k = 0; k < 4; ++k)
        {
            int x = i + dx[k]; 
            int y = j + dy[k];
            if(x >= 0 && x < m && y >= 0 && y < n && matrix[x][y] > matrix[i][j])
            {   // 路径合法,且严格递增,则往该方向继续走
                maxpath = max(DFS(matrix,x,y)+1, maxpath);
            }
        }
        // 来到此处,说明四周均判断完毕,记录当前(i,j)找出的最长递增路径,返回
        memo[i][j] = maxpath;
        return maxpath;
    }
};

  
  
  
  
  
  
  
  
  
  
  
  
  

Fin、共勉。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/719762.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智源联合多所高校推出首个多任务长视频评测基准MLVU

当前&#xff0c;研究社区亟需全面可靠的长视频理解评估基准&#xff0c;以解决现有视频理解评测基准在视频长度不足、类型和任务单一等方面的局限性。因此&#xff0c;智源联合北邮、北大和浙大等多所高校提出首个多任务长视频理解评测基准MLVU&#xff08;A Comprehensive Be…

利用K8S技术栈打造个人私有云

1.三个节点&#xff1a;master&#xff0c;slave&#xff0c;client 在Kubernetes集群中&#xff0c;三个节点的职责分别如下&#xff1a; Master节点&#xff1a; docker&#xff1a;用于运行Docker容器。 etcd&#xff1a;一个分布式键值存储系统&#xff0c;用于保存Kuberne…

AI + 3D:用单个图像和文本提示创建可交互的3D世界

你是否曾经梦想过只需一张照片和一些简单的文字描述,就能立即进入一个生动的3D虚拟世界?今天,我们将介绍一个革命性的技术,它就像是一台神奇的3D场景制造机,能够根据你的想象快速构建出令人惊叹的虚拟空间。 一、技术概览 这项技术不仅仅是一个简单的图像到3D的转换工具…

PCB雕刻切割用德国自动换刀主轴SycoTec 4033 AC-ESD

随着电子行业的蓬勃发展&#xff0c;印刷电路板&#xff08;PCB&#xff09;的应用范围正在迅速扩大&#xff0c;涵盖了通信、计算机、消费电子等诸多领域。伴随着PCB的广泛应用&#xff0c;对PCB板切割加工技术的要求也日益严格。高速电主轴作为分板机的关键零部件之一&#x…

【vue3|第10期】Vue3中watchEffect详解

日期&#xff1a;2024年6月10日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

CSS详解

盒子模型&#xff08;box-sizing&#xff09; line-height与height CSS选择符和可继承属性 属性选择符&#xff1a; 示例&#xff1a;a[target"_blank"] { text-decoration: none; }&#xff08;选择所有target"_blank"的<a>元素&#xff09; /* 选…

63、上海大学:MSConvNet-多尺度卷积神经网络解码大鼠运动疲劳数据[攒劲的模型来喽]

1、介绍&#xff1a; 文章&#xff1a;<A multiscale convolutional neural network based on time-frequency features for decoding rat exercise fatigue LFP >&#xff0c;本文由上海大学于2024.4.8日发表于<Biomedical Signal Processing and Control >&…

【启明智显产品介绍】Model4 工业级HMI芯片详解系列专题(一):芯片性能

Model4 工业级HMI芯片详解系列专题&#xff08;一&#xff09;【芯片性能】 Model4系列工业级MPU是国产自主面向工业应用的RISC-V架构的应用级芯片&#xff0c;内置玄铁64bit RISC-V CPU C906&#xff0c;主频高达600MHz&#xff0c;算力约1380DMIPS。 Model4系列工业级MPU具…

App上架和推广前的准备

众所周知&#xff0c;App推广的第一步是上架各大应用下载市场&#xff0c;然后才是其他推广渠道。所以本文主要分两部分&#xff0c;第一部分主要介绍的是上架各大应用市场方面的准备&#xff0c;第二部分主要介绍的是其他渠道推广方面的准备。 一、App上架前的准备 1.1 上架…

演示:WPF开发的Diagram自动化流程图应用

一、目的&#xff1a;演示Diaram应用功能 二、预览 三、功能列表 功能模块 通用测试 流程图 仪器仪表 机器人 网络通信测试 PLC测试 轮毂生产线流程测试 图像处理 目标检测 绘图 思维导图 图表 流程图功能 模板管理 工程管理 模块许可管理 工具栏 开始 停止 删除 清除 …

任务3.8.3 利用RDD统计每日新增用户

任务目标 统计给定用户访问历史数据中&#xff0c;每日的新增用户数量。 数据准备 原始数据格式&#xff1a;每行包含两个字段&#xff0c;日期和用户名&#xff0c;以逗号分隔。示例数据&#xff1a;2024-05-01,mike 2024-05-01,alice 2024-05-01,brown ...解决方案 使用倒…

一平台一张图,撑起危化生产“安全伞”

安全生产是永恒的主题&#xff0c;是一切工作的基础。 风险辨识不到位、特种作业不合规、隐患治理不彻底、应急能力不匹配……如何从消除事故隐患、从根本上解决问题&#xff1f;随着新一代信息技术和安全生产的深度融合&#xff0c;安全生产的管理方式也在发生深刻变化。 提前…

docker怎么拉取全部镜像,打包所有镜像

因为docker&#xff0c;所以我把电脑上之前的镜像全部打包出来了 你们也可以打包&#xff0c;我提供一个脚本&#xff0c;你运行即可 export_docker.sh #!/bin/bash# 导出目录 EXPORT_DIR"docker_images_backup" mkdir -p "$EXPORT_DIR"# 获取所有镜像 …

苹果电脑压缩视频的软件,苹果电脑怎么压缩视频文件大小

在数字时代的浪潮中&#xff0c;视频已成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;视频文件的大小也在不断攀升&#xff0c;给存储和传输带来了不小的挑战。因此&#xff0c;视频压缩技术应运而生&#xff0c;成为解决这一问题的关键。本文将详细介绍视频压缩…

DS18B20温度传感器完整使用介绍(配合51单片机)

DS18B20是一款由Maxim Integrated&#xff08;原Dallas Semiconductor&#xff09;生产的数字温度传感器&#xff0c;以其高精度、低功耗、灵活的接口方式和易于使用的特性&#xff0c;在各种温度监测应用中被广泛采用。 以下是DS18B20的详细介绍&#xff1a; 基本特性 数字输…

Vue3学习日记(day3)

目录详解&#xff1a; 简单解释&#xff1a; 详细解释&#xff1a; .vscode public assets compents router views app.vue package.json package-lock.json 区别 探究文档 应用配置​ 语法合集 插值表达式​ V- HTML&#xff08;易造成xss漏洞&#xff09;​…

AMEYA360代理品牌 | 思瑞浦发布高精度12位8通道SAR ADC-TPC502200

聚焦高性能模拟芯片和嵌入式处理器的半导体供应商思瑞浦3PEAK(股票代码&#xff1a;688536)全新推出TPC502200&#xff0c;支持I2C接口的12位8通道SAR ADC。 TPC502200集成了高精度基准源&#xff0c;同时可在极端温度范围(-40C至125C)下稳定工作。TPC502200凭借强大的性能优势…

基于协同过滤算法的电影推荐

基于协同过滤算法的电影推荐 电影推荐系统使用了基于**协同过滤&#xff08;Collaborative Filtering&#xff09;的算法来生成推荐。具体来说&#xff0c;使用了基于用户的协同过滤&#xff08;User-Based Collaborative Filtering&#xff09;**算法&#xff0c;步骤如下&am…

网络安全:什么是SQL注入

文章目录 网络安全&#xff1a;什么是SQL注入引言SQL注入简介工作原理示例代码 攻击类型为什么SQL注入危险结语 网络安全&#xff1a;什么是SQL注入 引言 在数字化时代&#xff0c;数据安全成为了企业和个人最关心的问题之一。SQL注入&#xff08;SQL Injection&#xff09;是…

vue大作业-实现学校官网

vue大作业-实现学校官网 基于vue2实现的学校官网 项目展示 学校官网介绍 欢迎访问我们学校的官方网站&#xff0c;这里为您提供了全面的信息和资源&#xff0c;帮助您更好地了解我们的教育理念、教学资源和学术活动。 首页 首页是您了解我们学校的起点。这里展示了学校的最…