【算法】子序列问题合集

news2024/11/17 9:51:43

前言

动态规划的核心设计思想是数学归纳法

假如我们想证明一个数学结论:

  1. 那么先假设这个结论在 k < n 时成立
  2. 想办法推导证明出 k = n 的时候此结论也成立。

是需要一个 dp 数组嘛?

  1. 可以假设 dp[0...i - 1] 都已经被算出来了
  2. 然后问自己:怎么通过这些结果算出 dp[i]
  3. 首先要定义清楚的 dp 数组的含义,即 dp[i] 的值到底代表是什么?

Tips:”子序列“ 和 ”子串“ 区别

  • 子串一定是连续的
  • 子序列不一定是连续的

子序列问题是最常见的算法问题,而且并不好解决。

一旦涉及子序列和最值,那几乎可以肯定,考察的是动态规划技巧,时间复杂度一般都是 O(n ^ 2)

既然用到动态规划,那就要定义 dp 数组,寻找状态转移关系。

两种思路:

  1. 第一种思路模板是一个一维的 dp 数组:
int n = array.length;
int [] dp = new int[n];

for (int i = 1; i < n; ++i) {
    for (int j = 0; j < i; ++j) {
        dp[i] = 最值(dp[i], dp[j] + ...)
    }
}
复制代码
  1. 第二种思路模板是一个二维的 dp 数组:
int n = arr.length;
int [][] dp = new int[n][n];

for (int i = 0; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
        if (arr[i] == arr[j]) 
            dp[i][j] = dp[i][j] + ...
        else
            dp[i][j] = 最值(...)
    }
}
复制代码

题目

(1)LeetCode 300 最长递增子序列

题目描述


给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。


示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4


示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
复制代码

思路解法


定义是这样的:dp[i] 表示以 nums[i] 这个数结尾的最长递增子序列的长度。

可以推出 base case:dp[i] 初始值为 1, 因为以 nums[i] 结尾的最长递增子序列起码要包含它自己。

public class LeetCode_300 {

    // 方法一:
    // Time: o(n^2), Space: o(n), Faster: 27.93%
    public int lengthOfLISDP(int [] nums) {
        if (nums == null || nums.length == 0) return 0;
        int n = nums.length, max = 1;
        int [] d = new int[n];
        d[0] = 1;

        for (int i = 1; i < n; ++i) {
            for (int j = 0; j < i; ++j) {
                int cur = nums[i] > nums[j] ? d[j] + 1 : 1;
                d[i] = Math.max(d[i], cur);
            }
            max = Math.max(max, d[i]);
        }
        return max;
    }

    // 方法二:
    // Time: o(n * log(n)), Space: o(n), Faster:  92.62%
    public int lengthOfLISBinarySearch(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        // 牌堆数初始化为 0
        int len = 0;
        int [] top = new int[nums.length];
        for (int x : nums) {
            int left = binarySearchInsertPosition(top, len, x);
            // 把这张牌放到牌堆顶,牌堆顶的牌是这个堆最小的
            top[left] = x;
            // 没找到合适的牌堆,新建一堆
            if (left == len) ++len;
        }
        return len;
    }
    
    private int binarySearchInsertPosition(int[] d, int len, int x) {
        int low = 0, high = len - 1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (x < d[mid]) high = mid - 1;
            else if (x > d[mid]) low = mid + 1;
            else return mid;
        }
        return low;
    }

}
复制代码

(2)LeetCode 53 最大子序和

题目描述


给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
复制代码

思路解法


题目解读:以 nums[i] 为结尾的 “最大子数组和” 为 dp[i]

使用数学归纳法来找状态转移关系:假设已经算出了 dp[i - 1], 如何推导出 dp[i] 呢?

dp[i] 有两种 “选择”:

  1. 要么与前面的相邻子数组连接,形成一个和更大的子树组
  2. 要么不与前面的子数组连接,自成一派,自己作为一个子数组。
// 要么自成一派,要么和前面的子数组合并
dp[i] = Math.max(nums[i], num[i] + dp[i - 1]);
复制代码

思路:

  1. 方法一:暴力求法,两层 for 循环
  2. 方法二:dp方法。
  3. 方法三:遍历一遍,负数 + 负数没有任何意义 前面累加值为负数,则对后面没有正向的贡献, 所以可以直接舍弃前面这段子序列的和

这里主要讲的是方法三:

public class LeetCode_53 {

    // Time: O(n), Space: O(1), Faster: 95.05%
    public int maxSumOfSubArray(int[] nums) {
        int max = Integer.MIN_VALUE, cur = 0;

        for (int i = 0; i < nums.length; ++i) {
        
            // 前面累加值为负数,对后面没有正向的贡献,可以直接舍弃前面的子序列的和
            cur = cur <= 0 ? nums[i] : (cur + nums[i]);
            max = Math.max(max, cur);
        }

        return max;
    }
}
复制代码

总结:

  • dp 大部分还是有规律可循的。

  • dp 数组的定义是 “以 nums[i] 为结尾的最大子数组和 / 最长递增子序列为 dp[i] ”。

  • 因为只有这样的定义才能使 dp[i + 1]dp[i] 建立联系,利用数学归纳发写出状态转移方程。

(3)LeetCode 152 连续子序列的最大乘积

题目描述


这个题目说的是,给你一个整数数组,你要找到乘积最大的连续子序列,然后返回它的乘积。

比如说,给你的数组是:

8, 1, -2, 4, -1

这个数组中连续子序列的最大乘积是 64,连续子序列就是数组本身。
复制代码

思路解法


解法有两种:

  1. 暴力法:两层 for 循环
  2. 动态规划:在遍历数组时候,要保留当前最大乘积、当前最小乘积
    • 当前最大乘积
    • 当前最小乘积

图解如下:

AC 代码:

public class LeetCode_152 {

    // 方式一:暴力法
    // Time: O(n ^ 2), Space: O(1), Faster: 5.01%
    public int maxProduct2(int[] nums) {
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; ++i) {
            int sum = nums[i];
            max = Math.max(max, sum);
            for (int j = i + 1; j < nums.length; ++j) {
                sum *= nums[j];
                max = Math.max(sum, max);
            }
        }
        return max;
    }

    // 方式二:动态规划
    // Time: o(n), Space: o(1), Faster: 66.15%
    public int maxProduct(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        int max = nums[0], currMax = nums[0], currMin = nums[0];

        for (int i = 1; i < nums.length; ++i) {
            int a = currMax * nums[i], b = currMin * nums[i], c = nums[i];
            currMax = max(a, b, c);
            currMin = min(a, b, c);
            max = Math.max(max, currMax);
        }

        return max;
    }

    private int max(int a, int b, int c) {
        return Math.max(Math.max(a, b), c);
    }

    private int min(int a, int b, int c) {
        return Math.min(Math.min(a, b), c);
    }
}
复制代码

(4)LeetCode 354 俄罗斯套娃信封问题

题目描述


给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。

请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。

说明: 不允许旋转信封。

示例:

输入: envelopes = [[5,4],[6,4],[6,7],[2,3]]
输出: 3 
解释: 最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
复制代码

信封嵌套问题实际上是最长递增子序列问题上升到二维,其解法就需要先按照特定的规则排序,之后转换为一个一维的最长递增子序列问题,最后用二分搜索框架中的技巧来解决。

这道题目其实是 最长递增子序列(LOngest Incresing Subsequence, LIS 的一个变种。

每次合法的嵌套是大的套小的,相当于找一个最长递增的子序列,其长度就是最多能嵌套的信封个数。

一个直接的想法就是,通过 w * h 计算面积,然后对面积进行标准的 LIS 算法。但是稍加思考就会发现这样不行,比如 1 * 10 大于 3 * 3, 但是显然这样的两个信封是无法互相嵌套的。

思路解法


思路步骤:

  1. 先对宽度 w 进行升序排序,如果遇到 w 相同的情况,则按照高度 h 降序排序。
  2. 之后把所有的 h 作为一个数组,在这个数组上计算出的 LIS 的长度就是答案。

步骤1,如图:

步骤2,如图:

public class LeetCode_354 {

    // Time: O(n * log(n)), Space: O(n), Faster: 87.03%
    public int maxEnvelopes(int[][] envelopes) {

        int n = envelopes.length;
        // 按照宽度升序排列,如果宽度一样,则按高度降序排列
        Arrays.sort(envelopes, (a, b) -> a[0] == b[0] ? b[1] - a[1] : a[0] - b[0]);

        // 对高度数组寻找 LIS
        int [] height = new int[n];
        for (int i = 0; i < n; ++i) {
            height[i] = envelopes[i][1];
        }

        return lengthOfLISBinarySearch(height);
    }

    // Time: o(n * log(n)), Space: o(n), Faster:  92.62%
    private int lengthOfLISBinarySearch(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        // 牌堆数初始化为 0
        int len = 0;
        int [] top = new int[nums.length];
        for (int x : nums) {
            int left = binarySearchInsertPosition(top, len, x);
            // 把这张牌放到牌堆顶
            top[left] = x;
            // 没找到合适的牌堆,新建一堆
            if (left == len) ++len;
        }
        return len;
    }

    private int binarySearchInsertPosition(int[] d, int len, int x) {
        int low = 0, high = len - 1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (x < d[mid]) high = mid - 1;
            else if (x > d[mid]) low = mid + 1;
            else return mid;
        }
        return low;
    }
}
复制代码

总结:

其实这种问题还可以扩展到三维,比如过说嵌套箱子,每个箱子有长、宽、高三个维度,请你计算最多能嵌套几个箱子?

按之前思路,可能会想:先把前两个维度(长和宽)按信封嵌套的思路求一个嵌套序列,最后在这个序列的第三个维度(高度)找一下 LIS,就能算出答案。

实际上,这个思路是错误的。这类问题叫做 “偏序问题”,上升到三维会使难度巨幅提升,需要借助一种高级数据结构 “树状数组”。

(5)LeetCode 1312 让字符串成为回文串的最少插入次数

题目描述


给你一个字符串 s ,每一次操作你都可以在字符串的任意位置插入任意字符。

请你返回让 s 成为回文串的 最少操作次数 。

「回文串」是正读和反读都相同的字符串。

示例 1:

输入:s = "zzazz"
输出:0
解释:字符串 "zzazz" 已经是回文串了,所以不需要做任何插入操作。
示例 2:

输入:s = "mbadm"
输出:2
解释:字符串可变为 "mbdadbm" 或者 "mdbabdm" 。
示例 3:

输入:s = "leetcode"
输出:5
解释:插入 5 个字符后字符串变为 "leetcodocteel" 。
示例 4:

输入:s = "g"
输出:0
示例 5:

输入:s = "no"
输出:1
复制代码

提示:

1 <= s.length <= 500 s 中所有字符都是小写字母。

题干分析


要找最少的插入次数,那肯定要穷举喽。

每次都可以在两个字符的中间插入任意一个字符,外加判断字符串是否为回文字符串,它的时间复杂度肯定暴增,而且是指数级的。

动态规划标准套路:

  1. 第一步要明确:状态选择
  2. 第二步要明确:dp 数组的定义
  3. 第三步:根据 “选择”,思考状态转移的逻辑

1. 第一步要明确:状态 和 选择

  1. 状态:“指针 i” 和 “指针 j
  2. 选择:“插入” 或者 “不插入”

2. 第二步要明确:dp 数组的定义

  1. dp数组的定义dp[i][j] , 对字符串 s[i..j],最少需要进行 dp[i][j] 次插入才能变成回文串。
  1. 最终答案dp[0][n - 1] 的大小(ns 的长度)
  1. base casei == j 时,dp[i][j] = 0, 因为当 i == js[i..j] 就是一个字符,本身就是回文串,所以不需要进行任何插入操作;

3. 第三步:根据 “选择”,思考状态转移的逻辑

  1. 如果 s[i] == s[j],不需要进行任何插入,只要知道如何把 s[i+1..j-1] 变成回文串即可

  2. 如果 s[i] != s[j],分情况讨论,看下文。

分析第三步:状态转移方程

想要计算 dp[i][j] 的值,能从子问题 dp[i + 1][j - 1] 推出 dp[i][j] 值嘛?

也就认为 s[i+1 .. j-1] 已经是一个回文串了,所以通过 dp[i+1][j-1] 推导 dp[i][j] 的关键在于 s[i]s[j]

  1. 如果 s[i] == s[j],不需要进行任何插入,只要知道如何把 s[i+1..j-1] 变成回文串即可。

如图:

// 翻译成代码
if (s[i] == s[j]) {
    dp[i][j] = dp[i + 1][j - 1];
}
复制代码
  1. 如果 s[i] != s[j],分情况讨论:

s[i] != s[j] 时,插入两次肯定可以让 s[i..j] 变成回文串,但是不一定是插入次数最少的。

如图:

第一步:将 s[i] 插到 s[j] 的左边

第二步:将 s[j] 插到 s[i] 的左边

特殊情况:

只需要插入一个字符即可使得 s[i..j] 变成回文,如下图:

这种情况,s[i+1..j]s[i..j - 1] 原本就是回文串,那么就不需要插入,只需要插入另一个即可。

if (s[i] != s[j]) {
    // 步骤一选择代价较小的
    // 步骤二必然要进行一次插入
    dp[i][j] = Math.min(dp[i + 1][j], dp[i][j - 1]) + 1;
}
复制代码

思路解法


状态转移方程中 dp[i][j]dp[i + 1][j]dp[i][j - 1]dp[i + 1][j - 1] 三个状态有关,为了保证每次计算 dp[i][j] 时,这三个状态都已经被计算,一般选择从下向上,从左到右遍历 dp 数组:

public class LeetCode_1312 {

    // Time: O(n ^ 2), Space: O(n ^ 2), Faster: 60.65%
    public int minInsertions(String s) {
        int n = s.length();

        // 定义: 对 s[i..j], 最少需要插入 dp[i][j] 次才能变成回文串
        // base case: dp 数组全部初始化为 0
        int [][] dp = new int[n][n];

        // 从下向上遍历
        for (int i = n - 2; i >= 0; --i) {
            // 从左向右遍历
            for (int j = i + 1; j < n; ++j) {
                // 根据 s[i] 和 s[j] 进行状态转移
                if (s.charAt(i) == s.charAt(j)) {
                    dp[i][j] = dp[i + 1][j -1];
                } else {
                    dp[i][j] = Math.min(dp[i + 1][j], dp[i][j - 1]) + 1;
                }
            }
        }
        // 根据 dp 数组的定义,题目要求的答案是 dp[0][n - 1]
        return dp[0][n - 1];
    }
}
复制代码

优化:

dp 数组的状态只和和它相邻的状态有关,所以 dp 数组是可以压缩成一维的。

public class LeetCode_1312 {

    // Time: O(n ^ 2), Space: O(n), Faster: 77.81%
    public int minInsertions(String s) {
        int n = s.length();

        int [] dp = new int[n];

        int temp = 0;
        for (int i = n - 2; i >= 0; --i) {
            // 记录 dp[i+1][j-1]
            int pre = 0;
            for (int j = i + 1; j < n; ++j) {
                temp = dp[j];

                if (s.charAt(i) == s.charAt(j)) {
                    // dp[i][j] = dp[i+1][j-1];
                    dp[j] = pre;
                } else {
                    // dp[i][j] = Math.min(dp[i + 1][j], dp[i][j - 1]) + 1;
                    dp[j] = Math.min(dp[j], dp[j - 1]) + 1;
                }
                pre = temp;
            }
        }

        return dp[n - 1];
    }
}
复制代码

(6)LeetCode 1143 最长公共子序列

题目描述


给定两个字符串 text1text2,返回这两个字符串的最长公共子序列的长度。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。

若这两个字符串没有公共子序列,则返回 0。

示例 1:

输入:text1 = "abcde", text2 = "ace" 
输出:3
解释:最长公共子序列是 "ace",它的长度为 3。


示例 2:

输入:text1 = "abc", text2 = "abc"
输出:3
解释:最长公共子序列是 "abc",它的长度为 3。


示例 3:

输入:text1 = "abc", text2 = "def"
输出:0
解释:两个字符串没有公共子序列,返回 0。
复制代码

题干分析


**最长公共子序列(Longest Common Subsequence, LCS)**是一道非常经典的面试题目,因为它的解法是典型的二维动态规划

这个算法稍微加改造就可以用于解决其他问题,所以说 LCS 算法是值得掌握的。

动态规划思路:

  1. 第一步:一定要明确 dp 数组的含义
  2. 定义 base case
  3. 找状态转移方程

1. 第一步:一定要明确 dp 数组的含义。

对于两个字符串的动态规划问题,套路是通用的,一般都需要一个二维 dp 数组。

比如对于字符串 s1s2,一般来说要构造一个这样的 DP table

dp[i][j] 含义是:对于 s1[0..i - 1]s2[0..j - 1],它们的 LCS 长度是 dp[i][j]

比如上图这个例子,dp[2][4] = 2 含义就是:对于 "ac""babc",它们的 LCS 长度是2。根据这个定义,最终想得到的答案应该是 dp[3][6]

2. 定义 base case

专门让索引为 0 的行和列表示空串,dp[0][..]dp[..][0] 都应该初始化为 0,这就是 base case

比如按照刚才 dp 数组的定义,dp[0][3] = 0 的含义是:对于空字符串 """bab",其 LCS 的长度为 0。

因为有一个字符串是空串,它们的最长公共子序列的长度显然应该是 0

3. 找状态转移方程

做 “选择”。

s1s2 的最长公共子序列,设:子序列为 lcs

那么对于 s1s2 中的每个字符,有什么选择?

很简单,两种选择,要么在 lcs 中,要么不在。

如图:

对于 s1[i]s2[j],怎么知道它们到底在不在 lcs 中?

可以很容易想到的是,如果某个字符在 lcs 中,那么这个字符肯定同时存在与 s1s2 中,因为 lcs 是最长公共子序列。

dp(i, j) 表示 s1[0...i]s2[0...j] 中最长公共子序列的长度,这样就可以找到状态转移关系:

  1. 如果 s1[i] == s2[j]

说明这个公共字符一定在 lcs 中,如果知道了 s1[0..i-1]s2[0..j-1] 中的 lcs 长度,再加 1 就是 s1[0..i]s2[0..j]lcs 的长度。 根据 dp 函数的定义,如下:

if (str1[i] == str2[j]) dp[i][j] = dp(i - 1, j - 1) + 1;
复制代码
  1. 如果 s1[i] != s2[j]

说明 s1[i]s2[j] 这两个字符至少有一个不在 lcs 中,那到底是哪个字符不在 lcs 中呢? 根据 dp 函数的定义,如下:

if (str1[i] != str2[j]) dp[i][j] = Math.max(dp(i - 1, j), dp(i, j - 1));
复制代码

明白了状态转移方程,可以直接写出解法。

思路解法


思路:

  1. 二维数组 dp
  2. dp 压缩
public class LeetCode_1143 {
    // Time: O(n ^ 2), Space: O(m * n), Faster: 72.28%
    public int longestCommonSubsequence(String text1, String text2) {

        int m = text1.length(), n = text2.length();
        // 定义: 对于 s1[0..i-1] 和 s2[0..j-1], 它们的 lcs 长度是 dp[i][j]
        // base case: dp[0][..] = dp[..][0] = 0 已初始化
        int [][] dp = new int[m + 1][n + 1];

        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                // 状态转移逻辑
                if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
                }
            }
        }
        return dp[m][n];
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记录Android Studio连接华为(nova)手机鸿蒙系统踩过的坑

目录 安装Android studio 安装Google USE Driver 查看华为手机的安卓版本 设置开发者模式 安装华为手机助手 重启Android studio 总结 安装Android studio 我主要参考的是这篇文章&#xff1a;Android基础&#xff08;android studio最详细基础使用功略&#xff09;_手下…

14考虑电动汽车可调度潜力的充电站两阶段市场投标策略

参考文献 考虑电动汽车可调度潜力的充电站两阶段市场投标策略——詹祥澎&#xff08;电力系统自动化,2021&#xff09; 主要内容 在电力市场环境下,充电站优化投标策略能降低电力成本&#xff0c;甚至通过售电获取收益。本程序考虑了电动汽车成为柔性储荷资源的潜力&#xf…

【目标检测】只需一张图~YOLOv5原理懂了~

目录 一、简介 二、模型结构 1.整体结构图 2.Backbone&#xff08;CSPDarknet&#xff09; 3.SPPF&#xff08;Spatial Pyramid Pooling - Fast&#xff09; 4.Neck&#xff08;FPNPAN&#xff09; 5.Head 三、anchor编解码 1.anchor编码 2.anchor解码 四、损失函数 …

一文读懂Go函数调用

导读&#xff5c;Go的函数调用时参数是通过栈传递还是寄存器传递&#xff1f;使用哪个版本的Go语言能让程序运行性能提升5%&#xff1f;腾讯后台开发工程师涂明光将带你由浅入深了解函数调用&#xff0c;并结合不同版本Go进行实操解答。函数调用基本概念1&#xff09;调用者cal…

【服务器数据恢复】Linux服务器重装系统后出现空白超级块的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌X系列服务器&#xff1b; linux操作系统&#xff1b; 4块SAS接口硬盘组建raid5磁盘阵列。 服务器故障&检测&#xff1a; 服务器运行过程中由于未知原因突然瘫痪&#xff0c;用户为故障服务器重新安装操作系统&#xff0c;安装完成后发…

【车载开发系列】UDS诊断---基于事件响应($0x86)

【车载开发系列】UDS诊断—基于事件响应&#xff08;$0x86&#xff09; 诊断---基于事件响应&#xff08;$0x86&#xff09;【车载开发系列】UDS诊断---基于事件响应&#xff08;$0x86&#xff09;一.概念定义二.注意事项三.报文格式1&#xff09;请求报文2&#xff09;肯定响应…

Java+MySQL基于ssm家教服务平台

随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用SSM框架建设家教服务平台。 本毕业设计主…

11个案例讲透 Python 函数参数

今天给大家分享一下自己整理的一篇 Python 参数的内容&#xff0c;内容非常的干&#xff0c;全文通过案例的形式来理解知识点&#xff0c;自认为比网上 80% 的文章讲的都要明白&#xff0c;如果你是入门不久的 python 新手&#xff0c;相信本篇文章应该对你会有不小的帮助。 接…

第5章 高级SQL

第5章 高级SQL 考试范围&#xff1a; 5.2 -5.3 考试题型&#xff1a; 计算题 考试内容&#xff1a; 函数、过程和触发器的概念 会定义和调用函数、过程 会定义触发器 函数、过程和触发器的概念 函数&&过程 存储过程和函数是一组为了完成特定功能的SQL语句集&…

如何用pgloader将Zabbix的MySQL数据库迁移到PostgreSQL数据库?

感谢本文作者 董玉凡 &#xff0c;Zabbix工程师 摘 要 ►今天我们使用一款工具pgloader来进行从Zabbix的MySQL数据库将数据迁移到PostgreSQL数据库。 ►pgloader是一款开源软件项目&#xff0c;可以将各种来源的数据加载到PostgreSQL当中&#xff0c;可以支持动态读取的数据…

计算机毕设Python+Vue寻迹边境丹东旅游网站(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

2022中国产业数字化发展成熟度行业指数分析—— 重视差异,结合自身要素禀赋,推进产业精细化治理

易观分析&#xff1a;随着新一轮数字技术加速渗透到各行各业&#xff0c;发展壮大战略性新兴产业成为了现代化产业体系的新动力引擎。战略性新兴产业代表了新一轮科技革命和产业变革的方向&#xff0c;既是推进新型工业化的主要抓手&#xff0c;也是中国式现代化建设必不可少的…

【UE4 第一人称射击游戏】03-再生护甲和伤害功能

效果&#xff1a; 步骤&#xff1a; 1.打开“ThirdPersonCharacter”&#xff0c;添加如下节点&#xff1a; 如果护甲量<100%&#xff0c;就每秒1% 2.新建一个函数&#xff0c;命名为“TakeDamage5%” 每次执行该函数就减少5%的护甲量&#xff0c;如果护甲量<0&#…

NeurIPS'22 | GBA:面向搜推广模型的同步和异步自由切换的训练范式

丨目录&#xff1a; 搜推广增量迭代挑战 GBA的诞生 GBA的收敛性分析 GBA工程实现 GBA实验效果 未来展望近日&#xff0c;阿里巴巴在国际顶级机器学习会议NeurIPS 2022上发表了新的自研训练模式Gloabl Batch gradients Aggregation GBA&#xff08;论文链接&#xff1a;https://…

Maven导入sqlserver驱动jar包依赖包到本地仓库并引用

一、配置maven环境变量 (1)、找到此电脑右键---->点击属性---->选择高级系统设置---->点击环境变量---->新建系统变量 (2)、新建系统变量&#xff1a;MAVEN_HOME&#xff0c;变量值填你maven解压的路径&#xff0c;然后点击确定。 (3)、在已有的path系统变量里&…

Codeforces Round #703 (Div. 2) C2. Guessing the Greatest (hard version)

翻译&#xff1a; 简单版本和困难版本之间的唯一区别是查询数量的限制。 这是一个互动的问题。 有一个包含&#x1d45b;不同数字的数组&#x1d44e;。在一个查询中&#xff0c;您可以询问子段&#x1d44e;[&#x1d459;..&#x1d45f;]中第二个最大元素的位置。在不超过…

CUDA独立上下文模块加载

CUDA独立上下文模块加载 大多数 CUDA 开发人员都熟悉 cuModuleLoad API 及其对应项&#xff0c;用于将包含设备代码的模块加载到 CUDA 上下文中。 在大多数情况下&#xff0c;您希望在所有设备上加载相同的设备代码。 这需要将设备代码显式加载到每个 CUDA 上下文中。 此外&…

408总结-冲冲冲

数据结构 m阶B树除根节点外所有节点关键字范围⌈m/2⌉−1至m−1\lceil m/2\rceil-1至m-1⌈m/2⌉−1至m−1。所有叶节点都在同一层&#xff0c;且不带信息&#xff0c;代表查找失败的位置。是所有节点平衡因子都为0的多路平衡查找树完全二叉树的叶子结点只可能出现在最下面两层…

AndroidStudio使用maven-publish发布aar至mavencentral中央仓库

目录AndroidStudio使用maven-publish发布aar至mavencentral中央仓库1、注册[【sonatype】](https://issues.sonatype.org/secure/Signup!default.jspa)2、创建Group ID3、下载安装[gnupg](https://www.gnupg.org/download/index.html)4、创建生成密钥5. 配置maven-publish打包推…

设计模式之访问者模式

Visitor design pattern 访问者模式的概念、访问者模式的结构、访问者模式的优缺点、访问者模式的使用场景、访问者模式实现示例、访问者模式的源码分析、双分派 1、访问者模式的概念 访问者模式&#xff0c;即在不改变聚合对象内元素的前提下&#xff0c;为聚合对象内每个元素…