算法31:针对算法30货币问题进行拓展 + 时间复杂度 + 空间复杂度优化--------从左往右尝试模型

在算法30中,我们说过从左往右尝试模型,口诀就是针对固定集合,值不同,就是讨论要和不要的累加和

那么对于非固定集合,我们应该怎么做呢?

针对非固定集合,面值固定,张数无限。口诀就是讨论要与不要,要的话逐步讨论要几张的累加和

题目:

* arr是面值数组,其中的值都是正数且没有重复。再给定一个正数aim。

* 每个值都认为是一种面值,且认为张数是无限的。

* 返回组成aim的方法数

分析:

* 例如:arr = {1,2},aim = 4

* 方法如下:1+1+1+1、1+1+2、2+2 * 一共就3种方法,所以返回3

递归写法:

 //递归版本public static int ways(int[] arr, int aim) {if (arr == null || arr.length == 0 || aim < 0) {return 0;}return process(arr, 0, aim);}public static int process (int[] arr, int index, int aim){if (index == arr.length) { // 没钱了return aim == 0 ? 1 : 0;}//讨论不同货币组成aim的可能int ways = 0;//因为货币张数无限,所有需要讨论每一种情况。此次,就不是简单的要与不要的问题了for (int zhangshu = 0; zhangshu * arr[index] <= aim; zhangshu++) {/*** 此处,还是讨论要与不要的问题。* 0张代表不要* 要的话需要讨论要几张 :* 要1 张, 那么后面的数组需要进行递归继续讨论要还是不要,要的话要几张* 要2 张,那么后面的数组需要进行递归继续讨论要还是不要,要的话要几张*  依次类推*/ways += process(arr, index + 1, aim - zhangshu * arr[index]);}return ways;}

动态规划

1. 套路还是老样子。以数组为横坐标,以aim为纵坐标。并且行与列都新增1个。

2. 根据递归

if (index == arr.length) { // 没钱了return aim == 0 ? 1 : 0;
}

可以推导出最后一行的第一列为1,其余全部为0.

aim 0aim 1aim 2aim 3aim 4
index 0 (1)
index 1 (2)
index 210000

3. 根据递归:

int ways = 0;
//因为货币张数无限,所有需要讨论每一种情况。此次,就不是简单的要与不要的问题了
for (int zhangshu = 0; zhangshu * arr[index] <= aim; zhangshu++) {/*** 此处,还是讨论要与不要的问题。* 0张代表不要* 要的话需要讨论要几张 :* 要1 张, 那么后面的数组需要进行递归继续讨论要还是不要,要的话要几张* 要2 张,那么后面的数组需要进行递归继续讨论要还是不要,要的话要几张*  依次类推*/ways += process(arr, index + 1, aim - zhangshu * arr[index]);
}

可以得到:

1. zhangshu * arr[index] <= aim必须成立,否则不做推导;直接返回0

2. 如果zhangshu * arr[index] <= aim成立,那么当前行当前列的值  依赖于下一行的aim - zhangshu * arr[index]列。

aim= 0aim= 1aim= 2aim= 3aim= 4
index 0 (1)
index 1 (2)

aim - zhangshu * arr[index]  = 0 - 张数 *2;

讨论:

面值为2:张数为0,则 计算值为0

dp[1][0] = dp[2][0] = 1; 即只存在1种解法。

讨论:

张数为0

dp[1][1] = dp[2][1] = 0

 

张数为1

可得 1 - 2 < 0;取值0

0+0=0,最终取值0
 

讨论

张数0

dp[1][2] = dp[2][2] = 0;

张数为1,可得 2 - 2 =0;

可得dp[1][2] = dp[2][0] = 1;

张数为2,可得 2 - 2*2 <0;直接取0;

即1种解法,即0+1+0=1

讨论1:

张数为0

dp[1][3] ]= dp[2][3] = 0;

张数为1,可得 3 - 2 =1;

可得:

dp[1][3] = dp[2][1] = 0;

张数为2。

可得3 - 2*2 < 0取值0;

张数为3. 即3-3*2<0,直接取0

0+0+0+0=0,最终取值0

张数为0

dp[1][4] = dp[2][4] = 0;

张数为1,可得 4 - 2 =2;

dp[1][4] = dp[2][2] = 0;

张数为2.

可得4 - 2*2 = 0.

dp[1][4] = dp[2][0] = 1;

张数为3:

4-3*2 < 0;直接取0

张数为4,4-4*2 < 0;直接取0

0+0+1+0+0=1

最终可得1种解法。

index 210000

    接着,我们推导出第一行的数据:

aim= 0aim= 1aim= 2aim= 3aim= 4
index 0 (1)

 面值为1
张数为0,dp[0][0] = dp[1][0] = 1;

  面值为1
张数为0,dp[0][1] = dp[1][1] = 0;

张数为1:

dp[0][1]=dp[1][0] = 1;

累计1种

 张数为0:

dp[0][2] = dp[1][2] = 1;

张数为1:

dp[0][2] = dp[1][1] = 0;

累计1种

张数为0:

dp[0][3] = dp[1][3] = 0;

张数为1:

dp[0][3] = dp[1][2] = 1;

张数为2:

dp[0][3] = dp[1][1] = 0;

累计1种

张数为0;

dp[0][4]=[1][4-0] = dp[1][4] = 1

张数为1:

dp[0][4] = dp[1][4-1*1] = dp[1][3] = 0;

张数为2:

dp[0][4] = dp[1][4-2*1] = dp[1][2] = 1;

张数为3:

dp[0][4] = dp[1][4-3*1] = dp[1][1] = 0;

张数为4:

dp[0][4] = dp[1][4-4*1] = dp[1][0] = 1;

累计1+1+1=3;

index 1 (2)

aim - zhangshu * arr[index]  = 0 - 张数 *2;

讨论:

面值为2:张数为0,则 计算值为0

dp[1][0] = dp[2][0] = 1; 即只存在1种解法。

讨论:

张数为0

dp[1][1] = dp[2][1] = 0

 

张数为1

可得 1 - 2 < 0;取值0

0+0=0,最终取值0
 

讨论

张数0

dp[1][2] = dp[2][2] = 0;

张数为1,可得 2 - 2 =0;

可得dp[1][2] = dp[2][0] = 1;

张数为2,可得 2 - 2*2 <0;直接取0;

即1种解法,即0+1+0=1

讨论1:

张数为0

dp[1][3] ]= dp[2][3] = 0;

张数为1,可得 3 - 2 =1;

可得:

dp[1][3] = dp[2][1] = 0;

张数为2。

可得3 - 2*2 < 0取值0;

张数为3. 即3-3*2<0,直接取0

0+0+0+0=0,最终取值0

 

张数为0,

dp[1][4] = dp[2][4] = 0;

张数为1,可得 4 - 2 =2;

dp[1][4] = dp[2][2] = 0;

张数为2.

可得4 - 2*2 = 0.

dp[1][4] = dp[2][0] = 1;

张数为3:

4-3*2 < 0;直接取0

张数为4,4-4*2 < 0;直接取0

0+0+1+0+0=1

最终可得1种解法。

index 210000

最终需要的是第一行最后一列数据:

1. aim为4,面值为1的一张都没有。可得dp[0][4]=[1][4-0] = dp[1][4] = 1

2. aim 为4, 面值为1的只有一张。可得 dp[0][4] = dp[1][4-1*1] = dp[1][3] = 0;

3. aim 为4, 面值为1的只有两张。可得 dp[0][4] = dp[1][4-2*1] = dp[1][2] = 1;

4. aim 为4, 面值为1的只有三张。可得 dp[0][4] = dp[1][4-3*1] = dp[1][1] = 0;

5. aim 为4, 面值为1的只有四张。可得 dp[0][4] = dp[1][4-4*1] = dp[1][0] = 1;

累计可得1+1+1 = 3, 即3种方法。

  //动态规划public static int ways2(int[] arr, int aim) {if (arr == null || arr.length == 0 || aim < 0) {return 0;}//老样子int N = arr.length;int[][] dp = new int[N + 1][aim + 1];//最后一行的第一列为1,其余都为0。 根据递归 return aim == 0 ? 1 : 0;得到dp[N][0] = 1;//双层for循环,动态规划的老套路。一维数组arr作为横坐标,aim作为纵坐标for (int row = N -1 ; row >= 0; row--) {     //row代表递归中的 indexfor (int col = 0; col <= aim; col++) {   //col代表递归中的 aim//此处是比较复杂的,完全套用递归内部的代码。这一层的for循环就是对//要的张数进行讨论。int ways = 0;//此处zhangshu * arr[row] <= col是唯一变化。重点理解for (int zhangshu = 0; zhangshu * arr[row] <= col; zhangshu++) {/*** 此处,还是讨论要与不要的问题。* 0张代表不要* 要的话需要讨论要几张 :* 要1 张, 那么后面的数组需要进行递归继续讨论要还是不要,要的话要几张* 要2 张,那么后面的数组需要进行递归继续讨论要还是不要,要的话要几张*  依次类推*///根据ways += process(arr, row + 1, aim - zhangshu * arr[row]);推导//此处的aim - zhangshu * arr[index] 需要变成 col - zhangshu * arr[index]ways += dp[row + 1][col - (zhangshu * arr[row])];}dp[row][col] = ways;}}return dp[0][aim];}

那么如何进行时间复杂度优化呢?继续观察二维数组:

aim= 0aim= 1aim= 2aim= 3aim= 4
index 0 (1)

 面值为1
张数为0,dp[0][0] = dp[1][0] = 1;

  面值为1
张数为0,dp[0][1] = dp[1][1] = 0;

张数为1:

dp[0][1]=dp[1][0] = 1;

累计1种

 张数为0:

dp[0][2] = dp[1][2] = 1;

张数为1:

dp[0][2] = dp[1][1] = 0;

累计1种

张数为0:

dp[0][3] = dp[1][3] = 0;

张数为1:

dp[0][3] = dp[1][2] = 1;

张数为2:

dp[0][3] = dp[1][1] = 0;

累计1种

张数为0;

dp[0][4]=[1][4-0] = dp[1][4] = 1

张数为1:

dp[0][4] = dp[1][4-1*1] = dp[1][3] = 0;

张数为2:

dp[0][4] = dp[1][4-2*1] = dp[1][2] = 1;

张数为3:

dp[0][4] = dp[1][4-3*1] = dp[1][1] = 0;

张数为4:

dp[0][4] = dp[1][4-4*1] = dp[1][0] = 1;

累计1+1+1=3;

index 1 (2)

aim - zhangshu * arr[index]  = 0 - 张数 *2;

讨论:

面值为2:张数为0,则 计算值为0

dp[1][0] = dp[2][0] = 1; 即只存在1种解法。

讨论:

张数为0

dp[1][1] = dp[2][1] = 0

 

张数为1

可得 1 - 2 < 0;取值0

0+0=0,最终取值0
 

讨论

张数0

dp[1][2] = dp[2][2] = 0;

张数为1,可得 2 - 2 =0;

可得dp[1][2] = dp[2][0] = 1;

张数为2,可得 2 - 2*2 <0;直接取0;

即1种解法,即0+1+0=1

讨论1:

张数为0

dp[1][3] ]= dp[2][3] = 0;

张数为1,可得 3 - 2 =1;

可得:

dp[1][3] = dp[2][1] = 0;

张数为2。

可得3 - 2*2 < 0取值0;

张数为3. 即3-3*2<0,直接取0

0+0+0+0=0,最终取值0

 

张数为0,

dp[1][4] = dp[2][4] = 0;

张数为1,可得 4 - 2 =2;

dp[1][4] = dp[2][2] = 0;

张数为2.

可得4 - 2*2 = 0.

dp[1][4] = dp[2][0] = 1;

张数为3:

4-3*2 < 0;直接取0

张数为4,4-4*2 < 0;直接取0

0+0+1+0+0=1

最终可得1种解法。

index 210000

1. 任何一行的每一列,当张数为0的时候,都是直接依赖下一行的当前列的值。也就是说这个值一定是依赖下一行的当前列的值。

2.  col是aim的值,当 zhangshu * arr[row] <= col 的时候,我们是依赖 dp[row + 1][col - (zhangshu * arr[row])]的值的。这一点是非常非常重要的。由此我们可以推导出;

0张,我们依赖y1处的值

1张,依赖y2处的值。

2张,依赖y3处的值

3张,依赖y4处的值

4张,依赖y5处的值

5张,依赖y6处的值

那 x 不就是 y1 + y2 + y3 + y4 + y5 + y6 吗?

x1 不就是 y2 + y3 + y4 + y5 +y6 吗?

状态转移可得。 x = x1 + y1.

根据以上推导,我们是不是可以直接转化成完整的表格,即

既然我们知道

x = x1 + y1; 假设x处的列下标col为15. 那么x1处的小标不就是 col - value.  此处的value不就是一维数组中的arr[index]的值,即为3。 那么x1处的下标不就是 15 - 3 = 12吗?

 for (int zhangshu = 0; zhangshu * arr[row] <= col; zhangshu++);循环是每次枚举下一行的值的。既然下一行的值已经存储在 x1 x2 x3 .......处,那我们还要这个for循环干嘛呢?

时间复杂度优化代码如下:

 //动态规划 针对时间复杂度的优化版public static int ways3(int[] arr, int aim) {if (arr == null || arr.length == 0 || aim < 0) {return 0;}//老样子int N = arr.length;int[][] dp = new int[N + 1][aim + 1];//最后一行的第一列为1,其余都为0。 根据递归 return aim == 0 ? 1 : 0;得到dp[N][0] = 1;//双层for循环,动态规划的老套路。一维数组arr作为横坐标,aim作为纵坐标for (int row = N -1 ; row >= 0; row--) {     //row代表递归中的 indexfor (int col = 0; col <= aim; col++) {   //col代表递归中的 aim// 每一列都存在aim为0张的情况,// 下一行的当前列dp[row][col] = dp[row + 1][col];//当前下标col, 那么前一处的下标不就是 col - arr[row] 吗 ?if (col - arr[row] >= 0) {/*** for循环中的 下一行的 dp[row + 1][col - (zhangshu * arr[row])]列** 直接转化为当前行的 前 col - arr[row] 列。*/dp[row][col] += dp[row][col - arr[row]];}}}return dp[0][aim];}

 以上代码已经对时间复杂度进行了优化,下面按照空间压缩的思维,对空间复杂度再进行优化。

在算法28 算法28:力扣64题,最小路径和------------样本模型-CSDN博客 和 算法29 算法29:不同路径问题(力扣62和63题)--针对算法28进行扩展-CSDN博客中,我已经详细的分析过空间压缩的技巧以及思维。下面直接上代码

空间压缩代码

//动态规划 针对空间复杂度的优化版public static int ways4(int[] arr, int aim) {if (arr == null || arr.length == 0 || aim < 0) {return 0;}//老样子int N = arr.length;int[] dp = new int[aim + 1];//最后一行的第一列为1,其余都为0。 根据递归 return aim == 0 ? 1 : 0;得到dp[0] = 1;//双层for循环,动态规划的老套路。一维数组arr作为横坐标,aim作为纵坐标for (int row = N -1 ; row >= 0; row--) {     //row代表递归中的 indexfor (int col = 0; col <= aim; col++) {   //col代表递归中的 aimif (col - arr[row] >= 0) {dp[col] += dp[col - arr[row]];}}}return dp[aim];}

从递归到动态规划,再对动态规划代码进行时间复杂度空间复杂度进行双重优化。本文重点介绍了从左往右模型的技巧、动态规划的推理、时间复杂度的优化。至于空间复杂度,由于前面2篇博客已经重点分析了,所有没有过多累赘叙述。

从左往右模型总结:

1、 针对固定集合,值不同,就是讨论要和不要的累加和

2.    针对非固定集合,面值固定,张数无限。口诀就是讨论要与不要,要的话逐步讨论要几张的累加和

下面贴出完整代码,并加入对数器进行海量数据测试:

package code03.动态规划_07.lesson4;/*** arr是面值数组,其中的值都是正数且没有重复。再给定一个正数aim。* 每个值都认为是一种面值,且认为张数是无限的。* 返回组成aim的方法数* 例如:arr = {1,2},aim = 4* 方法如下:1+1+1+1、1+1+2、2+2* 一共就3种方法,所以返回3*/
public class ContainWaysNotLimitPaper_05 {//递归版本public static int ways(int[] arr, int aim) {if (arr == null || arr.length == 0 || aim < 0) {return 0;}return process(arr, 0, aim);}public static int process (int[] arr, int index, int aim){if (index == arr.length) { // 没钱了return aim == 0 ? 1 : 0;}//讨论不同货币组成aim的可能int ways = 0;//因为货币张数无限,所有需要讨论每一种情况。此次,就不是简单的要与不要的问题了for (int zhangshu = 0; zhangshu * arr[index] <= aim; zhangshu++) {/*** 此处,还是讨论要与不要的问题。* 0张代表不要* 要的话需要讨论要几张 :* 要1 张, 那么后面的数组需要进行递归继续讨论要还是不要,要的话要几张* 要2 张,那么后面的数组需要进行递归继续讨论要还是不要,要的话要几张*  依次类推*/ways += process(arr, index + 1, aim - zhangshu * arr[index]);}return ways;}//动态规划public static int ways2(int[] arr, int aim) {if (arr == null || arr.length == 0 || aim < 0) {return 0;}//老样子int N = arr.length;int[][] dp = new int[N + 1][aim + 1];//最后一行的第一列为1,其余都为0。 根据递归 return aim == 0 ? 1 : 0;得到dp[N][0] = 1;//双层for循环,动态规划的老套路。一维数组arr作为横坐标,aim作为纵坐标for (int row = N -1 ; row >= 0; row--) {     //row代表递归中的 indexfor (int col = 0; col <= aim; col++) {   //col代表递归中的 aim//此处是比较复杂的,完全套用递归内部的代码。这一层的for循环就是对//要的张数进行讨论。int ways = 0;//此处zhangshu * arr[row] <= col是唯一变化。重点理解for (int zhangshu = 0; zhangshu * arr[row] <= col; zhangshu++) {/*** 此处,还是讨论要与不要的问题。* 0张代表不要* 要的话需要讨论要几张 :* 要1 张, 那么后面的数组需要进行递归继续讨论要还是不要,要的话要几张* 要2 张,那么后面的数组需要进行递归继续讨论要还是不要,要的话要几张*  依次类推*///根据ways += process(arr, row + 1, aim - zhangshu * arr[row]);推导//此处的aim - zhangshu * arr[index] 需要变成 col - zhangshu * arr[index]ways += dp[row + 1][col - (zhangshu * arr[row])];}dp[row][col] = ways;}}return dp[0][aim];}//动态规划 针对时间复杂度的优化版public static int ways3(int[] arr, int aim) {if (arr == null || arr.length == 0 || aim < 0) {return 0;}//老样子int N = arr.length;int[][] dp = new int[N + 1][aim + 1];//最后一行的第一列为1,其余都为0。 根据递归 return aim == 0 ? 1 : 0;得到dp[N][0] = 1;//双层for循环,动态规划的老套路。一维数组arr作为横坐标,aim作为纵坐标for (int row = N -1 ; row >= 0; row--) {     //row代表递归中的 indexfor (int col = 0; col <= aim; col++) {   //col代表递归中的 aim// 每一列都存在aim为0张的情况,// 下一行的当前列dp[row][col] = dp[row + 1][col];//当前下标col, 那么前一处的下标不就是 col - arr[row] 吗 ?if (col - arr[row] >= 0) {/*** for循环中的 下一行的 dp[row + 1][col - (zhangshu * arr[row])]列** 直接转化为当前行的 前 col - arr[row] 列。*/dp[row][col] += dp[row][col - arr[row]];}}}return dp[0][aim];}//动态规划 针对空间复杂度的优化版public static int ways4(int[] arr, int aim) {if (arr == null || arr.length == 0 || aim < 0) {return 0;}//老样子int N = arr.length;int[] dp = new int[aim + 1];//最后一行的第一列为1,其余都为0。 根据递归 return aim == 0 ? 1 : 0;得到dp[0] = 1;//双层for循环,动态规划的老套路。一维数组arr作为横坐标,aim作为纵坐标for (int row = N -1 ; row >= 0; row--) {     //row代表递归中的 indexfor (int col = 0; col <= aim; col++) {   //col代表递归中的 aimif (col - arr[row] >= 0) {dp[col] += dp[col - arr[row]];}}}return dp[aim];}// 为了测试public static int[] randomArray(int maxLen, int maxValue) {int N = (int) (Math.random() * maxLen);int[] arr = new int[N];boolean[] has = new boolean[maxValue + 1];for (int i = 0; i < N; i++) {do {arr[i] = (int) (Math.random() * maxValue) + 1;} while (has[arr[i]]);has[arr[i]] = true;}return arr;}// 为了测试public static void printArray(int[] arr) {for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();}public static void main(String[] args) {/*   int[] arr = {1,2,3};int aim = 13;System.out.println(ways(arr, aim));System.out.println(ways2(arr, aim));System.out.println(ways3(arr, aim));System.out.println(ways4(arr, aim));*/// 为了测试int maxLen = 10;int maxValue = 30;int testTime = 1000000;System.out.println("测试开始");for (int i = 0; i < testTime; i++) {int[] arr = randomArray(maxLen, maxValue);int aim = (int) (Math.random() * maxValue);int ans1 = ways(arr, aim);int ans2 = ways2(arr, aim);int ans3 = ways3(arr, aim);int ans4 = ways4(arr, aim);if (ans1 != ans2 || ans1 != ans3 || ans1 != ans4) {System.out.println("Oops!");printArray(arr);System.out.println(aim);System.out.println(ans1);System.out.println(ans2);System.out.println(ans3);break;}}System.out.println("测试结束");}
}

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

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

相关文章

【CSS】设置0.5px的边框宽度

直接写border: 0.5px solid red; 这样在移动端可能会出现问题&#xff0c;下面说下解决办法&#xff1a; 直接上代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-C…

Linux_apachectl 网页优化

1.1 网页压缩与缓存 在使用 Apache 作为 Web 服务器的过程中&#xff0c;只有对 Apache 服务器进行适当的优化配 置&#xff0c;才能让 Apache 发挥出更好的性能。反过来说&#xff0c;如果 Apache 的配置非常糟糕&#xff0c; Apache 可能无法正常为我们服务。因此&#xff0c…

web网站,可当期末作业,随机一言,天气,时钟,音乐等综合网站

文章目录 主页面时间胶囊底部条文心一言音乐播放器天气时钟禁用右键其他每次刷新页面会随机更换壁纸新春版 主页面 时间胶囊 底部条 文心一言 点击可随机变化文心一言 音乐播放器 天气时钟 禁用右键 其他 每次刷新页面会随机更换壁纸 新春版

科技助力教育:数字化如何改变家校社协同育人?

近年来,随着社会的快速发展,教育的责任已不再仅局限于学校。家庭、学校和社会协同育人理念,正成为促进教育高质量发展的关键要素。 2023年初,教育部等十三部门联合印发《关于健全学校家庭社会协同育人机制的意见》,提出到“十四五”时期末,形成更加完善的由“学校积极主导、家…

vscode安装Prettier插件,对vue3项目进行格式化

之前vscode因为安装了Vue Language Features (Volar)插件&#xff0c;导致Prettier格式化失效&#xff0c;今天有空&#xff0c;又重新设置了一下 1. 插件要先安装上 2. 打开settings.json {"editor.defaultFormatter": "esbenp.prettier-vscode","…

基于视觉的无人机自主降落系统设计

文章目录 摘 要第一章 绪论1.1 课题开发背景1.1.1 课题的意义1.1.2 国内外发展状况 1.2 课题研究内容1.3 课题研究步骤1.4 本章小节 第二章 MatlabGUI的搭建2.1 下载安装Matlab2.2 在Matlab中搭建GUI平台2.2.1 GUI介绍2.2.2 GUI的组成2.2.3 GUI搭建步骤2.2.4 GUI的使用 2.3 mat…

stable diffusion 基础教程-提示词之艺术风格用法

展现夕阳 golden hour, (rim lighting):1.2, warm tones, sun flare, soft shadows, vibrant colors, hazy glow, painterly effect, dreamy atmosphere阴影 chiaroscuro, (high contrast):1.2, dramatic shadows, bold highlights, moody atmosphere, captivating inte…

发挥数字化潜能,提升企业效率——探索三叠云证章管理系统

企业的生命源泉在于其持续且高效的运维&#xff0c;这非常依赖于其管理工作的顺畅和精准。在现代商业环境中&#xff0c;企业用证/章管理是一个至关重要的环节。然而&#xff0c;传统的用章管理方式往往存在诸多问题&#xff0c;如繁琐的手续、低效的审批流程以及容易出现的管理…

【React系列】JSX核心语法和原理

本文来自#React系列教程&#xff1a;https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. ES6 的 class 虽然目前React开发模式中更加流行hooks&#xff0c;但是依然有很多的项目依然是使用类组件&#x…

macOS跨进程通信: XPC 创建实例

一&#xff1a;简介 XPC 是 macOS 里苹果官方比较推荐和安全的的进程间通信机制。 集成流程简单&#xff0c;但是比较绕。 主要需要集成 XPC Server 这个模块&#xff0c;这个模块最终会被 apple 的根进程 launchd 管理和以独立进程的方法唤起和关闭&#xff0c; 我们主app 进…

解读IPD产品需求管理流程

在IPD体系下&#xff0c;产品投资组合管理的例行活动首先表现在对客户需求的快速响应上。这包括需求的收集、分析与决策、研发实现等端到端等业务流。需求管理本质上是一条“从客户中来到客户中去”的业务流。为了高效地协同各个部门&#xff0c;更好地管理客户需求被满足的全过…

光明源@智慧厕所技术:优化生活,提升卫生舒适度

在当今数字科技飞速发展的时代&#xff0c;我们的日常生活正在经历一场革命&#xff0c;而这场革命的其中一个前沿领域就是智慧厕所技术。这项技术不仅仅是对传统卫生间的一次升级&#xff0c;更是对我们生活品质的全方位提升。从智能感应到数据分析&#xff0c;从环保设计到舒…