动态规划专题

目录

    • 动态规划基础
        • 钢条切割
        • 矩阵链乘法
        • 动态规划原理
            • 最优子结构
          • 经典问题:
          • 子问题重叠
          • 重构最优解
        • 最长公共子序列
        • 最优二叉搜索树
        • 最长连续不下降子序列
        • 最长不下降子序列
        • 经典问题(来自习题)
          • DAG 中的最长简单路径
          • 最长回文子序列
          • 最长回文子串
  • 记忆化搜索
          • 记忆化搜索的特征:
          • 如何写记忆化搜索
        • 记忆化搜索的优缺点
            • 优点:
          • 缺点:
          • 记忆化搜索的注意事项
  • 背包 DP
    • 0-1 背包
          • 核心代码:
    • 完全背包
    • 二维费用背包
    • 分组背包
    • 输出方案
    • 求方案数
    • 求最优方案总数
  • 区间 DP
  • DAG 上的 DP
  • 树形 DP
  • 状压 DP
  • 数位 DP
  • 插头 DP
  • 计数 DP
  • 动态 DP
  • 概率 DP
  • DP 优化
    • 单调队列/单调栈优化
    • 斜率优化
    • 四边形不等式优化
    • 状态设计优化
  • 其它 DP 方法

动态规划(Dynamic programming,简称 DP)通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。
动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。
通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。
严格意义上,动态规划只能用来解决最优化问题,但在 OI 中,计数等非最优化问题的递推解法也常被不规范地称作 DP。事实上,动态规划与其它类型的递推的确有很多相似之处,学习时可以注意它们之间的异同。

动态规划基础

动态规划应用于子问题重叠的情况:

  1. 要去刻画最优解的结构特征;
  2. 尝试递归地定义最优解的值(就是我们常- 说的考虑从 转移到 );
  3. 计算最优解;
  4. 利用计算出的信息构造一个最优解。

钢条切割

给定一段钢条,和不同长度的价格,问如何切割使得总价格最大。
为了求解规模为n的原问题,我们先求解形式完全一样,但规模更小的子问题。 即当完成首次切割后,我们将两段钢条看成两个独立的钢条切割问题实例。 我们通过组合相关子问题的最优解,并在所有可能的两段切割方案中选取组合收益最大者,构成原问题的最优解。

最优子结构:问题的最优解由相关子问题的最优解组合而成,而这些子问题可以独立求解。

动态规划的两种实现方法:

  • 带备忘的自顶向下法(记忆化搜索);
  • 自底向上法(将子问题按规模排序,类似于递推)。

算导用子问题图上按照逆拓扑序求解问题,引出记忆化搜索。
重构解(输出方案):转移的时候记录最优子结构的位置。

矩阵链乘法

给出 n个矩阵的序列,希望计算他们的乘积,问最少需要多少次乘法运算?

(认为p×qp\times qp×q 的矩阵与q×rq\times rq×r 的矩阵相乘代价是p×q×rp \times q \times rp×q×r 。)
完全括号化方案是指要给出谁先和谁乘。

动态规划原理

两个要素:

最优子结构

具有最优子结构也可能是适合用贪心的方法求解。
注意要确保我们考察了最优解中用到的所有子问题。

  1. 证明问题最优解的第一个组成部分是做出一个选择;
  2. 对于一个给定问题,在其可能的第一步选择中,你界定已经知道哪种选择才会得到最优解。你现在并不关心这种选择具体是如何得到的,只是假定已经知道了这种选择;
    给定可获得的最优解的选择后,确定这次选择会产生哪些子问题,以及如何最好地刻画子问题空间;
  3. 证明作为构成原问题最优解的组成部分,每个子问题的解就是它本身的最优解。方法是反证法,考虑加入某个子问题的解不是其自身的最优解,那么就可以从原问题的解中用该子问题的最优解替换掉当前的非最优解,从而得到原问题的一个更优的解,从而与原问题最优解的假设矛盾。
  4. 要保持子问题空间尽量简单,只在必要时扩展。

最优子结构的不同体现在两个方面:

  1. 原问题的最优解中涉及多少个子问题;
    确定最优解使用哪些子问题时,需要考察多少种选择。
  2. 子问题图中每个定点对应一个子问题,而需要考察的选择对应关联至子问题顶点的边。
经典问题:
  • 无权最短路径: 具有最优子结构性质。
  • 无权最长(简单)路径: 此问题不具有,是 NPC 的。区别在于,要保证子问题无关,即同一个原问题的一个子问题的解不影响另一个子问题的解。相关:求解一个子问题时用到了某些资源,导致这些资源在求解其他子问题时不可用。
子问题重叠

子问题空间要足够小,即问题的递归算法会反复地求解相同的子问题,而不是一直生成新的子问题。

重构最优解

存表记录最优分割的位置,就不用重新按照代价来重构。

最长公共子序列

子序列允许不连续。

每个c[i][j]c[i][j]c[i][j] 只依赖于c[i−1][j]c[i-1][j]c[i1][j]c[i][j−1]c[i][j-1]c[i][j1]c[i−1][j−1]c[i-1][j-1]c[i1][j1]

记录最优方案的时候可以不需要额外建表(优化空间),因为重新选择一遍(转移过程)也是 O(1)O(1)O(1) 的。

最优二叉搜索树

给二叉搜索树的每个节点定义一个权值,问如何安排使得权值和深度的乘积最小。
考虑当一棵子树成为了一个节点的子树时,答案(期望搜索代价)有何变化?

由于每个节点的深度都增加了 1,这棵子树的期望搜索代价的增加值应为所有概率之和。

tD/eD 动态规划: 状态空间是 O(nt)O(n^{t})O(nt) 的,每一项依赖其他O(ne)O(n^{e})O(ne) 项。

最长连续不下降子序列

我们的目标是求出给定序列的一个最长的连续子序列,满足这个序列中的后一个元素 不小于 前一个元素。

因为是连续的,所以只要与上一个元素进行比较即可。

int a[MAXN];
int dp() {int now = 1, ans = 1;for (int i = 2; i <= n; i++) {if (a[i] >= a[i - 1])now++;elsenow = 1;ans = max(now, ans);}return ans;
}

最长不下降子序列

与最长连续不下降子序列不同的是,不需要这个子序列是连续的了。

求最长子序列的方法有两种。
最简单的第一种O(n2)O(n^{2})O(n2)的算法。每一次从头扫描找出最佳答案。

int a[MAXN], d[MAXN];
int dp() {d[1] = 1;int ans = 1;for (int i = 2; i <= n; i++) {for (int j = 1; j < i; j++)if (a[j] <= a[i]) {//判断j能否添加到该序列中d[i] = max(d[i], d[j] + 1);//是否将j添加到该序列中ans = max(ans, d[i]);}}return ans;
}

稍复杂的第二种nnn long nnn的算法, 参考了这篇文章

首先,定义 a1......ana_{1}......a_{n}a1......an为原始序列, d为当前的不下降子序列, len为子序列的长度,那么dlend_{len}dlen 就是长度为 len 的不下降子序列末尾元素。

初始化:d1=a1、len=1d_{1}=a_{1} 、len=1d1=a1len=1

现在我们已知最长的不下降子序列长度为 1,那么我们让 i 从 2 到 n循环,依次求出前 i个元素的最长不下降子序列的长度,循环的时候我们只需要维护好 这个数d组还有 len就可以了。关键在于如何维护。

考虑进来一个元素aia_{i}ai

1.元素大于等于 dlend_{len}dlen,直接d++len=aid_{++len}=a_{i}d++len=ai 即可,这个比较好理解。
元素小于dlend_{len}dlen ,找到 第一个 大于它的元素,插入进去,其他小于它的元素不要。
那么代码如下:

for (int i = 0; i < n; ++i) scanf("%d", a + i);
memset(dp, 0x1f, sizeof dp);
mx = dp[0];
for (int i = 0; i < n; ++i) {*std::upper_bound(dp, dp + n, a[i]) = a[i];
}
ans = 0;
while (dp[ans] != mx) ++ans;

经典问题(来自习题)

DAG 中的最长简单路径

dp[i]=max(dp[j]+1)((i,j)∈E)dp[i]=max(dp[j]+1)((i,j)\in E)dp[i]=max(dp[j]+1)((i,j)E)

最长回文子序列

dp[i][i+len]dp[i][i+len]dp[i][i+len]={max(dp[i+1][i+len],dp[i][i+len−1]),elsedp[i+1][i+len−1]+1,ifs[i]=s[i+len]\left \{ ^{dp[i+1][i+len-1]+1 ,if s[i]=s[i+len]}_{max(dp[i+1][i+len],dp[i][i+len-1]),else} \right.{max(dp[i+1][i+len],dp[i][i+len1]),elsedp[i+1][i+len1]+1,ifs[i]=s[i+len]
边界:dp[i][j]=1dp[i][j]=1dp[i][j]=1

注意: dp[i][j]dp[i][j]dp[i][j]表示的是闭区间。

也可以转化为 LCS 问题,只需要把a 串反转当做b ,对 a和 b求 LCS 即可。
注意区分子串(要求连续)的问题。

最长回文子串

O(n2):dp[i]=max(dp[j]+1,dp[i]),s(j+1...i)O(n^{2}):dp[i]=max(dp[j]+1,dp[i]),s(j+1...i)O(n2):dp[i]=max(dp[j]+1,dp[i]),s(j+1...i)是回文

O(n)O(n)O(n):Manacher

p[i]表示从i 向两侧延伸(当然要保证两侧对应位置相等)的最大长度。

为了处理方便,我们把原串每两个字符之间加一个(不包含在原串中的)#,开头加一个 $。

这样得到的回文串长度就保证是奇数了
考虑如果按顺序得到了p[1...i−1]p[1...i-1]p[1...i1] ,如何计算p[i] 的值?
如果之前有一个位置比如说是id ,有 p[id]+id>i那么 i 这个位置是被覆盖了的,根据id 处的对称性,我们找p[id×2−i]p[id \times 2-i]p[id×2i] 延伸的部分被p[id] 延伸的部分所覆盖的那段,显然这段对称回去之后是可以从i 处延伸出去的长度。
如果找不到呢?就先让p[id]=1 吧。
之后再暴力延伸一下.
可以证明是O(n)O(n)O(n) 的。
至于如何找是否有这么一个 id 呢?递推的时候存一个max 就好了。

当选取的状态难以进行递推时(分解出的子问题和原问题形式不一样),考虑将问题状态分类细化,增加维度。

记忆化搜索

(1)How many ways HDU - 1978(记忆化搜索关于求多少种方式模板)
(2)FatMouse and Cheese HDU - 1078(记忆化搜索入门模板)

记忆化搜索的特征:
  1. 不依赖任何 外部变量
  2. 答案以返回值的形式存在,而不能以参数的形式存在(就是不能将 dfs 定义成 dfs(pos,tleft,nowans),这里面的 nowans 不符合要求)。
  3. 对于相同一组参数,dfs 返回值总是相同的
如何写记忆化搜索

方法一

  1. 把这道题的 dp 状态和方程写出来
  2. 根据它们写出 dfs 函数
  3. 添加记忆化数组

dp[i]=max(dp[i],dp[j+1])(最长上升子序列)dp[i]=max(dp[i],dp[j+1])(最长上升子序列)dp[i]=max(dp[i],dp[j+1])()

int dfs(int i) {if (mem[i] != -1) return mem[i];int ret = 1;for (int j = 1; j < i; j++)if (a[j] < a[i]) ret = max(ret, dfs(j) + 1);return mem[i] = ret;
}
int main() {memset(mem, -1, sizeof(mem));// 读入部分略去cout << dfs(n) << endl;
}

方法 II

  1. 写出这道题的暴搜程序(最好是 dfs)
  2. 将这个 dfs 改成“无需外部变量”的 dfs
  3. 添加记忆化数组

山洞里有 M株不同的草药,采每一株都需要一些时间tit_{i}ti ,每一株也有它自身的价值viv_{i}vi 。给你一段时间 T,在这段时间里,你可以采到一些草药。让采到的草药的总价值最大。

int n, t;
int tcost[103], mget[103];
int ans = 0;
void dfs(int pos, int tleft, int tans) {if (tleft < 0) return;if (pos == n + 1) {ans = max(ans, tans);return;}dfs(pos + 1, tleft, tans);dfs(pos + 1, tleft - tcost[pos], tans + mget[pos]);
}
int main() {cin >> t >> n;for (int i = 1; i <= n; i++) cin >> tcost[i] >> mget[i];dfs(1, t, 0);cout << ans << endl;return 0;
}

记忆化搜索的优缺点

优点:
  • 记忆化搜索可以避免搜到无用状态,特别是在有状态压缩时
  • 不需要注意转移顺序(这里的“转移顺序”指正常 dp 中 for 循环的嵌套顺序以及循环变量是递增还是递减)

举例:用常规 dp 写“合并石子”需要先枚举区间长度然后枚举起点,但记忆化搜索直接枚举断点(就是枚举当前区间由哪两个区间合并而成)然后递归下去就行

  • 边界情况非常好处理,且能有效防止数组访问越界
  • 有些 dp(如区间 dp) 用记忆化搜索写很简单但正常 dp 很难
  • 记忆化搜索天生携带搜索天赋,可以使用技能“剪枝”!
缺点:
  • 致命伤:不能滚动数组!
  • 有些优化比较难加
  • 由于递归,有时效率较低但不至于 TLE(状压 dp 除外)
记忆化搜索的注意事项
  • 千万别忘了加记忆化!
  • 边界条件要加在检查当前数组值是否为非法数值(防止越界)
  • 数组不要开小了

背包 DP

0-1 背包

Jin Ge Jin Qu hao UVA - 12563 (劲歌金曲)01背包,求装入的东西最多(相同多时价值大)

意概要:有 n个物品和一个容量为 W 的背包,每个物品有重量wiw_{i}wi 和价值viv_{i}vi 两种属性,要求选若干物品放入背包使背包中物品的总价值最大且背包中物品的总重量不超过背包的容量。

在上述例题中,由于每个物体只有2 种可能的状态(取与不取),正如二进制中的 0 和 1,这类问题便被称为「0-1 背包问题」。

例题中已知条件有第 i个物品的重量 wiw_{i}wi,价值 viv_{i}vi,以及背包的总容量W 。

设 DP 状态 fi,jf_{i,j}fi,j为在只能放前 i 个物品的情况下,容量为j 的背包所能达到的最大总价值。

考虑转移。假设当前已经处理好了前 i-1个物品的所有状态,那么对于第 i个物品,当其不放入背包时,背包的剩余容量不变,背包中物品的总价值也不变,故这种情况的最大价值为fi−1,jf_{i-1,j}fi1,j ;当其放入背包时,背包的剩余容量会减小wiw_{i}wi ,背包中物品的总价值会增大viv_{i}vi ,故这种情况的最大价值为 fi−1,j−wi+vif_{i-1,j-w_{i}}+v_{i}fi1,jwi+vi
由此可以得出状态转移方程:
fi,j=max(fi−1,j,fi−1,j−wi+vi)f_{i,j}=max(f_{i-1,j},f_{i-1,j-w_{i}}+v_{i})fi,j=max(fi1,j,fi1,jwi+vi)
这里如果直接采用二维数组对状态进行记录,会出现 MLE。可以考虑改用滚动数组的形式来优化。

由于对 fif_{i}fi有影响的只有 fi−1f_{i-1}fi1,可以去掉第一维,直接用 fif_{i}fi 来表示处理到当前物品时背包容量为 的最大价值,得出以下方程:fj=max(fj,fj−wi+vi)f_{j}=max(f_{j},f_{j-w_{i}}+v_{i})fj=max(fj,fjwi+vi)
如果第二层循环正着遍历,对于当前处理的物品 i 和当前状态fi,jf_{i,j}fi,j ,在 j≥wij\geq w_{i}jwi时, fi,jf_{i,j}fi,j是会被fi,j−w−if_{i,j-w-{i}}fi,jwi 所影响的。这就相当于物品i 可以多次被放入背包,与题意不符。(事实上,这正是完全背包问题的解法)

为了避免这种情况发生,我们可以改变枚举的顺序,从W 枚举到wiw_{i}wi ,这样就不会出现上述的错误,因为fi,jf_{i,j}fi,j 总是在fi,j−wif_{i,j-w_{i}}fi,jwi 前被更新。

核心代码:
for (int i = 1; i <= n; i++)for (int l = W; l >= w[i]; l--) f[l] = max(f[l], f[l - w[i]] + v[i])

完全背包

完全背包模型与 0-1 背包类似,与 0-1 背包的区别仅在于一个物品可以选取无限次,而非仅能选取一次。
Piggy-Bank POJ - 1384(完全背包+背包放满)

二维费用背包

这道题是很明显的 0-1 背包问题,可是不同的是选一个物品会消耗两种价值(经费、时间)。这种问题其实很简单:方程基本不用变,只需再开一维数组,同时转移两个价值就行了!(完全、多重背包同理)
这时候就要注意,再开一维存放物品编号就不合适了,因为容易 MLE。

for (int k = 1; k <= n; k++) {for (int i = m; i >= mi; i--)    // 对经费进行一层枚举for (int j = t; j >= ti; j--)  // 对时间进行一层枚举dp[i][j] = max(dp[i][j], dp[i - mi][j - ti] + 1);
}

分组背包

所谓分组背包,就是将物品分组,每组的物品相互冲突,最多只能选一个物品放进去。
这种题怎么想呢?其实是从「在所有物品中选择一件」变成了「从当前组中选择一件」,于是就对每一组进行一次 0-1 背包就可以了。
再说一说如何进行存储。我们可以将tk,it_{k,i}tk,i 表示第 k组的第i 件物品的编号是多少,再用 cntkcnt_{k}cntk 表示第k 组物品有多少个。

for (int k = 1; k <= ts; k++)          // 循环每一组for (int i = m; i >= 0; i--)         // 循环背包容量for (int j = 1; j <= cnt[k]; j++)  // 循环该组的每一个物品if (i >= w[t[k][j]])dp[i] = max(dp[i],dp[i - w[t[k][j]]] + c[t[k][j]]);  // 像0-1背包一样状态转移

输出方案

输出方案其实就是记录下来背包中的某一个状态是怎么推出来的。我们可以用gi,vg_{i,v}gi,v 表示第 i 件物品占用空间为 v的时候是否选择了此物品。然后在转移时记录是选用了哪一种策略(选或不选)。输出时的伪代码:

int v = V;  // 记录当前的存储空间
for (从最后一件循环至第一件)  // 因为最后一件物品存储的是最终状态,所以从最后一件物品进行循环
{if (g[i][v]) {选了第 i 项物品;v -= 第 i 项物品的价值;} else未选第 i 项物品;
}

求方案数

对于给定的一个背包容量、物品费用、其他关系等的问题,求装到一定容量的方案总数。
这种问题就是把求最大值换成求和即可。
例如 0-1 背包问题的转移方程就变成了:
dpi=Σ(dpi,dpi−ci)dp_{i}=\Sigma(dp_{i},dp_{i-c_{i}})dpi=Σ(dpi,dpici)
初始条件:dp0=1dp_{0}=1dp0=1
因为当容量为 0 时也有一个方案:什么都不装!

求最优方案总数

for (int i = 0; i < N; i++) {for (int j = V; j >= v[i]; j--) {int tmp = max(dp[j], dp[j - v[i]] + w[i]);int c = 0;if (tmp == dp[j]) c += cnt[j];                       // 如果从dp[j]转移if (tmp == dp[j - v[i]] + w[i]) c += cnt[j - v[i]];  // 如果从dp[j-v[i]]转移dp[j] = tmp;cnt[j] = c;}
}
int max = 0;  // 寻找最优解
for (int i = 0; i <= V; i++) {max = max(max, dp[i]);
}
int res = 0;
for (int i = 0; i <= V; i++) {if (dp[i] == max) {res += cnt[i];  // 求和最优解方案数}
}

区间 DP

Click Here

DAG 上的 DP

树形 DP

Click Here

状压 DP

Click Here

数位 DP

(1)Round Numbers POJ - 3252(数位dp+判断前导零)
(2)数位dp总结 之 从入门到模板(stO)

插头 DP

计数 DP

Sumsets POJ - 2229(计数dp)

动态 DP

概率 DP

Click Here

DP 优化

单调队列/单调栈优化

斜率优化

四边形不等式优化

状态设计优化

其它 DP 方法

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

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

相关文章

Azure 国际版与中国版服务列表对(2020年6月版)

点击上方关注“汪宇杰博客” ^_^对于选择Azure平台的用户来说&#xff0c;会面临选择国内还是国际版的问题。由于一些原因&#xff0c;由世纪互联运营的中国大陆版Azure无法落地所有的国际版服务。相比几年前&#xff0c;情况已经有了一定的改善。本文列出了国际版和国内版Azur…

[JavaWeb-JavaScript]JavaScript流程控制语句

流程控制语句&#xff1a; 1. if...else...2. switch:* 在java中&#xff0c;switch语句可以接受的数据类型&#xff1a; byte int shor char,枚举(1.5) ,String(1.7)* switch(变量):case 值:* 在JS中,switch语句可以接受任意的原始数据类型3. while4. do...while5. for

解读三组容易混淆的Dockerfile指令

长话短说&#xff0c;今天分享三组容易混淆的Dockerfile指令&#xff0c; 帮助大家编写更优雅的Dockfile文件、构建更纯净的Docker镜像。COPY vs ADDCOPY、ADD主体功能类似&#xff1a;从指定位置src拷贝文件到Docker镜像dest。COPY <src>... <dest> ADD <src&…

[JavaWeb-HTML]HTML概念介绍和快速入门

HTML 1. 概念&#xff1a;是最基础的网页开发语言* Hyper Text Markup Language 超文本标记语言* 超文本:* 超文本是用超链接的方法&#xff0c;将各种不同空间的文字信息组织在一起的网状文本.* 标记语言:* 由标签构成的语言。<标签名称> 如 html&#xff0c;xml* 标记…

ASP.NET Core使用Nacos SDK访问阿里云ACM

背景 前段时间&#xff0c;cranelee 在Github上给老黄提了个issues&#xff0c; 问到了如何用Nacos的SDK访问阿里云ACM。https://github.com/catcherwong/nacos-sdk-csharp/issues/13刚看到这个issues的时候&#xff0c;老黄也是觉得一脸懵逼&#xff0c;好像这两者没有什么必然…

[JavaWeb-JavaScript]JavaScript_Function函数(方法)对象

Function&#xff1a;函数(方法)对象 1. 创建&#xff1a;1. var fun new Function(形式参数列表,方法体); //忘掉吧2. function 方法名称(形式参数列表){方法体}3. var 方法名 function(形式参数列表){方法体}2. 方法&#xff1a;3. 属性&#xff1a;length:代表形参的个数…

java基础输入输出语句

输入语句 方法一&#xff1a; System.in和System.out方法 缺点一: 该方法能获取从键盘输入的字符&#xff0c;但只能针对一个字符的获取缺点二: 获取的只是char类型的。如果想获得int,float等类型的输入,比较麻烦。 import java.io.IOException; public class test {public…

为.netcore助力--WebApiClient正式发布core版本

1、前言NCC WebApiClient 已成熟稳定&#xff0c;发布了WebApiClient.JIT 和 WebApiClient.AOT 两个 NuGet 包&#xff0c;累计近 10w 次下载。我对它的高可扩展性设计相当满意和自豪&#xff0c;但 WebApiClient 并不因此而停下脚步&#xff0c;在一年前&#xff0c;我产生了编…

[JavaWeb-JavaScript]JavaScript_Data日期对象

Date&#xff1a;日期对象 1. 创建&#xff1a;var date new Date();2. 方法&#xff1a;toLocaleString()&#xff1a;返回当前date对象对应的时间本地字符串格式getTime():获取毫秒值。返回当前如期对象描述的时间到1970年1月1日零点的毫秒值差示例代码如下: <!DOCTYPE …

括号匹配+Java栈

括号匹配 import java.util.LinkedList;class MyStack{private int num;private LinkedList<Character>date;public MyStack(){this.num0;datenew LinkedList<Character>();}public boolean isEmpty(){return num0?true:false;}public void push(Character ch){t…

一个static和面试官扯了一个小时,舌战加强版

一&#xff1a;背景1. 讲故事最近也是奇怪&#xff0c;在社区里看到好几篇文章聊static 的玩法以及怎么拿这个和面试官扯半个小时&#xff0c;有点意思&#xff0c;点进去看都是java版的&#xff0c;这就没意思了&#xff0c;怎么也得有一篇和面试官扯C# 中的 static用法撒&…

[JavaWeb-JavaScript]JavaScript_Math数学对象

Math&#xff1a;数学对象 1. 创建&#xff1a;* 特点&#xff1a;Math对象不用创建&#xff0c;直接使用。 Math.方法名();2. 方法&#xff1a;random():返回 0 ~ 1 之间的随机数。 含0不含1ceil(x)&#xff1a;对数进行上舍入。floor(x)&#xff1a;对数进行下舍入。round(x…

数据结构整理中。。。

目录栈队列链表单向链表双向链表向链表中插入&#xff08;写入&#xff09;数据单向链表单向循环链表双向循环链表从链表中删除数据单向&#xff08;循环&#xff09;链表双向循环链表哈希表哈希函数冲突拉链法闭散列法并查集启发式合并&#xff08;按秩合并&#xff09;带权并…

.NET开发者省份分布排名

什么叫.NET开发者省份分布排名呢&#xff1f; 顾名思义&#xff0c;这几个词大家都认识&#xff0c;.NET开发者都集中在城市&#xff0c;涵盖一线城市到五线城市。排名的方法非常简单粗暴&#xff0c;就是根据本公众号&#xff08;dotnet跨平台&#xff09;的省份订阅读者数量排…

[JavaWeb-JavaScript]JavaScript_RegExp正则表达式对象

RegExp&#xff1a;正则表达式对象 1. 正则表达式&#xff1a;定义字符串的组成规则。1. 单个字符:[]如&#xff1a; [a] [ab] [a-zA-Z0-9_]* 特殊符号代表特殊含义的单个字符:\d:单个数字字符 [0-9]\w:单个单词字符[a-zA-Z0-9_]2. 量词符号&#xff1a;?&#xff1a;表示出现…

创建型模式——单例模式

一、 实验目的与要求 1.练习使用单例模式。设计相关的模拟场景并进行实施&#xff0c;验证模式特性&#xff0c;掌握其优缺点。 2.实验结束后&#xff0c;对相关内容进行总结。 二、实验内容 1.模式应用场景说明 在山区或者边远地区火车站往往只有一个窗口在买票&#xff0c;但…

Sql Server之旅——终点站 nolock引发的三级事件的一些思考

曾今有件事情让我记忆犹新&#xff0c;那年刚来携程不久&#xff0c;马上就被安排写一个接口&#xff0c;供企鹅公司调用他们员工的差旅信息&#xff0c;然后我就三下五除二的给写好了&#xff0c;上线之后&#xff0c;大概过了一个月。。。DBA那边报告数据库出现大量锁超时&am…

[JavaWeb-JavaScript]JavaScript_Global全局对象

Global 1. 特点&#xff1a;全局对象&#xff0c;这个Global中封装的方法不需要对象就可以直接调用。 方法名();2. 方法&#xff1a;encodeURI():url编码decodeURI():url解码encodeURIComponent():url编码,编码的字符更多decodeURIComponent():url解码parseInt():将字符串转为…

创建型模式——原型模式

一、 实验目的与要求 1.练习使用单一模式。设计相关的模拟场景并进行实施&#xff0c;验证模式特性&#xff0c;掌握其优缺点。 2.实验结束后&#xff0c;对相关内容进行总结。 二、实验内容 1.模式应用场景说明 原型模式&#xff1a;在需要一个类的大量对象的时候&#xff0c;…

现在就是.Net最好的时代!我赞成,谁反对?

2020年.NET Core逆袭冲榜&#xff0c;多榜直接冠军&#xff01;Build2020&#xff0c;发布多款产品赋能.NET开发者&#xff01;截止5月&#xff0c;腾讯&#xff0c;阿里&#xff0c;特斯拉等大厂都在招聘.NET&#xff01;这些征兆&#xff0c;都预示着.NET的春天即将到来&…