Leetcode百题斩-DP

又到了最好玩的dp了,各种玄学转移也算是其乐无穷。前段时间刚做的LCA正是这种题的小试牛刀,如果当时就把这个专题刷完了,或许我现在已经从西溪园区跑到云谷园区了。

不过,恐怖如斯的dp专题居然只给了一道hard,基本也没啥难度可言了。看部分题目之前也刷过,但也没怎么记录在博客里,这次统一再刷一遍,快速过掉。部分题深挖一下倒也可以温习一些旁路的知识点

二维

先看二维,理论上二维要比一维要好想一点

5. Longest Palindromic Substring[Medium]

思路:这题就是之前通义实验室出的面试题,虽然有dp做法,但中心扩散法和终极Manachar算法还是挺有趣的。由于是几个月前刚做的,这里就不赘述了,感兴趣可以往前翻

多学一点:马拉车算法

最长回文子序列-CSDN博客

64. Minimum Path Sum[Medium]

思路:求矩阵左上到右下的最小路径和,这种矩阵的求和是最经典的dp了,直接左上两格转移即可

/*
Author Owen_Q
*/
public class MinimumPathSum {public static int minPathSum(int[][] grid) {int m = grid.length;int n = grid[0].length;int[][] dp = new int[m][n];for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (i == 0 && j == 0) {dp[i][j] = grid[i][j];} else if (i == 0) {dp[i][j] = dp[i][j - 1] + grid[i][j];} else if (j == 0) {dp[i][j] = dp[i - 1][j] + grid[i][j];} else {dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];}}}return dp[m - 1][n - 1];}
}

72. Edit Distance[Medium]

思路:单词变更和矩阵题类似,也十分容易出dp类型的题,以新旧两个单词的长度作为dp维度,每次变更一位进行转移,那么增,删,改分别刚好对应了左,上和左上三个转移区域。针对改特判一下若尾部相同则可以不进行修改即可。

/*
Author Owen_Q
*/
public class WordsDistance {public static int minDistance(String word1, String word2) {int m = word1.length();int n = word2.length();int[][] dp = new int[m + 1][n + 1];for (int i = 0; i <= m; i++) {for (int j = 0; j <= n; j++) {if (i == 0) {dp[i][j] = j;} else if (j == 0) {dp[i][j] = i;} else {dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1]);if (word1.charAt(i - 1) == word2.charAt(j - 1)) {dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i][j]);} else {dp[i][j] = Math.min(dp[i - 1][j - 1] + 1, dp[i][j]);}}}}return dp[m][n];}
}

1143. Longest Common Subsequence[Medium]

思路:经典二维dp问题,LCS,话不多说直接上代码

/*
Author Owen_Q
*/
public class LongestCommonSequence {public static int longestCommonSubsequence(String text1, String text2) {int n = text1.length();int m = text2.length();int[][] dp = new int[n + 1][m + 1];for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; 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 - 1][j], dp[i][j - 1]);}}}return dp[n][m];}
}

 118. Pascal's Triangle[Easy]

思路:杨辉三角来咯

/*
Author Owen_Q
*/
public class PascalTriangle {public static List<List<Integer>> generate(int numRows) {List<List<Integer>> result = new ArrayList<>();int[][] dp = new int[numRows][numRows];for (int i = 0; i < numRows; i++) {List<Integer> rowResult = new ArrayList<>();for (int j = 0; j <= i; j++) {if (j == 0 || j == i) {dp[i][j] = 1;} else {dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];}rowResult.add(dp[i][j]);}result.add(rowResult);}return result;}
}

多学一点:组合数性质

比较有意思的就是,杨辉三角的值刚好对应了组合数的值,即杨辉三角的第n行第m列刚好是组合数的 c_{n}^{m}=\frac{n!}{m!\times (n-m)!}。这刚好对应了组合数的性质,即 c_{n}^{m} = c_{n-1}^{m} +c_{n-1}^{m-1}。此外,杨辉三角的每一行也刚好就是 (a+b)^{n} 二项展开式中的系数

62. Unique Paths[Medium]

思路:求矩阵左上到右下的路径数量,和上述编号64题极其类似,上面是求最小最小值,这里是求和,换汤不换药

/*
Author Owen_Q
*/
public class UniquePaths {public static int uniquePaths(int m, int n) {int[][] dp = new int[m][n];for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (i == 0 && j == 0) {dp[i][j] = 1;} else if (i == 0) {dp[i][j] = dp[i][j - 1];} else if (j == 0) {dp[i][j] = dp[i - 1][j];} else {dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}}return dp[m - 1][n - 1];}
}

一维 

接下来看看一维,其实一维也很简单,leetcode真的很良心了,基本毫无难度

152. Maximum Product Subarray[Medium]

思路:求数串的最大子串乘积,其实可以不用dp,在不考虑符号的情况下,乘积肯定是越乘越大,考虑符号,那么记录一下当前最大乘积和最小乘积,每次遇到零则清空一下即可。最后注意一下单个数字的场景,这种情况下该数字即为最大乘积,而非初始化的0,特判一下即可;

/*
Author Owen_Q
*/
public class MaximumProductSubarray {public static void main(String[] args) {System.out.println(maxProduct(new int[] {2, 3, -2, 4}));System.out.println(maxProduct(new int[] {-2, 0, -1}));System.out.println(maxProduct(new int[] {-2}));System.out.println(maxProduct(new int[] {-4, -3, -2}));}public static int maxProduct(int[] nums) {if (nums.length == 1) {return nums[0];}int result = nums[0];int curMaxProduct = 0;int curMinProduct = 0;for (int num : nums) {if (num == 0) {curMaxProduct = 0;curMinProduct = 0;} else if (num > 0) {curMaxProduct = Math.max(curMaxProduct * num, num);curMinProduct = Math.min(curMinProduct * num, num);} else {int preMaxProduct = curMaxProduct;curMaxProduct = Math.max(curMinProduct * num, num);curMinProduct = Math.min(preMaxProduct * num, num);}//System.out.println(num + "*" + curMaxProduct + "*" + curMinProduct);result = Math.max(result, curMaxProduct);}return result;}
}

279. Perfect Squares[Medium]

思路:给定某个数,求当前数最少可以由多少个完全平方数求和而来。那么这个dp思路也很好想,每个数由其减去一个完全平方数转移而来,即 dp[i] = min(dp[i-k^{2}]+1), k^{2} <= i

/*
Author Owen_Q
*/
public class PerfectSquares {public static int numSquares(int n) {int[] dp = new int[n + 1];for (int i = 0; i <= n; i++) {dp[i] = i;for (int j = 1; j * j <= i; j++) {dp[i] = Math.min(dp[i], dp[i - j * j] + 1);}}return dp[n];}
}

多学一点:四平方和定理

上述递推的时间复杂度为O(n\sqrt{n}),对于大数会有很大的消耗。因此如果有数学方法进行优化,那将大大降低时间复杂度。这里我们引入拉格朗日的四平方数定理的,即:任何一个正整数都可以表示为至多四个正整数的平方和。这个定理一下就把这题的值域缩小到了 [1,4],这四个整数内。进一步了解,在四平方和定理的基础上,还有一个更严格的定理,就是勒让德的三平方和定理,即:当且仅当 n= 4^{k}\times (8m+7) 时,n可以被表示为四个正整数的平方。那么,当 n\neq 4^{k}\times (8m+7) 时,答案的数量又被缩小到 [1,3]。于是直接特判即可。针对答案为1的场景,n为完全平方式。针对答案为2的场景,n=a^{2}+b^{2},那么枚举a,如果 b=n-a^{2} 为完全平方数,则成立。最后,若1和2均不满足,则答案为3。于是,利用平方定理,最大的时间耗时就是在判断答案是否为2这条分支上,于是整体的时间复杂度就被降到了O(\sqrt{n})

/*
Author Owen_Q
*/
public class PerfectSquares {public static int numSquaresWithMaths(int n) {if (foutSquares(n)) {return 4;}if (perfectSquares(n)) {return 1;}if (twoSquares(n)) {return 2;}return 3;}private static boolean foutSquares(int n) {while (n % 4 == 0) {n /= 4;}return n % 8 == 7;}private static boolean perfectSquares(int n) {int sqrtn = (int)Math.sqrt(n);return sqrtn * sqrtn == n;}private static boolean twoSquares(int n) {for (int i = 1; i * i < n; i++) {if (perfectSquares(n - i * i)) {return true;}}return false;}
}

直接登顶

70. Climbing Stairs[Easy]

思路:不愧是easy题,斐波那契数组和杨辉三角堪称dp届的始祖。这题就是斐波那契数组,直接求

/*
Author Owen_Q
*/
public class ClimbingStairs {public static int climbStairs(int n) {int[] dp = new int[n + 1];dp[0] = 1;dp[1] = 1;for (int i = 2; i <= n; i++) {dp[i] = dp[i - 1] + dp[i - 2];}return dp[n];}
}

多学一点:矩阵快速幂

一提到斐波那契,怎么能没有矩阵快速幂。

基础递推01-CSDN博客

首先,观察通项公式

dp[n] = dp[n-1]+dp[n-2]

将通项公式转化到矩阵中,可以得到矩阵的递推关系

\begin{bmatrix} dp[n]\\ dp[n-1] \end{bmatrix}=\begin{bmatrix} dp[n-1]+dp[n-2]\\ dp[n-1] \end{bmatrix}=\begin{bmatrix} 1\times dp[n-1]+1\times dp[n-2]\\ 1\times dp[n-1] + 0\times dp[n-2] \end{bmatrix}=\begin{bmatrix} 1& 1\\ 1 & 0 \end{bmatrix}\begin{bmatrix} dp[n-1]\\ dp[n-2] \end{bmatrix}=\begin{bmatrix} 1& 1\\ 1 & 0 \end{bmatrix}^{k}\begin{bmatrix} dp[n-k]\\ dp[n-k-1] \end{bmatrix} =\begin{bmatrix} 1& 1\\ 1 & 0 \end{bmatrix}^{n-1}\begin{bmatrix} dp[1]\\ dp[0] \end{bmatrix}

于是,O(n) 的递推线性复杂度就被降为了 O(logn) 的求矩阵幂的复杂度

/*
Author Owen_Q
*/
public class ClimbingStairs {public static int climbStairsWithBinaryExponentiation(int n) {int[][] a = {{1, 1}, {1, 0}};return power(a, n)[0][0];}private static int[][] power(int[][] a, int n) {if (a == null) {return null;}int len = a.length;int size = a[0].length;if (len != size) {return null;}int[][] result = {{1, 0}, {0, 1}};while (n > 0) {if ((n & 1) == 1) {result = multiple(result, a);}a = multiple(a, a);n >>= 1;}return result;}private static int[][] multiple(int[][] a, int[][] b) {int alen = a.length;int blen = b.length;int asize = a[0].length;int bsize = b[0].length;if (asize != blen) {return null;}int c[][] = new int[alen][bsize];for (int i = 0; i < alen; i++) {for (int j = 0; j < bsize; j++) {c[i][j] = 0;for (int k = 0; k < asize; k++) {c[i][j] += a[i][k] * b[k][j];}}}return c;}
}

再衍生一步,其实任何线性其次递推公式都可以用矩阵快速幂来优化

针对m项递推 f(n)=\sum_{i=1}^{m}a_{i}\times f(n-i) ,都可以构造m \times m的矩阵\begin{bmatrix} a_{1}& a_{2}& a_{3}& ...& a_{m-1}& a_{m}\\ 1& 0 & 0 & ... & 0 & 0\\ 0& 1& 0 &... &0 &0 \\ 0& 0 & 1 & ... & 0 & 0\\ ...& ... & ... & ... & ... & ...\\ 0& 0 &0 &... & 1 & 0 \end{bmatrix}

然后即可基于矩阵快速幂进行计算,而对应的单位矩阵即为

\begin{bmatrix} 1& 0 & 0 & ... & 0\\ 0& 1& 0 &... &0 \\ 0& 0 & 1 & ... & 0\\ ...& ... & ... & ... & ...\\ 0& 0 &0 &... & 1 \end{bmatrix}

198. House Robber[Medium]

思路:选物品,每个物品有一定价值,不占容量,但不可连续选择,求最大物品数。这像是个低配版背包,直接相邻转移即可

/*
Author Owen_Q
*/
public class HorseRobber {public static int rob(int[] nums) {int n = nums.length;int[] dp = new int[n + 1];dp[0] = 0;dp[1] = nums[0];for (int i = 2; i <= n; i++) {dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i - 1]);}return dp[n];}
}

300. Longest Increasing Subsequence[Medium]

思路:经典LIS问题,最长单增子序列,不多说直接求

/*
Author Owen_Q
*/
public class LongestIncreasingSubsequence {public static int lengthOfLIS(int[] nums) {int n = nums.length;int[] dp = new int[n];dp[0] = 1;int re = 1;for (int i = 1; i < n; i++) {dp[i] = 1;for (int j = 0; j < i; j++) {if (nums[j] < nums[i]) {dp[i] = Math.max(dp[i], dp[j] + 1);}}re = Math.max(dp[i], re);}return re;}
}

多学一点:贪心 

这么经典的问题,当然不能用DP,这平方级别的复杂度,当然要想着优化一下。

这里用到一个神奇的思路,就是转换状态和状态值

原先 dp[i] 表示结尾为 num[i] 的最长单增子序列的长度

那么这次引入新的数组 g[i] 表示长度为 i 的最长单增子序列的最小结尾值。

不难发现,g[i] 一定是单增的。比如,某长度为i的最长公共子序列,最后一位为 g[i] 删去最后一位后,倒数第二位一定大于等于 g[i-1],因为若倒数第二位小于 g[i-1],那么这个数自身就可以更新 g[i-1] 使得值更小。于是这题就变成了贪心求 g[i]

具体贪心的过程即是,遍历数组,针对每个新的数,找到g数组中大于当前数的首个位置,若没有找到,则将当前数塞到g数组末尾。否则,更新找到的位置为当前数。至于找到首个大于当前数的位置,可以直接用二分来实现,最终能将时间内复杂度降到 O(nlogn)

下面来说一下二分搜索。java中有现成的函数 java.util.Collections#binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T),要求传入的数组一定为有序的。返回值分为两种,若为正数,则说明当前值已找到,返回的结果即为当前值在数组中的位置。若返回值为负数,则表示当前值未找到,返回的结果为当前值可插入的位置-1

/*
Author Owen_Q
*/
public class LongestIncreasingSubsequence {public static int lengthOfLISGreedy(int[] nums) {List<Integer> g = new ArrayList<>();for (int num : nums) {int searchResult = Collections.binarySearch(g, num);if (searchResult < 0) {searchResult = searchResult * -1 - 1;if (searchResult == g.size()) {g.add(num);} else {g.set(searchResult, num);}}}return g.size();}
}

效果拔群 

322. Coin Change[Medium]

思路:提到DP,怎么能没有背包呢!典型的背包问题,由于硬币的数量无限,那么这就是个完全背包问题,转移时从小向大遍历。如果这题每种硬币只能取一个,那就变成了最基础的01背包问题,从大向小遍历即可。背包做完舒服了

/*
Author Owen_Q
*/
public class CoinChange {public static int coinChange(int[] coins, int amount) {int[] dp = new int[amount + 1];Arrays.fill(dp, -1);dp[0] = 0;for (int coin : coins) {for (int i = 1; i <= amount; i++) {if (i >= coin && dp[i - coin] >= 0) {if (dp[i] == -1) {dp[i] = dp[i - coin] + 1;} else {dp[i] = Math.min(dp[i], dp[i - coin] + 1);}}}}return dp[amount];}
}

416. Partition Equal Subset Sum[Medium]

思路:给定一个数组,求能否将数组中的数均匀分成两块。由于数组中的数字不可分,那么又可以转换为背包问题。每个数均只有一个,可以用01背包。这题由于只需要求可行性,因此,直接将初始dp默认为1,别的均初始化为0,然后设置背包容量为数组和的一半,通过最大值进行转移看最终能否将1转移到半背包容量的位置处

/*
Author Owen_Q
*/
public class PartitionEqualSubsetSum {public static boolean canPartition(int[] nums) {int sum = 0;for (int num : nums) {sum += num;}if (sum % 2 == 1) {return false;}sum >>= 1;int[] dp = new int[sum + 1];dp[0] = 1;for (int num : nums) {for (int i = sum; i >= num; i--) {dp[i] = Math.max(dp[i], dp[i - num]);}}return dp[sum] == 1;}
}

139. Word Break[Medium]

思路:判断某个字符串是否可以被分割为多个特定字典中的单词。当然想到dp,表示当前位置为止的前缀是否满足要求。转移方程就是往前遍历,找到前面满足的位置,再判断从找到的位置到当前位置中的字符串是否能在字典中寻找到,即 dp[i]=dp[j]\wedge word[j,i)

/*
Author Owen_Q
*/
public class WordBreak {public static boolean wordBreak(String s, List<String> wordDict) {int len = s.length();boolean[] dp = new boolean[len + 1];dp[0] = true;for (int i = 1; i <= len; i++) {for (int j = 0; j < i; j++) {if (wordDict.contains(s.substring(j, i)) && dp[j]) {dp[i] = true;break;}}}return dp[len];}
}

多学一点:字典树(Trie)

不难发现dp转移过程中,有很多无用的转移,比如当当前字典中没有以当前字母为开头的字段时,就可以停止这轮转移。甚至更进一步,当当前字典中没有以当前搜索的区域为前缀的字段时,就可以停止继续搜索了。

还记得之前特地有个专题说到了前缀问题的数据结构字典树吗,这不就用上了

Leetcode百题斩-字典树_leetcode 字典树-CSDN博客

于是开始搜索,搜索时为了避免重复搜索,可以使用记忆化搜索,确保每轮只要搜索一次。

与之前动态转移从前往后判断,用 dp 来记录前缀是否满足条件不同,这次我们从后往前判断,并 dp 我们用来记录后缀是否满足条件。

搜索分三部分:特判,搜索找到后进行递归搜索以及搜索没找到时的遍历搜索

第一部分是特判。每次搜索,特判若首字母不在字典树中则直接返回失败,若整个字符串在字典树中被搜到则直接返回成功。

第二部分是递归搜索。从头开始寻找字典树中的字段位置,若搜索到,则以当前位置进行递归向后搜索。

第三部分是遍历搜索。当然若没搜索到,则将当前搜索点向后顺移一位判断被延长后的子串是否在字典树中,并继续搜索

/*
Author Owen_Q
*/
public class WordBreak {public static boolean wordBreakTrie(String s, List<String> wordDict) {int len = s.length();int[] dp = new int[len];Trie trie = new Trie();for (String word : wordDict) {trie.insert(word);}return wordBreakTrieSearch(s, trie, 0, dp);}private static boolean wordBreakTrieSearch(String s, Trie trie, int pos, int[] dp) {int len = s.length();if (dp[pos] != 0) {return dp[pos] == 1;}if (!trie.startsWith(String.valueOf(s.charAt(pos)))) {dp[pos] = -1;return false;}if (trie.search(s.substring(pos))) {dp[pos] = 1;return true;}for (int i = pos + 1; i < len; i++) {if (trie.search(s.substring(pos, i)) && wordBreakTrieSearch(s, trie, i, dp)) {dp[pos] = 1;return true;}if (!trie.startsWith(s.substring(pos, i + 1))) {dp[pos] = -1;return false;}}dp[pos] = -1;return false;}
}

效果还是挺明显的

32. Longest Valid Parentheses[Hard]

思路:作为dp专题唯一的hard,倒是要好好来看一下。

括号匹配,求最长合法括号串。

由于合法括号串一定是以 ) 结尾,因此所有 ( 处的值一定为0。

接下来开始考虑转移。

一共有两种转移方案,刚好对应了括号串的两种合法状态

一是...()

若当前位的前一位为 (,则可以直接形成匹配,长度无脑加2

二是...((...))

若当前位的前一位为 ),则需要判断前一位是否形成合法串了。如果形成了合法串,则需要再向前找到前一位合法串前的位是否为 (,即是否可以再前一个合法串外围再包一个匹配。

此外还需要再注意的一点就是,如果外围匹配成功,则需要再向前往一位,再加一个前位的合法串长度。因为你多一个匹配很有可能将两个合法串连接到了一起

/*
Author Owen_Q
*/
public class LongestValidParentheses {public static int longestValidParentheses(String s) {int len = s.length();int[] dp = new int[len + 1];int maxLen = 0;for (int i = 0; i < len; i++) {if (s.charAt(i) == '(') {continue;}if (i > 0 && s.charAt(i - 1) == '(') {dp[i + 1] = dp[i - 1] + 2;maxLen = Math.max(maxLen, dp[i + 1]);} else if (i - dp[i] > 0 && s.charAt(i - dp[i] - 1) == '(') {dp[i + 1] = dp[i] + 2;if (i - dp[i] - 1 > 0) {dp[i + 1] += dp[i - dp[i] - 1];}maxLen = Math.max(maxLen, dp[i + 1]);}}return maxLen;}}

多学一点:贪心

回归传统思维,直接贪心模拟。实时记录当前左右括号的数量,当右括号数量多于左括号时,那么前面的一定无法组成合法场景,直接从头开始计算。当左右括号数量相等时,统计此时的模拟长度。但这种场景其实针对最终左括号多于右括号的场景无法得出,因为不知道最右边的右括号匹配到了哪个左括号,即有效的长度究竟是多少。那么最简单的方式就是反过来再求一次就好了

/*
Author Owen_Q
*/
public class LongestValidParentheses {public static int longestValidParenthesesGreedy(String s) {int sLen = s.length();int left = 0;int right = 0;int len = 0;int maxLen = 0;for (int i = 0; i < sLen; i++) {len++;if (s.charAt(i) == '(') {left++;} else {right++;}if (right > left) {left = 0;right = 0;len = 0;}if (left == right) {maxLen = Math.max(maxLen, len);}}left = 0;right = 0;len = 0;for (int i = sLen - 1; i >= 0; i--) {len++;if (s.charAt(i) == '(') {left++;} else {right++;}if (right < left) {left = 0;right = 0;len = 0;}if (left == right) {maxLen = Math.max(maxLen, len);}}return maxLen;}}

多学一点 :栈

其实针对左括号比右括号多无法定位到具体位置的问题,用栈就可以很好的解决。栈可以实时获取到当前合法串的长度。我们只要把栈底元素始终放置此轮合法的起点,即左括号不比右括号少的首个位置。然后每次左括号位置进栈,右括号位置出栈。那么此轮出栈的元素一定都是合法串的一部分,于是我们只需要在每次出栈的时候,比较当前位置与栈顶位置的差值,即从栈顶到当前一共有多少个元素在栈外,即可获取到当前串的长度。最后,针对左括号少于右括号的场景,把栈底元素出栈后,再将当前元素入栈,即可确保起点也被成功更新,开启新的一轮

/*
Author Owen_Q
*/
public class LongestValidParentheses {public static int longestValidParenthesesStack(String s) {Stack<Integer> stack = new Stack<>();stack.push(-1);int len = s.length();int maxLen = 0;for (int i = 0; i < len; i++) {if (s.charAt(i) == '(') {stack.push(i);} else {stack.pop();if (stack.isEmpty()) {stack.push(i);} else {int top = stack.peek();maxLen = Math.max(maxLen, i - top);}}}return maxLen;}}

完结撒花

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

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

相关文章

策略模式与工厂模式的黄金组合:从设计到实战

策略模式和工厂模式是软件开发中最常用的两种设计模式&#xff0c;当它们结合使用时&#xff0c;能产生11>2的效果。本文将通过实际案例&#xff0c;阐述这两种模式的协同应用&#xff0c;让代码架构更优雅、可维护性更强。 一、为什么需要组合使用&#xff1f; 单独使用的…

SAP PP模块与MM模块作用详解

SAP PP模块与MM模块作用详解 一、PP模块&#xff08;Production Planning&#xff09;—— 生产计划与执行中枢 核心作用&#xff1a;将销售需求转化为可执行的生产指令&#xff0c;管控从计划到完工的全过程。 关键功能 功能说明业务价值主数据管理维护BOM&#xff08;物料…

Linux tcp_info:监控TCP连接的秘密武器

深入解析 Linux tcp_info&#xff1a;TCP 状态的实时监控利器 在开发和运维网络服务时&#xff0c;我们常常遇到这些问题&#xff1a; 我的 TCP 连接为什么速度慢&#xff1f;是发生了重传&#xff0c;还是窗口太小&#xff1f;拥塞控制到底有没有生效&#xff1f; 这些问题…

CVE-2015-5531源码分析与漏洞复现(Elasticsearch目录遍历漏洞)

概述 漏洞名称&#xff1a;Elasticsearch 快照API目录遍历漏洞 CVE 编号&#xff1a;CVE-2015-5531 CVSS 评分&#xff1a;7.5 影响版本&#xff1a; Elasticsearch 1.0.0–1.6.0&#xff08;1.5.1及以前版本无需配置即可触发&#xff1b;1.5.2–1.6.0需配置path.repo&#xf…

HexHub开发运维利器Database, Docker, SSH, SFTP

支持隧道&#xff0c;SFTP&#xff0c;X11转发&#xff0c;跳板机&#xff0c;分屏广播输入&#xff0c;LRZSZ&#xff0c;TRZSZ&#xff0c;SCP 分屏广播输入 管理多台服务器&#xff0c;更快一步 支持多种文件传输协议 支持跨服务器文件传输&#xff0c;使用复制粘贴即可进…

2025年教育、心理健康与信息管理国际会议(EMHIM 2025)

2025 2nd International Conference on Education, Mental Health, and Information Management 一、大会信息 会议简称&#xff1a;EMHIM 2025 大会地点&#xff1a;中国三亚 收录检索&#xff1a;提交Ei Compendex,CPCI,CNKI,Google Scholar等 二、会议简介 第二届教…

数字孪生技术为UI前端注入新活力:实现智能化交互新体验

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩! 在数字化转型的深水区&#xff0c;数字孪生技术正以破竹之势重构 UI 前端的技术逻辑与交互范式…

组件协作模式

目录 “组件协作”模式模板方法模式动机模式定义结构要点总结 “组件协作”模式 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”。“组件协作”模式通过晚期绑定&#xff0c;实现框架与应用程序之间的松耦合&#xff0c;是二者之间协作时常用的模式。典型模式&a…

Docker 运行RAGFlow 搭建RAG知识库

借鉴视频&#xff1a;DeepSeek 10分钟完全本地部署 保姆级教程 断网运行 无惧隐私威胁 大语言模型 CPU GPU 混合推理32B轻松本地部署&#xff01;DeepSeek模拟王者&#xff01;&#xff01;_哔哩哔哩_bilibili 借鉴博客&#xff1a;RAGFlow搭建全攻略&#xff1a;从入门到精通…

python编写脚本每月1号和15号执行一次将TRX是否强更发送到钉钉

编写脚本 import requests import json import time import hmac import hashlib import base64 import urllib.parse# 1. 配置钉钉机器人 webhook "https://oapi.dingtalk.com/robot/send?access_tokenXXXXXX" secret "XXXXXXXX" # 如果没有加签验…

Linux-系统管理

[rootlocalhost ~]# lscpu //查看cpu [rootlocalhost etc]# cat /etc/redhat-release //查看当前目录的版本信息 [rootlocalhost ~]# ifconfig //查看当前激活的网卡信息 [rootlocalhost ~]# ifconfig ens33 192.168.1.10 //给网卡配置临时地址 [rootlocalhost ~]# hostnam…

【Spring】系统化的 Spring Boot 全栈学习教程,涵盖基础配置、核心功能、进阶实战及文档自动生成

这里写目录标题 &#x1f6e0;️ **一、环境搭建与项目创建**1. 开发环境准备2. 创建第一个项目&#xff08;Spring Initializr&#xff09; &#x1f680; **二、核心功能开发**1. RESTful API 开发2. 数据持久化&#xff08;Spring Data JPA&#xff09;3. 配置文件多环境切换…

Discrete Audio Tokens: More Than a Survey

文章目录 模型设计的考虑量化的方式&#xff1a;比特率&#xff1a;Fixed vs. Adaptive Bitrate码本内容设计的考虑Streamability. 模型评估Reconstruction Evaluation and Complexity Analysis.识别和生成任务&#xff08;SE, SR)Acoustic Language Modeling.Music Generation…

设计在线教育项目核心数据库表

1 在线教育项目核心数据库表设计-ER图 简介&#xff1a;设计在线教育的核心库表结构 在线教育站点速览 xdclass.net ER图知识回顾&#xff1a; 实体对象&#xff1a;矩形属性&#xff1a;椭圆关系&#xff1a;菱形 核心库表 videochapterepisodeuservideo_ordervideo_banner…

【音视频】Ubuntu下配置ffmpeg库

一、下载预编译的库 在github上可以找到编译好的ffmpeg&#xff0c;多个版本的都有&#xff0c;这里我下载ffmpeg编译好的动态库 仓库链接&#xff1a;(https://github.com/BtbN/FFmpeg-Builds/releases 下载后解压得到 二、配置环境变量 打开.bashrc配置文件&#xff0c;添…

equine在神经网络中建立量化不确定性

​一、软件介绍 文末提供程序和源码下载 众所周知&#xff0c;用于监督标记问题的深度神经网络 &#xff08;DNN&#xff09; 可以在各种学习任务中产生准确的结果。但是&#xff0c;当准确性是唯一目标时&#xff0c;DNN 经常会做出过于自信的预测&#xff0c;并且无论测试数…

C++动态链接库之非托管封装Invoke,供C#/C++ 等编程语言使用,小白教程——C++动态链接库(一)

目录&#xff1a; 一、前言及背景1.1需求描述1.2应用背景 二、编程基础知识2.1非托管方式交互逻辑2.2该方式下C 与C# 数据转换对应2.3VS工程下的注意点2.4C封装接口2.4.1 __declspec(dllexport) 方式2.4.2 .def 文件方式2.4.3结合使用&#xff08;高级&#xff09; 2.5C# 封装接…

消息队列的网络模型详解:IO多路复用、Reactor模型、零拷贝

文章目录 一、消息队列的网路模型拟解决问题单个请求性能优化1. 编解码速度2. 网络模块处理速度 并发请求性能优化1. 高效的连接管理2. 快速处理高并发请求3. 大流量场景处理 二、一些技术基础知识1. 基于多路复用技术管理 TCP 连接&#xff08;提高性能&#xff09;&#xff0…

【生成模型】【模型介绍】(一)视频生成Wan2.1速度质量简单评测

基础模型&#xff1a;FramePack https://github.com/kijai/ComfyUI-FramePackWrapper huggingface-cli download Comfy-Org/HunyuanVideo_repackaged --local-dir Comfy-Org/HunyuanVideo_repackaged --resume-download huggingface-cli download Comfy-Org/sigclip_vision_3…

微信小程序之滑块scroll-view

我们要做的东西&#xff1a; 滑块的视频 我们先做个基本的图片和文字(wxm;)&#xff1a; <scroll-view><view class"scrollItem"><image src"https://bkimg.cdn.bcebos.com/pic/fc1f4134970a304e251fd88e8191b086c9177f3ef634?x-bce-processim…