Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前缀和技巧c++版本 #306

Merged
merged 5 commits into from
Jun 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 43 additions & 1 deletion 动态规划系列/最长公共子序列.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,51 @@ else:

![labuladong](../pictures/labuladong.jpg)

[labuladong](https://github.com/labuladong) 提供Python解法代码:

```python
def longestCommonSubsequence(str1, str2) -> int:
m, n = len(str1), len(str2)
# 构建 DP table 和 base case
dp = [[0] * (n + 1) for _ in range(m + 1)]
# 进行状态转移
for i in range(1, m + 1):
for j in range(1, n + 1):
if str1[i - 1] == str2[j - 1]:
# 找到一个 lcs 中的字符
dp[i][j] = 1 + dp[i-1][j-1]
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])

return dp[-1][-1]
```

[Jinglun Zhou](https://github.com/Jasper-Joe) 提供C++解法代码:

```CPP
class Solution {
public:
int longestCommonSubsequence(string str1, string str2) {
int m=str1.size(), n=str2.size();
// 构建DP table 和 base case
vector<vector<int>> dp(m+1,vector<int>(n+1));
// dp[i][j]表示: 字符串str1[0:i]和字符串str2[0:j]的最大公共子序列
// 进行状态转移
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if(str1[i-1]==str2[j-1]) // 两个字符相等,必然可以构成子问题的最优解
// 找到一个lcs中的字符
dp[i][j]=1+dp[i-1][j-1];
else //如果两个字符不相等,我们往前看一个字符
//寄希望于str1[i-2]和str2[j-1]相等,或者str1[i-1]和str2[j-2]
//如果他们两个当中有任何一个可以匹配, 我们就有机会更新当前dp值
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
return dp[m][n]; // 根据dp的定义,答案就存储在dp[m][n]中
}
};
```
[上一篇:动态规划之正则表达](../动态规划系列/动态规划之正则表达.md)

[下一篇:学习算法和刷题的思路指南](../算法思维系列/学习数据结构和算法的高效方法.md)

[目录](../README.md#目录)
[目录](../README.md#目录)
62 changes: 61 additions & 1 deletion 动态规划系列/编辑距离.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,68 @@ class Node {

![labuladong](../pictures/labuladong.png)

[labuladong](https://github.com/labuladong) 提供Java解法代码:

```JAVA
int minDistance(String s1, String s2) {
int m = s1.length(), n = s2.length();
int[][] dp = new int[m + 1][n + 1];
// base case
for (int i = 1; i <= m; i++)
dp[i][0] = i;
for (int j = 1; j <= n; j++)
dp[0][j] = j;
// 自底向上求解
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
if (s1.charAt(i-1) == s2.charAt(j-1))
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] = min(
dp[i - 1][j] + 1,
dp[i][j - 1] + 1,
dp[i-1][j-1] + 1
);
// 储存着整个 s1 和 s2 的最小编辑距离
return dp[m][n];
}

int min(int a, int b, int c) {
return Math.min(a, Math.min(b, c));
}
```

[Jinglun Zhou](https://github.com/Jasper-Joe) 提供C++解法代码:

```CPP

class Solution {
public:
int minDistance(string s1, string s2) {
int m=s1.size(), n=s2.size();
vector<vector<int>> dp(m+1,vector<int>(n+1));
for(int i=1;i<=m;i++)
dp[i][0]=i; // base case: 当s2为空,s1需要删除所有字符才能与s2相等
for(int j=1;j<=n;j++)
dp[0][j]=j; // base case: 当s1为空, s1需要不断插入新字符才能与s2相等
//自底向上求解
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if(s1[i-1]==s2[j-1]) // 两个字符串当前的字符一样
dp[i][j]=dp[i-1][j-1];
else // 两个字符串当前的字符不同
//使得s1[0:i]和s2[0:j]相同的最短编辑距离可通过插入,删除或替换三种操作其中一种得到
dp[i][j]=min({
dp[i-1][j]+1, // 删除s1[i]这个字符
dp[i][j-1]+1, // 在s1[i]后面加一个和s2[j]相同的字符
dp[i-1][j-1]+1}); // 将s1[i]的字符替换为s2[j]的字符
//储存着整个 s1 和 s2 的最小编辑距离
return dp[m][n];
}
};
```
[上一篇:动态规划设计:最长递增子序列](../动态规划系列/动态规划设计:最长递增子序列.md)

[下一篇:经典动态规划问题:高楼扔鸡蛋](../动态规划系列/高楼扔鸡蛋问题.md)

[目录](../README.md#目录)
[目录](../README.md#目录)
55 changes: 54 additions & 1 deletion 算法思维系列/前缀和技巧.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,62 @@ for (int i = 1; i < count.length; i++)

![labuladong](../pictures/labuladong.jpg)

[labuladong](https://github.com/labuladong) 提供JAVA解法代码:

```
int subarraySum(int[] nums, int k) {
int n = nums.length;
// map:前缀和 -> 该前缀和出现的次数
HashMap<Integer, Integer>
preSum = new HashMap<>();
// base case
preSum.put(0, 1);

int ans = 0, sum0_i = 0;
for (int i = 0; i < n; i++) {
sum0_i += nums[i];
// 这是我们想找的前缀和 nums[0..j]
int sum0_j = sum0_i - k;
// 如果前面有这个前缀和,则直接更新答案
if (preSum.containsKey(sum0_j))
ans += preSum.get(sum0_j);
// 把前缀和 nums[0..i] 加入并记录出现次数
preSum.put(sum0_i,
preSum.getOrDefault(sum0_i, 0) + 1);
}
return ans;
}
```

[Jinglun Zhou](https://github.com/Jasper-Joe) 提供C++解法代码:

```CPP
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int n=nums.size();
unordered_map<int,int> preSum;
// map: 前缀和 -> 该前缀和出现的次数
preSum[0]=1; // base case: 例如当数组中只有一个元素, 而k恰好等于这个元素
int ans=0, sum0_i=0; // sum0_i 表示前缀和 nums[0...i]
for(int i=0;i<n;i++)
{
sum0_i +=nums[i];
// 这是我们想找的前缀和 nums[0...j]
int sum0_j=sum0_i-k;
// 如果前面有这个前缀和,则直接更新答案
if(preSum.count(sum0_j))
ans+=preSum[sum0_j];
//把前缀和 nums[0...i] 加入并记录出现次数
preSum[sum0_i]++; // 把当前的前缀和加入到map中
}
return ans;
}
};
```

[上一篇:烧饼排序](../算法思维系列/烧饼排序.md)

[下一篇:字符串乘法](../算法思维系列/字符串乘法.md)

[目录](../README.md#目录)
[目录](../README.md#目录)