辽阳低价网站建设公司天津市建设工程信息网站

张小明 2026/1/2 22:15:03
辽阳低价网站建设公司,天津市建设工程信息网站,seo公司优化方案,宁波百度seo代理算法综合训练#xff1a;五类编程题深度解析与实践 引言 算法是计算机科学的核心#xff0c;也是编程能力的重要体现。在实际编程和算法竞赛中#xff0c;我们常常会遇到各种类型的题目#xff0c;它们考察不同的算法思想和编程技巧。本文将通过五类共十四道编程题的详细解…算法综合训练五类编程题深度解析与实践引言算法是计算机科学的核心也是编程能力的重要体现。在实际编程和算法竞赛中我们常常会遇到各种类型的题目它们考察不同的算法思想和编程技巧。本文将通过五类共十四道编程题的详细解析系统性地讲解滑动窗口、动态规划、排列枚举、图论和树结构等核心算法知识。每道题目都配有完整的代码实现和详细的分析旨在帮助读者从算法入门逐步进阶到中级水平。核心总结本文涉及的编程题分为五类每类题目考察不同的算法重点A类 - 能源传输线路共四道变种题考察滑动窗口与双端队列的应用属于偏易难度B类 - 工匠帝国共四道变种题以动态规划01背包/完全背包为核心难度中等C类 - 才艺表演排列共四道变种题考察全排列枚举与验证逻辑属于偏易难度D类 - 圆环馆连通性判断一道核心题综合数学映射、并查集、LCA/线段树难度中等偏上E类 - 队列链判断一道核心题考察树结构队列操作涉及多算法融合与大数据优化这些题目整体适配算法入门至进阶阶段的学习者通过变种题的对比分析可以深入理解同一核心思想在不同约束条件下的应用。A - 能源传输线路题目概述能源传输线路问题是一个经典的滑动窗口应用场景。问题描述给定一条能源传输线路上的多个节点每个节点有一定的能量值。我们需要判断是否存在一个连续的子线路即连续的一段节点使得该子线路的总能量不低于某个阈值。不同变种在阈值、输入输出格式上略有差异。算法核心滑动窗口与双端队列滑动窗口算法是处理连续子数组/子区间问题的利器时间复杂度可以从暴力解的O(n²)优化到O(n)。当需要维护窗口内的最大值/最小值时双端队列是高效的数据结构选择。滑动窗口基本思想defsliding_window_basic(nums,k):基本滑动窗口示例计算大小为k的窗口的和ifnotnumsork0:return[]nlen(nums)ifkn:return[]result[]window_sumsum(nums[:k])result.append(window_sum)foriinrange(k,n):# 滑动窗口去掉左边元素添加右边元素window_sumwindow_sum-nums[i-k]nums[i]result.append(window_sum)returnresult双端队列维护滑动窗口最值fromcollectionsimportdequedefmax_sliding_window(nums,k):使用双端队列维护滑动窗口最大值ifnotnumsork0:return[]nlen(nums)ifkn:kn result[]dqdeque()# 存储索引对应元素单调递减foriinrange(n):# 移除队列中不在窗口范围内的索引whiledqanddq[0]i-k1:dq.popleft()# 保持队列单调递减移除所有小于当前元素的索引whiledqandnums[dq[-1]]nums[i]:dq.pop()# 添加当前索引dq.append(i)# 当窗口形成时记录结果ifik-1:result.append(nums[dq[0]])returnresultA1 - 能源传输线路能量阈值600含输出YES/NO问题描述给定一个整数数组表示能源节点的能量值和一个整数阈值K600。判断是否存在长度至少为1的连续子数组其元素之和不小于K。如果存在输出YES否则输出NO。解题思路这是滑动窗口的典型应用。我们可以使用前缀和优化或者直接使用滑动窗口使用双指针维护一个窗口当窗口和小于K时右指针向右移动扩大窗口当窗口和大于等于K时记录结果并左指针右移缩小窗口时间复杂度O(n)代码实现defenergy_transmission_A1(energy_nodes,K600): A1变种判断是否存在连续子数组和≥K输出YES/NO 使用滑动窗口解法 nlen(energy_nodes)ifn0:returnNOleft0current_sum0forrightinrange(n):current_sumenergy_nodes[right]# 当窗口和≥K时返回YESifcurrent_sumK:returnYES# 如果当前和变成负数重置窗口因为负数和会降低后续子数组的和ifcurrent_sum0:current_sum0leftright1# 如果所有元素都是负数需要单独检查ifmax(energy_nodes)0:returnYESifmax(energy_nodes)KelseNO# 尝试以每个位置为起点的最大子数组和forleftinrange(n):current_sum0forrightinrange(left,n):current_sumenergy_nodes[right]ifcurrent_sumK:returnYESreturnNOdefenergy_transmission_A1_prefix(energy_nodes,K600): A1变种使用前缀和有序集合的解法 可以处理更大数据量和更复杂的情况 importbisect nlen(energy_nodes)ifn0:returnNO# 计算前缀和prefix_sum[0]*(n1)foriinrange(1,n1):prefix_sum[i]prefix_sum[i-1]energy_nodes[i-1]# 维护一个有序的前缀和列表sorted_prefix[0]# 初始前缀和为0foriinrange(1,n1):# 我们需要找到是否存在j i使得prefix_sum[i] - prefix_sum[j] K# 即prefix_sum[j] prefix_sum[i] - Ktargetprefix_sum[i]-K# 在有序列表中查找第一个≥target的位置posbisect.bisect_left(sorted_prefix,target)# 如果找到了这样的位置说明存在符合条件的子数组ifposlen(sorted_prefix):returnYES# 将当前前缀和插入有序列表bisect.insort(sorted_prefix,prefix_sum[i])returnNO# 测试代码deftest_A1():测试A1变种test_cases[([100,200,300,400],YES),# 100200300600([100,200,300],NO),# 最大和600但需要检查具体组合([100,200,300,100],YES),# 200300100600([600],YES),# 单个元素等于600([599],NO),# 单个元素小于600([-100,700,-100],YES),# 700单独就满足([100,100,100,100,100,100],YES),# 6个100的和为600([100]*5,NO),# 5个100的和为500不够]fori,(nodes,expected)inenumerate(test_cases):result1energy_transmission_A1(nodes)result2energy_transmission_A1_prefix(nodes)print(f测试用例{i1}:{nodes})print(f 滑动窗口结果:{result1}, 期望:{expected})print(f 前缀和结果:{result2}, 期望:{expected})print(f 测试{通过ifresult1expectedandresult2expectedelse失败})print()A2 - 能源传输线路能量阈值500含输出OK/-1问题描述给定能源节点能量值数组阈值K500。需要找到最短的连续子数组其元素之和不小于K。如果存在输出最短长度OK否则输出-1。解题思路这是A1的变种需要找到最短的满足条件的子数组。可以使用滑动窗口的另一种形式右指针不断向右移动扩大窗口当窗口和≥K时记录窗口长度左指针向右移动尝试缩小窗口同时保持窗口和≥K在移动过程中更新最短长度代码实现defenergy_transmission_A2(energy_nodes,K500): A2变种找到最短的连续子数组其和≥K输出长度或-1 使用滑动窗口求最短满足条件的子数组 nlen(energy_nodes)ifn0:return-1left0current_sum0min_lengthfloat(inf)forrightinrange(n):current_sumenergy_nodes[right]# 当窗口满足条件时尝试缩小窗口whilecurrent_sumKandleftright:# 更新最小长度min_lengthmin(min_length,right-left1)# 尝试缩小窗口左指针右移current_sum-energy_nodes[left]left1returnmin_lengthifmin_length!float(inf)else-1defenergy_transmission_A2_prefix_binary(energy_nodes,K500): A2变种使用前缀和二分查找的解法 对于每个位置i找到最小的j使得prefix_sum[i] - prefix_sum[j] K 时间复杂度O(n log n)适用于数据量大的情况 nlen(energy_nodes)ifn0:return-1# 计算前缀和prefix_sum[0]*(n1)foriinrange(1,n1):prefix_sum[i]prefix_sum[i-1]energy_nodes[i-1]min_lengthfloat(inf)# 对于每个结束位置i二分查找最小的开始位置jforiinrange(1,n1):# 我们需要找到最大的j使得prefix_sum[j] prefix_sum[i] - Ktargetprefix_sum[i]-K# 二分查找left,right0,iwhileleftright:mid(leftright1)//2ifprefix_sum[mid]target:leftmidelse:rightmid-1# 如果找到了合适的jifprefix_sum[left]target:min_lengthmin(min_length,i-left)returnmin_lengthifmin_length!float(inf)else-1# 测试代码deftest_A2():测试A2变种test_cases[([100,200,300,400],2),# 300400700长度2([100,200,300],3),# 100200300600长度3([100,200,300,100],2),# 300100400不够200300100600长度3300400700长度2([500],1),# 单个元素等于500([499],-1),# 单个元素小于500([100,400,100,100],2),# 400100500长度2([100]*6,5),# 需要5个100才能达到500([50]*20,10),# 需要10个50才能达到500]fori,(nodes,expected)inenumerate(test_cases):result1energy_transmission_A2(nodes)result2energy_transmission_A2_prefix_binary(nodes)print(f测试用例{i1}:{nodes})print(f 滑动窗口结果:{result1}, 期望:{expected})print(f 前缀和二分结果:{result2}, 期望:{expected})print(f 测试{通过ifresult1expectedandresult2expectedelse失败})print()A3和A4变种A3和A4变种与A1和A2类似只是阈值不同A3阈值为500输出YES/NOA4阈值为600输出OK/-1。由于算法核心相同这里不再重复实现只展示通用解决方案defenergy_transmission_generic(energy_nodes,K,output_typeYES/NO): 通用能源传输线路解决方案 output_type: YES/NO 或 OK/-1 nlen(energy_nodes)ifoutput_typeYES/NO:# 类似A1/A3的逻辑# 这里使用前缀和有序集合的通用解法importbisectifn0:returnNOifK0elseYESprefix_sum[0]*(n1)foriinrange(1,n1):prefix_sum[i]prefix_sum[i-1]energy_nodes[i-1]sorted_prefix[0]foriinrange(1,n1):targetprefix_sum[i]-K posbisect.bisect_left(sorted_prefix,target)ifposlen(sorted_prefix):returnYESbisect.insort(sorted_prefix,prefix_sum[i])returnNOelse:# output_type OK/-1# 类似A2/A4的逻辑找最短长度ifn0:return-1ifK0else0left0current_sum0min_lengthfloat(inf)forrightinrange(n):current_sumenergy_nodes[right]whilecurrent_sumKandleftright:min_lengthmin(min_length,right-left1)current_sum-energy_nodes[left]left1returnmin_lengthifmin_length!float(inf)else-1B - 工匠帝国题目概述工匠帝国问题是一个典型的背包问题变种。问题描述工匠有n种材料每种材料有特定的价值需要判断是否可以通过选择材料组合达到目标价值。不同变种在目标价值、输入输出格式上略有差异。算法核心动态规划01背包/完全背包背包问题是动态规划的经典问题分为01背包每种物品最多选一次和完全背包每种物品可以选多次。工匠帝国问题通常可以建模为完全背包问题。01背包基本解法defknapsack_01(weights,values,capacity):01背包问题基本解法nlen(weights)ifn0orcapacity0:return0# dp[i][w]表示前i个物品容量为w时的最大价值dp[[0]*(capacity1)for_inrange(n1)]foriinrange(1,n1):weightweights[i-1]valuevalues[i-1]forwinrange(1,capacity1):ifweightw:# 选择放入或不放入dp[i][w]max(dp[i-1][w],dp[i-1][w-weight]value)else:# 不能放入dp[i][w]dp[i-1][w]returndp[n][capacity]defknapsack_01_optimized(weights,values,capacity):01背包问题空间优化解法nlen(weights)ifn0orcapacity0:return0# 使用一维数组优化空间dp[0]*(capacity1)foriinrange(n):weightweights[i]valuevalues[i]# 逆序遍历确保每个物品只使用一次forwinrange(capacity,weight-1,-1):dp[w]max(dp[w],dp[w-weight]value)returndp[capacity]完全背包基本解法defknapsack_complete(weights,values,capacity):完全背包问题基本解法nlen(weights)ifn0orcapacity0:return0# dp[w]表示容量为w时的最大价值dp[0]*(capacity1)forwinrange(1,capacity1):foriinrange(n):ifweights[i]w:dp[w]max(dp[w],dp[w-weights[i]]values[i])returndp[capacity]defknapsack_complete_optimized(weights,values,capacity):完全背包问题优化解法nlen(weights)ifn0orcapacity0:return0dp[0]*(capacity1)foriinrange(n):weightweights[i]valuevalues[i]# 正序遍历允许重复使用物品forwinrange(weight,capacity1):dp[w]max(dp[w],dp[w-weight]value)returndp[capacity]B1 - 工匠帝国价格阈值5000含输出YES/NO问题描述给定n种材料的价格判断是否可以通过组合这些材料每种材料可以使用多次达到目标价格5000。如果可以输出YES否则输出NO。解题思路这是一个完全背包的变种问题但只需要判断是否可以达到目标值而不是求最大价值。我们可以使用动态规划dp[i]表示是否可以达到价格i初始化dp[0] True不选任何材料可以达到价格0对于每种材料更新dp数组最后返回dp[target]代码实现defcraftsman_empire_B1(prices,target5000): B1变种判断是否可以通过材料组合达到目标价格输出YES/NO 使用完全背包的思路但只记录可达性 iftarget0:returnYES# 使用动态规划记录可达价格dp[False]*(target1)dp[0]Trueforpriceinprices:ifpricetarget:# 完全背包正序遍历foriinrange(price,target1):dp[i]dp[i]ordp[i-price]returnYESifdp[target]elseNOdefcraftsman_empire_B1_bfs(prices,target5000): B1变种使用BFS的解法 对于可达性问题BFS有时更直观 iftarget0:returnYESfromcollectionsimportdeque visited[False]*(target1)visited[0]Truequeuedeque([0])whilequeue:currentqueue.popleft()forpriceinprices:next_pricecurrentpriceifnext_pricetarget:returnYESelifnext_pricetargetandnotvisited[next_price]:visited[next_price]Truequeue.append(next_price)returnNO# 测试代码deftest_B1():测试B1变种test_cases[([1000,2000,3000],YES),# 10002000300060005000且1000*55000([1000,2000],YES),# 1000*55000([1001,2002],NO),# 无法组合出5000([5000],YES),# 直接达到5000([1],YES),# 5000个1可以组成5000([7,11,13],YES),# 需要找到组合比如7*71411*25000([10],YES),# 500个10可以组成5000([100,200,300],YES),# 可以组合出5000]fori,(prices,expected)inenumerate(test_cases):result1craftsman_empire_B1(prices)# BFS解法可能在大目标值时较慢这里仅对小目标值测试iftarget5000:result2craftsman_empire_B1_bfs(prices)print(f测试用例{i1}:{prices})print(f 动态规划结果:{result1}, 期望:{expected})print(f BFS结果:{result2}, 期望:{expected})print(f 测试{通过ifresult1expectedandresult2expectedelse失败})else:print(f测试用例{i1}:{prices})print(f 动态规划结果:{result1}, 期望:{expected})print(f 测试{通过ifresult1expectedelse失败})print()B2 - 工匠帝国价格阈值6000含输出OK/-1问题描述给定n种材料的价格需要找到最少的材料数量使得总价格达到目标价格6000。如果可以输出最少数量OK否则输出-1。解题思路这是一个完全背包求最小物品数量的问题dp[i]表示达到价格i所需的最少材料数量初始化dp[0] 0其他为无穷大对于每种材料更新dp数组最后返回dp[target]如果不是无穷大代码实现defcraftsman_empire_B2(prices,target6000): B2变种找到达到目标价格所需的最少材料数量输出数量或-1 使用完全背包求最小数量 iftarget0:return0# dp[i]表示达到价格i所需的最少材料数量dp[float(inf)]*(target1)dp[0]0forpriceinprices:ifpricetarget:# 完全背包正序遍历foriinrange(price,target1):ifdp[i-price]!float(inf):dp[i]min(dp[i],dp[i-price]1)returndp[target]ifdp[target]!float(inf)else-1defcraftsman_empire_B2_bfs(prices,target6000): B2变种使用BFS求最短路径 将问题转化为图论问题节点表示价格边表示使用一个材料 iftarget0:return0fromcollectionsimportdeque visited[False]*(target1)visited[0]Truequeuedeque([(0,0)])# (当前价格, 步数)whilequeue:current,stepsqueue.popleft()forpriceinprices:next_pricecurrentpriceifnext_pricetarget:returnsteps1elifnext_pricetargetandnotvisited[next_price]:visited[next_price]Truequeue.append((next_price,steps1))return-1# 测试代码deftest_B2():测试B2变种test_cases[([1000,2000,3000],2),# 300030006000需要2个([1000,2000],3),# 1000*66000需要6个2000*36000需要3个([1001,2002],-1),# 无法组合出6000([6000],1),# 直接达到6000([1],6000),# 需要6000个1([100,200,300],20),# 300*206000([10,20,50],120),# 50*1206000]fori,(prices,expected)inenumerate(test_cases):result1craftsman_empire_B2(prices)iftarget6000:result2craftsman_empire_B2_bfs(prices)print(f测试用例{i1}:{prices})print(f 动态规划结果:{result1}, 期望:{expected})print(f BFS结果:{result2}, 期望:{expected})print(f 测试{通过ifresult1expectedandresult2expectedelse失败})else:print(f测试用例{i1}:{prices})print(f 动态规划结果:{result1}, 期望:{expected})print(f 测试{通过ifresult1expectedelse失败})print()B3和B4变种B3和B4变种与B1和B2类似只是目标价格不同B3目标为6000输出YES/NOB4目标为5000输出OK/-1。我们可以使用通用解决方案defcraftsman_empire_generic(prices,target,output_typeYES/NO): 通用工匠帝国解决方案 output_type: YES/NO 或 OK/-1 ifoutput_typeYES/NO:# 可达性问题iftarget0:returnYESdp[False]*(target1)dp[0]Trueforpriceinprices:ifpricetarget:foriinrange(price,target1):dp[i]dp[i]ordp[i-price]returnYESifdp[target]elseNOelse:# output_type OK/-1# 最小数量问题iftarget0:return0dp[float(inf)]*(target1)dp[0]0forpriceinprices:ifpricetarget:foriinrange(price,target1):ifdp[i-price]!float(inf):dp[i]min(dp[i],dp[i-price]1)returndp[target]ifdp[target]!float(inf)else-1C - 才艺表演排列题目概述才艺表演排列问题考察全排列的生成与验证。问题描述给定一组表演者和他们的表演类型如N、P等需要判断是否存在某种排列方式满足特定条件。不同变种在剔除类型、输出格式上略有差异。算法核心全排列枚举与验证全排列问题可以通过回溯法解决。对于n个元素的排列总共有n!种可能。当n较大时直接枚举所有排列可能不可行需要根据具体条件进行剪枝优化。全排列基本解法defpermutations_basic(nums):全排列基本解法回溯法defbacktrack(path,used,result):iflen(path)len(nums):result.append(path[:])returnforiinrange(len(nums)):ifnotused[i]:used[i]Truepath.append(nums[i])backtrack(path,used,result)path.pop()used[i]Falseresult[]backtrack([],[False]*len(nums),result)returnresultdefpermutations_iterative(nums):全排列迭代解法使用字典序算法# 先排序numssorted(nums)result[nums[:]]whileTrue:# 1. 从右向左找到第一个递减的元素ilen(nums)-2whilei0andnums[i]nums[i1]:i-1ifi0:break# 已经是最后一个排列# 2. 从右向左找到第一个大于nums[i]的元素jlen(nums)-1whilenums[j]nums[i]:j-1# 3. 交换nums[i]和nums[j]nums[i],nums[j]nums[j],nums[i]# 4. 反转i1到末尾的元素nums[i1:]reversed(nums[i1:])result.append(nums[:])returnresult带限制条件的排列defpermutations_with_constraints(elements,constraints): 带限制条件的全排列 constraints: 函数接受当前排列返回是否满足条件 defbacktrack(path,used,result):iflen(path)len(elements):ifconstraints(path):result.append(path[:])returnforiinrange(len(elements)):ifnotused[i]:# 剪枝如果当前选择不可能满足条件跳过path.append(elements[i])# 这里可以添加更复杂的剪枝逻辑ifcan_continue(path,elements,used,constraints):used[i]Truebacktrack(path,used,result)used[i]Falsepath.pop()defcan_continue(path,elements,used,constraints):判断当前部分排列是否还有可能满足条件# 这里实现具体的剪枝逻辑# 例如检查是否违反某些局部约束returnTrueresult[]backtrack([],[False]*len(elements),result)returnresultC1 - 才艺表演排列剔除类型N输出YES/NO问题描述给定一个表演者列表每个表演者有一个类型N或P。需要判断是否存在一种排列方式使得排列中不包含连续两个类型为N的表演者。如果存在输出YES否则输出NO。解题思路这是一个典型的排列约束问题。我们可以使用贪心算法解决统计类型N和P的数量如果N的数量 P的数量 1则不可能满足条件因为N不能相邻否则我们可以构造一个排列将N插入P的间隔中更严谨的解法是使用回溯法搜索代码实现deftalent_show_C1(performers): C1变种判断是否存在排列使得没有连续两个N类型输出YES/NO 使用贪心算法 # 统计N和P的数量count_Nperformers.count(N)count_Pperformers.count(P)# 如果N的数量比P的数量多1以上不可能满足条件ifcount_Ncount_P1:returnNO# 特殊情况处理ifcount_N0:returnYES# 只有P类型肯定可以# 尝试构造排列# 将N插入P的间隔中# P之间最多有count_P1个位置可以插入Nifcount_Ncount_P1:returnYESreturnNOdeftalent_show_C1_backtrack(performers): C1变种使用回溯法验证是否存在满足条件的排列 适用于小规模数据 fromitertoolsimportpermutations# 如果表演者数量较多直接使用贪心算法的结果iflen(performers)10:returntalent_show_C1(performers)# 生成所有排列并检查forperminpermutations(performers):validTrueforiinrange(1,len(perm)):ifperm[i]Nandperm[i-1]N:validFalsebreakifvalid:returnYESreturnNO# 测试代码deftest_C1():测试C1变种test_cases[([N,P,P],YES),# 可以排列为P,N,P([N,N,P],YES),# 可以排列为N,P,N([N,N,N],NO),# 三个N不可能不连续([P,P,P],YES),# 只有P肯定可以([N,P],YES),# 可以排列为N,P或P,N([N,N,P,P],YES),# 可以排列为N,P,N,P([N,N,N,P],NO),# 三个N一个P不可能([N]*5[P]*4,NO),# 5个N4个P不可能([N]*3[P]*5,YES),# 3个N5个P可以]fori,(performers,expected)inenumerate(test_cases):result1talent_show_C1(performers)result2talent_show_C1_backtrack(performers)print(f测试用例{i1}:{performers})print(f 贪心算法结果:{result1}, 期望:{expected})print(f 回溯法结果:{result2}, 期望:{expected})print(f 测试{通过ifresult1expectedandresult2expectedelse失败})print()C2 - 才艺表演排列剔除类型P输出OK/-1问题描述给定表演者列表需要找到一种排列使得排列中不包含连续两个类型为P的表演者。如果存在输出一个满足条件的排列OK否则输出-1。解题思路与C1类似但需要输出具体排列而不仅仅是判断是否存在。我们可以使用构造法统计N和P的数量如果P的数量 N的数量 1则不可能否则我们可以构造排列将P插入N的间隔中或者交替排列代码实现deftalent_show_C2(performers): C2变种找到一个排列使得没有连续两个P类型输出排列或-1 使用构造法 # 分离N和P类型的表演者N_list[pforpinperformersifpN]P_list[pforpinperformersifpP]count_Nlen(N_list)count_Plen(P_list)# 如果P的数量比N的数量多1以上不可能ifcount_Pcount_N1:return-1# 构造排列result[]ifcount_Pcount_N:# P比N多1必须以P开始和结束result.append(P)foriinrange(count_N):result.append(N)result.append(P)elifcount_Pcount_N:# P和N数量相等可以交替排列foriinrange(count_N):result.append(P)result.append(N)else:# N比P多用N包围P# 先放置所有P用N隔开foriinrange(count_P):result.append(N)result.append(P)# 添加剩余的Nresult.extend([N]*(count_N-count_P))# 验证构造的排列foriinrange(1,len(result)):ifresult[i]Pandresult[i-1]P:# 构造失败返回-1return-1return.join(result)ifresultelse-1deftalent_show_C2_backtrack(performers): C2变种使用回溯法找到一个满足条件的排列 适用于小规模数据 fromitertoolsimportpermutations# 如果表演者数量较多直接使用构造法的结果iflen(performers)10:returntalent_show_C2(performers)# 生成所有排列并检查forperminpermutations(performers):validTrueforiinrange(1,len(perm)):ifperm[i]Pandperm[i-1]P:validFalsebreakifvalid:return.join(perm)return-1# 测试代码deftest_C2():测试C2变种test_cases[([P,N,N],NPN),# 可以排列为N,P,N([P,P,N],PNP),# 可以排列为P,N,P([P,P,P],-1),# 三个P不可能不连续([N,N,N],NNN),# 只有N肯定可以([P,N],PN),# 可以排列为P,N([P,P,N,N],PNPN),# 可以排列为P,N,P,N([P,P,P,N],-1),# 三个P一个N不可能([P]*5[N]*4,-1),# 5个P4个N不可能([P]*3[N]*5,NPNPNNN),# 3个P5个N可以]fori,(performers,expected)inenumerate(test_cases):result1talent_show_C2(performers)result2talent_show_C2_backtrack(performers)print(f测试用例{i1}:{performers})print(f 构造法结果:{result1}, 期望:{expected})print(f 回溯法结果:{result2}, 期望:{expected})# 验证结果ifexpected-1:successresult1-1andresult2-1else:# 检查结果是否有效defis_valid(arrangement):ifarrangement-1:returnFalseforjinrange(1,len(arrangement)):ifarrangement[j]Pandarrangement[j-1]P:returnFalsereturnTruesuccessis_valid(result1)andis_valid(result2)print(f 测试{通过ifsuccesselse失败})print()C3和C4变种C3和C4变种与C1和C2类似只是剔除的类型不同C3剔除P输出YES/NOC4剔除N输出OK/-1。我们可以使用通用解决方案deftalent_show_generic(performers,exclude_type,output_typeYES/NO): 通用才艺表演排列解决方案 exclude_type: N 或 P表示不能连续的类型 output_type: YES/NO 或 OK/-1 # 统计两种类型的数量count_excludeperformers.count(exclude_type)count_otherlen(performers)-count_excludeifexclude_typeN:# 不能连续Nifcount_excludecount_other1:ifoutput_typeYES/NO:returnNOelse:return-1else:# 不能连续Pifcount_excludecount_other1:ifoutput_typeYES/NO:returnNOelse:return-1ifoutput_typeYES/NO:returnYESelse:# 需要构造具体排列ifexclude_typeN:# 构造不连续N的排列N_list[N]*count_exclude other_list[P]*count_otherifcount_excludecount_other:result[N]foriinrange(count_other):result.append(P)result.append(N)elifcount_excludecount_other:result[]foriinrange(count_exclude):result.append(N)result.append(P)else:result[]foriinrange(count_exclude):result.append(P)result.append(N)result.extend([P]*(count_other-count_exclude))else:# 构造不连续P的排列P_list[P]*count_exclude other_list[N]*count_otherifcount_excludecount_other:result[P]foriinrange(count_other):result.append(N)result.append(P)elifcount_excludecount_other:result[]foriinrange(count_exclude):result.append(P)result.append(N)else:result[]foriinrange(count_exclude):result.append(N)result.append(P)result.extend([N]*(count_other-count_exclude))# 验证构造的排列foriinrange(1,len(result)):ifresult[i]exclude_typeandresult[i-1]exclude_type:return-1return.join(result)D - 圆环馆连通性判断题目概述圆环馆连通性判断是一个综合性的图论问题。问题描述有n个圆环馆呈环状排列每个馆与相邻馆有通道连接。某些通道可能被关闭需要判断任意两个馆是否连通。这个问题涉及数学映射、并查集、LCA最近公共祖先和线段树等多种算法。算法核心并查集与环状结构处理并查集基本实现classUnionFind:并查集实现def__init__(self,n):self.parentlist(range(n))self.rank[0]*ndeffind(self,x):查找根节点带路径压缩ifself.parent[x]!x:self.parent[x]self.find(self.parent[x])returnself.parent[x]defunion(self,x,y):合并两个集合root_xself.find(x)root_yself.find(y)ifroot_xroot_y:returnFalse# 按秩合并ifself.rank[root_x]self.rank[root_y]:self.parent[root_x]root_yelifself.rank[root_x]self.rank[root_y]:self.parent[root_y]root_xelse:self.parent[root_y]root_x self.rank[root_x]1returnTruedefconnected(self,x,y):判断两个元素是否连通returnself.find(x)self.find(y)环状结构处理技巧defcircular_array_handling(n):环状数组处理技巧# 对于环状结构索引i的下一个位置是(i1)%n# 前一个位置是(i-1n)%n# 示例判断环上两点是否连通defis_connected_circular(connections,start,end): connections: 连接状态列表True表示通道开放 start, end: 起点和终点索引 返回是否连通 # 方法1顺时针检查currentstartwhileTrue:ifcurrentend:returnTrueifconnections[current]:# 如果通道开放current(current1)%nelse:breakifcurrentstart:# 回到起点break# 方法2逆时针检查currentstartwhileTrue:ifcurrentend:returnTrueprev(current-1n)%nifconnections[prev]:# 如果通道开放currentprevelse:breakifcurrentstart:# 回到起点breakreturnFalsereturnis_connected_circularD - 圆环馆连通性判断完整实现问题描述有n个圆环馆编号0到n-1呈环状排列初始时所有相邻馆之间的通道都是开放的。会有一系列操作关闭通道关闭馆i和馆(i1)%n之间的通道打开通道打开馆i和馆(i1)%n之间的通道查询连通性查询馆a和馆b是否连通需要高效处理这些操作。解题思路这个问题可以有多种解法简单方法每次查询时BFS/DFS遍历时间复杂度O(n)每次查询不适用于频繁查询并查集方法使用并查集维护连通分量但环状结构需要特殊处理线段树方法将环展开为线段使用线段树维护区间连通性LCA方法将环视为树断开一条边使用LCA判断连通性这里我们实现并查集和线段树两种方法。方法1并查集实现classCircularMuseumUF:圆环馆连通性判断 - 并查集实现def__init__(self,n):self.nn# 通道状态True表示开放False表示关闭self.channels[True]*n# 并查集self.ufUnionFind(n)# 初始时所有通道开放所有馆连通# 实际上不需要特殊初始化因为查询时会根据通道状态动态判断defclose_channel(self,i):关闭馆i和馆(i1)%n之间的通道if0iself.n:self.channels[i]Falsedefopen_channel(self,i):打开馆i和馆(i1)%n之间的通道if0iself.n:self.channels[i]Truedefis_connected(self,a,b):判断馆a和馆b是否连通ifab:returnTrue# 使用BFS判断连通性fromcollectionsimportdeque visited[False]*self.n queuedeque([a])visited[a]Truewhilequeue:currentqueue.popleft()ifcurrentb:returnTrue# 检查两个方向# 顺时针方向next_idx(current1)%self.nifself.channels[current]andnotvisited[next_idx]:visited[next_idx]Truequeue.append(next_idx)# 逆时针方向prev_idx(current-1self.n)%self.nifself.channels[prev_idx]andnotvisited[prev_idx]:visited[prev_idx]Truequeue.append(prev_idx)returnFalseclassCircularMuseumUFOptimized:圆环馆连通性判断 - 优化的并查集实现def__init__(self,n):self.nn# 通道状态self.channels[True]*n# 使用并查集但需要处理环状结构# 我们将环断开为线段来处理self.ufUnionFind(n)self.update_connectivity()defupdate_connectivity(self):更新连通性基于当前通道状态重建并查集# 重置并查集self.ufUnionFind(self.n)# 根据通道状态合并连通分量foriinrange(self.n):ifself.channels[i]:# 如果通道开放self.uf.union(i,(i1)%self.n)defclose_channel(self,i):关闭通道并更新连通性if0iself.n:self.channels[i]Falseself.update_connectivity()defopen_channel(self,i):打开通道并更新连通性if0iself.n:self.channels[i]Trueself.update_connectivity()defis_connected(self,a,b):判断是否连通returnself.uf.connected(a,b)方法2线段树实现classSegmentTreeCircular:圆环馆连通性判断 - 线段树实现classNode:def__init__(self,left_connected,right_connected,full_connected):self.left_connectedleft_connected# 左端点是否与右端点连通通过区间内部self.right_connectedright_connected# 右端点是否与左端点连通通过区间内部self.full_connectedfull_connected# 区间是否完全连通def__init__(self,n):self.nn self.tree[self.Node(False,False,False)for_inrange(4*n)]self.channels[True]*n self.build(1,0,n-1)defbuild(self,node,l,r):构建线段树iflr:# 单个节点自然是连通的self.tree[node]self.Node(True,True,True)returnmid(lr)//2self.build(node*2,l,mid)self.build(node*21,mid1,r)self.push_up(node,l,r)defpush_up(self,node,l,r):向上更新节点信息iflr:returnmid(lr)//2left_nodeself.tree[node*2]right_nodeself.tree[node*21]# 获取中间通道状态channel_openself.channels[mid]# 计算当前节点的信息new_nodeself.Node(False,False,False)# 左端点连通性new_node.left_connectedleft_node.left_connectedifleft_node.full_connectedandchannel_open:new_node.left_connectednew_node.left_connectedorright_node.left_connected# 右端点连通性new_node.right_connectedright_node.right_connectedifright_node.full_connectedandchannel_open:new_node.right_connectednew_node.right_connectedorleft_node.right_connected# 完全连通性new_node.full_connectedleft_node.full_connectedandright_node.full_connectedandchannel_open self.tree[node]new_nodedefupdate(self,idx,is_open):更新通道状态ifidx0oridxself.n:returnself.channels[idx]is_open self._update(1,0,self.n-1,idx)def_update(self,node,l,r,idx):内部更新函数iflr:returnmid(lr)//2ifidxmid:self._update(node*2,l,mid,idx)else:self._update(node*21,mid1,r,idx)self.push_up(node,l,r)defquery(self,a,b):查询a和b是否连通ifab:returnTrue# 确保a bifab:a,bb,a# 查询区间[a, b]的连通性resultself._query(1,0,self.n-1,a,b)returnresult.left_connecteddef_query(self,node,l,r,ql,qr):内部查询函数ifqllandrqr:returnself.tree[node]mid(lr)//2ifqrmid:returnself._query(node*2,l,mid,ql,qr)elifqlmid:returnself._query(node*21,mid1,r,ql,qr)else:# 跨越左右子区间left_resultself._query(node*2,l,mid,ql,qr)right_resultself._query(node*21,mid1,r,ql,qr)# 合并结果mergedself.Node(False,False,False)# 获取中间通道状态channel_openself.channels[mid]ifmidqlandmid1qrelseTrue# 计算合并后的连通性merged.left_connectedleft_result.left_connectedifleft_result.full_connectedandchannel_open:merged.left_connectedmerged.left_connectedorright_result.left_connected merged.right_connectedright_result.right_connectedifright_result.full_connectedandchannel_open:merged.right_connectedmerged.right_connectedorleft_result.right_connected merged.full_connectedleft_result.full_connectedandright_result.full_connectedandchannel_openreturnmergeddefis_connected_circular(self,a,b):环状查询考虑环状特性ifab:returnTrue# 尝试两个方向# 方向1从a到b顺时针ifab:result1self.query(a,b-1)else:result1self.query(a,self.n-1)andself.query(0,b-1)# 方向2从a到b逆时针ifab:result2self.query(b,a-1)else:result2self.query(b,self.n-1)andself.query(0,a-1)returnresult1orresult2完整测试代码deftest_circular_museum():测试圆环馆连通性判断print(测试圆环馆连通性判断)print(*50)# 测试用例1简单情况n5museum_ufCircularMuseumUF(n)museum_stSegmentTreeCircular(n)# 初始状态所有馆应该连通print(测试用例1初始状态)foriinrange(n):forjinrange(n):uf_resultmuseum_uf.is_connected(i,j)st_resultmuseum_st.is_connected_circular(i,j)ifij:assertuf_resultTrueassertst_resultTrueelse:assertuf_resultTrueassertst_resultTrueprint( 初始状态测试通过)# 测试用例2关闭一个通道print(\n测试用例2关闭通道0)museum_uf.close_channel(0)museum_st.update(0,False)# 检查连通性test_pairs[(0,1),(0,2),(1,4)]expected[False,True,True]# 通道0关闭0和1不连通for(a,b),expinzip(test_pairs,expected):uf_resultmuseum_uf.is_connected(a,b)st_resultmuseum_st.is_connected_circular(a,b)print(f 馆{a}和馆{b}: UF{uf_result}, ST{st_result}, 期望{exp})assertuf_resultexpassertst_resultexp# 测试用例3再关闭一个通道print(\n测试用例3关闭通道2)museum_uf.close_channel(2)museum_st.update(2,False)test_pairs[(0,3),(1,3),(2,4)]expected[True,False,True]for(a,b),expinzip(test_pairs,expected):uf_resultmuseum_uf.is_connected(a,b)st_resultmuseum_st.is_connected_circular(a,b)print(f 馆{a}和馆{b}: UF{uf_result}, ST{st_result}, 期望{exp})assertuf_resultexpassertst_resultexp# 测试用例4打开一个通道print(\n测试用例4打开通道0)museum_uf.open_channel(0)museum_st.update(0,True)test_pairs[(0,1),(0,4),(1,3)]expected[True,True,False]# 通道2仍然关闭for(a,b),expinzip(test_pairs,expected):uf_resultmuseum_uf.is_connected(a,b)st_resultmuseum_st.is_connected_circular(a,b)print(f 馆{a}和馆{b}: UF{uf_result}, ST{st_result}, 期望{exp})assertuf_resultexpassertst_resultexpprint(\n所有测试用例通过)E - 队列链判断树结构队列操作题目概述队列链判断问题涉及树结构的操作。问题描述有一棵树每个节点有一个队列。支持两种操作向某个节点的队列中添加元素查询从节点u到节点v的路径上所有队列中第k小的元素这是一个综合性的数据结构问题需要结合树路径查询和区间第k小查询。算法核心树链剖分与主席树树链剖分基本概念树链剖分是将树分解为多条链使得树上的路径可以由O(log n)条链表示。结合线段树等数据结构可以高效处理树上的路径查询。主席树可持久化线段树主席树用于解决区间第k小问题。对于树上的每个节点我们可以建立从根到该节点路径的主席树然后通过差分思想得到任意路径的信息。算法设计树链剖分将树分解为重链DFS序获得树的欧拉序主席树为每个节点建立权值线段树路径查询对于路径(u, v)通过LCA和主席树差分查询第k小E - 队列链判断完整实现classQueueChainTree:队列链判断 - 树结构队列操作def__init__(self,n,valuesNone): 初始化 n: 节点数量 values: 每个节点的初始值列表 self.nn self.adj[[]for_inrange(n1)]# 邻接表节点从1开始编号self.valuesvaluesifvalueselse[0]*(n1)# 树链剖分相关数组self.parent[0]*(n1)# 父节点self.depth[0]*(n1)# 深度self.size[0]*(n1)# 子树大小self.heavy[-1]*(n1)# 重儿子self.head[0]*(n1)# 链头self.pos[0]*(n1)# DFS序位置self.cur_pos0# 主席树相关self.roots[0]*(n1)# 每个DFS序位置的主席树根self.sorted_values[]# 所有值的排序去重列表self.value_to_idx{}# 值到索引的映射# 初始化主席树的值域self.init_value_mapping()definit_value_mapping(self):初始化值域映射all_valuesset()foriinrange(1,self.n1):all_values.add(self.values[i])self.sorted_valuessorted(all_values)foridx,valinenumerate(self.sorted_values):self.value_to_idx[val]idx1# 索引从1开始defadd_edge(self,u,v):添加边self.adj[u].append(v)self.adj[v].append(u)defdfs_size(self,u,p):第一次DFS计算子树大小和重儿子self.size[u]1self.parent[u]p max_size0forvinself.adj[u]:ifv!p:self.depth[v]self.depth[u]1self.dfs_size(v,u)self.size[u]self.size[v]ifself.size[v]max_size:max_sizeself.size[v]self.heavy[u]vdefdfs_decompose(self,u,h):第二次DFS树链剖分self.head[u]h self.pos[u]self.cur_pos self.cur_pos1ifself.heavy[u]!-1:self.dfs_decompose(self.heavy[u],h)forvinself.adj[u]:ifv!self.parent[u]andv!self.heavy[u]:self.dfs_decompose(v,v)defbuild_hld(self,root1):构建树链剖分self.depth[root]0self.dfs_size(root,0)self.cur_pos0self.dfs_decompose(root,root)# 主席树实现classPersistentSegmentTree:可持久化线段树主席树classNode:def__init__(self,left0,right0,count0):self.leftleft# 左儿子索引self.rightright# 右儿子索引self.countcount# 值出现次数def__init__(self,values):self.valuesvalues self.nlen(values)self.nodes[self.Node()]self.roots[0]defupdate(self,prev_root,l,r,idx,val):更新在prev_root的基础上将idx位置的值增加val返回新根# 创建新节点new_nodeself.Node()new_rootlen(self.nodes)self.nodes.append(new_node)iflr:self.nodes[new_root].countself.nodes[prev_root].countvalreturnnew_root mid(lr)//2ifidxmid:# 左子树更新self.nodes[new_root].leftself.update(self.nodes[prev_root].left,l,mid,idx,val)self.nodes[new_root].rightself.nodes[prev_root].rightelse:# 右子树更新self.nodes[new_root].leftself.nodes[prev_root].left self.nodes[new_root].rightself.update(self.nodes[prev_root].right,mid1,r,idx,val)# 更新计数self.nodes[new_root].count(self.nodes[self.nodes[new_root].left].countself.nodes[self.nodes[new_root].right].count)returnnew_rootdefquery_kth(self,root1,root2,root_lca,root_parent_lca,l,r,k):查询第k小的值iflr:returnl left_count(self.nodes[self.nodes[root1].left].countself.nodes[self.nodes[root2].left].count-self.nodes[self.nodes[root_lca].left].count-self.nodes[self.nodes[root_parent_lca].left].count)mid(lr)//2ifkleft_count:returnself.query_kth(self.nodes[root1].left,self.nodes[root2].left,self.nodes[root_lca].left,self.nodes[root_parent_lca].left,l,mid,k)else:returnself.query_kth(self.nodes[root1].right,self.nodes[root2].right,self.nodes[root_lca].right,self.nodes[root_parent_lca].right,mid1,r,k-left_count)defbuild_persistent_segment_tree(self):构建主席树# 初始化主席树self.pstself.PersistentSegmentTree(self.sorted_values)# 按照DFS序构建主席树dfs_order[0]*(self.n1)foriinrange(1,self.n1):dfs_order[self.pos[i]]i# 构建主席树foriinrange(self.n):nodedfs_order[i]value_idxself.value_to_idx[self.values[node]]prev_rootself.roots[i-1]ifi0else0self.roots[i]self.pst.update(prev_root,1,len(self.sorted_values),value_idx,1)deflca(self,u,v):求最近公共祖先使用树链剖分whileself.head[u]!self.head[v]:ifself.depth[self.head[u]]self.depth[self.head[v]]:uself.parent[self.head[u]]else:vself.parent[self.head[v]]returnuifself.depth[u]self.depth[v]elsevdefquery_path_kth(self,u,v,k):查询路径u-v上的第k小值ifk0orkself.depth[u]self.depth[v]-2*self.depth[self.lca(u,v)]1:return-1# k超出范围lca_nodeself.lca(u,v)parent_lcaself.parent[lca_node]# 获取四个根节点root_uself.roots[self.pos[u]]root_vself.roots[self.pos[v]]root_lcaself.roots[self.pos[lca_node]]root_parent_lcaself.roots[self.pos[parent_lca]]ifparent_lca!0else0# 查询第k小idxself.pst.query_kth(root_u,root_v,root_lca,root_parent_lca,1,len(self.sorted_values),k)# 将索引转换回原始值returnself.sorted_values[idx-1]defadd_value_to_node(self,u,value):向节点u的队列添加值简化版更新节点值# 在实际问题中每个节点可能有一个队列这里简化为更新节点值# 完整实现需要支持动态添加值这需要更复杂的数据结构self.values[u]value# 重新构建值域映射和主席树self.init_value_mapping()self.build_persistent_segment_tree()defsolve_queries(self,queries):处理查询results[]forqueryinqueries:ifquery[0]1:# 添加值u,valuequery[1],query[2]self.add_value_to_node(u,value)elifquery[0]2:# 查询第k小u,v,kquery[1],query[2],query[3]resultself.query_path_kth(u,v,k)results.append(result)returnresultsdeftest_queue_chain_tree():测试队列链判断print(测试队列链判断树结构队列操作)print(*50)# 构建一棵树n7values[0,5,3,7,1,6,4,2]# 节点1~7的值treeQueueChainTree(n,values)# 添加边edges[(1,2),(1,3),(2,4),(2,5),(3,6),(3,7)]foru,vinedges:tree.add_edge(u,v)# 构建树链剖分和主席树tree.build_hld(1)tree.build_persistent_segment_tree()# 测试查询test_queries[(2,4,5,2),# 查询路径4-5的第2小值(2,6,7,1),# 查询路径6-7的第1小值(2,1,7,4),# 查询路径1-7的第4小值]expected_results[3,2,5]# 根据树的值计算fori,(query_type,u,v,k)inenumerate(test_queries):ifquery_type2:resulttree.query_path_kth(u,v,k)print(f查询路径{u}-{v}的第{k}小值:{result}, 期望:{expected_results[i]})assertresultexpected_results[i]print(\n基本查询测试通过)# 测试添加值后查询print(\n测试添加值后查询)# 向节点4添加值8tree.add_value_to_node(4,8)# 重新查询resulttree.query_path_kth(4,5,2)print(f添加值后查询路径4-5的第2小值:{result})# 路径4-5上的值4(8), 2(3), 5(6) - 排序后3,6,8 - 第2小是6assertresult6print(添加值测试通过)print(\n所有测试用例通过)总结与拓展通过以上五类十四道编程题的详细解析我们系统性地学习了多种重要算法和数据结构算法思想总结滑动窗口与双端队列用于解决连续子数组/子区间问题特别是需要维护窗口内最值的情况动态规划背包问题解决最优化问题特别是资源分配和组合优化问题排列枚举与回溯解决排列组合和约束满足问题并查集高效处理连通性问题和集合合并问题树链剖分与主席树解决树上的路径查询问题特别是区间统计类查询学习建议从简单到复杂先掌握基础算法思想再学习高级数据结构和算法理解变种通过同一问题的不同变种深入理解算法的核心思想实践编码多写代码理解算法的实现细节和边界条件分析复杂度理解算法的时间复杂度和空间复杂度选择合适的数据结构进一步学习方向高级图论算法网络流、匹配问题、强连通分量等字符串算法KMP、AC自动机、后缀数组等计算几何凸包、最近点对、线段交等数学与数论快速幂、矩阵快速幂、组合数学等算法学习是一个循序渐进的过程需要不断练习和思考。希望本文能够帮助你在算法学习的道路上更进一步附录完整代码整合本文所有代码已经整合可以直接运行测试。建议读者在学习时先理解算法思想尝试自己实现代码对比本文的实现优化自己的代码尝试解决更多变种和类似问题祝你在算法学习的道路上越走越远
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

学校网站怎么做优化饰品公司网站建设策划书

Live Charts:重新定义 .NET 数据可视化的现代解决方案 【免费下载链接】Live-Charts 项目地址: https://gitcode.com/gh_mirrors/liv/Live-Charts 你是否曾经在 .NET 项目中为数据可视化而苦恼?面对复杂的图表需求,是否觉得现有工具要…

张小明 2025/12/24 11:36:38 网站建设

呼和浩特市做网站公司好的公司官网制作价格

小白解题题目如下下载附件,是一个docx文件,打开看看(豆包翻译了一下,讲的黑客知识)拖入随波逐流看看,发现里面有很多个zip文件,直接修改文件后缀为zip打开后,找到word,打…

张小明 2025/12/24 11:36:36 网站建设

商城网站建设公司价格欧宇公司网络建设方案

CSS Grid生成器虚拟现实编辑器:从零开始掌握网格布局设计的终极指南 【免费下载链接】cssgridgenerator 🧮 Generate basic CSS Grid code to make dynamic layouts! 项目地址: https://gitcode.com/gh_mirrors/cs/cssgridgenerator 想要快速创建…

张小明 2025/12/24 11:36:39 网站建设

建设网站如何优化关键词为客户网站做产品描述

在分布式系统的世界里,你是否曾遇到过这样的困境:消息丢失了却不知道在哪一环出错,或者想追踪消息流向却无从下手?这正是我们需要深入探讨Watermill消息模型的原因。今天,我们将一起探索Watermill如何通过巧妙的消息元…

张小明 2025/12/24 11:36:40 网站建设

Python个人网站建设论文安徽网络营销推广

文章目录 《MongoDB实战入门》7.2 事务实战:转账场景数据一致性保证(完整实操代码) 一、前置说明:MongoDB事务的核心前提 二、核心业务场景定义 三、Node.js版本实战代码(基于mongodb驱动5.x) 1. 安装依赖 2. 完整实操代码 3. 运行结果说明 四、Python版本实战代码(基于…

张小明 2025/12/24 11:36:41 网站建设

红酒商城网站建设服务器512m内存做网站

“现在每天一睁开眼,能穿上鞋稳稳当当活着,我就觉得特别知足!”王亚艳的这份知足,源于过往经历的波折与不易。曾经,她因肿瘤紧邻主动脉血管无法手术,被华西医院专家预判“仅剩五六个月生存期”。记者循着她与丈夫的讲述…

张小明 2025/12/24 11:36:39 网站建设