? 作者主页:欢迎来到我的技术博客😎
? 个人介绍:大家好,本人热衷于Java后端开发,欢迎来交流学习哦!( ̄▽ ̄)~*
🍊 如果文章对您有帮助,记得关注、点赞、收藏、评论??????
📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉
算法流程:
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
vector<bool> st;
vector<vector<int>> permute(vector<int>& nums) {
path = vector<int>(nums.size());
st = vector<bool>(nums.size());
dfs(nums, 0);
return ans;
}
void dfs(vector<int>& nums, int u) {
if (u == nums.size()) {
ans.push_back(path);
return;
}
for (int i = 0; i < nums.size(); i ++) {
if (!st[i]) {
path[u] = nums[i];
st[i] = true;
dfs(nums, u + 1);
st[i] = false;
}
}
}
};
(操作分解) O(
n
2
n^2
n2)
直接操作旋转
9
0
o
90^o
90o比较困难,我们可以将它分解成两个操作:
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for (int i = 0; i < n; i ++)
for (int j = i + 1; j < n; j ++)
swap(matrix[i][j], matrix[j][i]);
for (int i = 0; i < n; i ++)
for (int j = 0, k = n - 1; j < k; j ++, k --)
swap(matrix[i][j], matrix[i][k]);
}
};
由于互为字母异位词的两个字符串包含的字母相同,因此对两个字符串分别进行排序之后得到的字符串一定是相同的,故可以将排序之后的字符串作为哈希表的键。
定义从 string
映射到vector<string>
的哈希表: unordered_map<string, vector<string>>
。
我们将每个字符串的所有字符从小到大排序,将排好序的字符串作为key
,然后将原字符串插入key
对应的vector<string>>
中
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> hash;
for (auto& str : strs) {
string nstr = str;
sort(nstr.begin(), nstr.end());
hash[nstr].push_back(str);
}
vector<vector<string>> res;
for (auto& item : hash) res.push_back(item.second);
return res;
}
};
动态规划 O ( n ) O(n) O(n)
f(i)f(i)
表示以第
i
i
i 个数字为结尾的最大连续子序列的 总和 是多少。f(0)=nums[0]
。f(i)=max(f(i?1)+nums[i],nums[i])
。可以理解为当前有两种决策,一种是将第
i
i
i 个数字和前边的数字拼接起来;另一种是第
i
i
i 个数字单独作为一个新的子序列的开始。class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size(), res = nums[0];
vector<int> f(n);
f[0] = nums[0];
for (int i = 1; i < n; i ++) {
f[i] = max(f[i - 1] + nums[i], nums[i]);
res = max(res, f[i]);
}
return res;
}
};
核心思想:尽可能跳到更远的位置。
class Solution {
public:
bool canJump(vector<int>& nums) {
int last = 0;
for (int i = 0; i <nums.size(); i ++) {
if (last < i) return false;
last = max(last, i + nums[i]);
}
return true;
}
};
贪心思想:
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& a) {
vector<vector<int>> res;
if (a.empty()) return res;
sort(a.begin(), a.end());
int l = a[0][0], r = a[0][1];
for (int i = 1; i < a.size(); i ++) {
if (a[i][0] > r) {
res.push_back({l, r});
l = a[i][0], r = a[i][1];
} else r = max(r, a[i][1]);
}
res.push_back({l, r});
return res;
}
};
动态规划
f[i][j]
表示从起点到
(
i
,
j
)
(i,j)
(i,j) 的路径总和;f[i][j] = f[i - 1][j] + f[i][j - 1]
;f[0][j]
或者第一列 f[j][0]
,由于都是在边界,所有只能为1。class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> f(m, vector<int>(n));
for (int i = 0; i < m; i ++)
for (int j = 0; j < n; j ++) {
if (!i || !j) f[i][j] = 1; //f[i][0] 和 f[0][j]单独初始化为1
else f[i][j] = f[i - 1][j] + f[i][j - 1];
}
return f[m - 1][n - 1];
}
};
状态表示: f[i][j]
表示从起点到
(
i
,
j
)
(i,j)
(i,j) 的最小路径和。
很显然,f[0][0] = grid[0][0]
,对于
f
f
f 中的其余元素值,通过以下状态转移方程计算元素值:
f[i][0] = f[i - 1][0] + grid[i][0]
;f[0][j] = f[0][j - 1] + grid[0][j]
;f[i][j] = min(f[i - 1][j], f[i][j - 1] + grid[i][j]
;class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int n = grid.size(), m = grid[0].size();
vector<vector<int>> f(n, vector<int>(m));
f[0][0] = grid[0][0]; //起点
//第一行,只能从左边来
for (int i = 1; i < n; i ++) {
f[i][0] = f[i - 1][0] + grid[i][0];
}
//第一列,只能从上面来
for (int j = 1; j < m; j ++) {
f[0][j] = f[0][j - 1] + grid[0][j];
}
//其他的则可以从左边或者上面来
for (int i = 1; i < n; i ++)
for (int j = 1; j < m; j ++) {
f[i][j] = min(f[i - 1][j], f[i][j - 1]) + grid[i][j];
}
return f[n - 1][m - 1];
}
};
定义数组
f
[
i
]
f[i]
f[i] 表示上
i
i
i 级台阶的方案数,则枚举最后一步是上1级台阶,还是上2级台阶,所以有:f[i] = f[i ? 1] + f[i ? 2]
。
class Solution {
public:
int climbStairs(int n) {
vector<int> f(n + 1);
f[0] = 1;
f[1] = 1;
for (int i = 2; i <= n; i ++)
f[i] = f[i - 1] + f[i - 2];
return f[n];
}
};
动态规划
状态表示: f[i][j]
表示
w
o
r
d
1
word1
word1 到
i
i
i 位置转化成
w
o
r
d
2
word2
word2 到
j
j
j 位置需要的最小步数。
状态转移方程:
word1[i] == word2[j]
,f[i][j] = f[i - 1][j - 1]
;word1[i] != word2[j]
,[i][j] = min(f[i - 1][j - 1] + 1, min(f[i][j - 1] + 1, f[i - 1][j] + 1))
;其中,f[i - 1][j - 1]
表示替换操作, f[i - 1][j]
表示删除操作,f[i][j - 1]
表示插入操作。
注意:针对第一行和第一列到单独考虑,我们引入 ''
如下图所示:
class Solution {
public:
int minDistance(string a, string b) {
int n = a.size(), m = b.size();
a = ' ' + a, b = ' ' + b;
vector<vector<int>> f(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; i ++) f[i][0] = i;
for (int j = 1; j <= m; j ++) f[0][j] = j;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++) {
if (a[i] == b[j])
f[i][j] = f[i - 1][j - 1];
else
f[i][j] = min(f[i - 1][j - 1] + 1, min(f[i][j - 1] + 1, f[i - 1][j] + 1));
}
return f[n][m];
}
};
?
非常感谢您阅读到这里,如果这篇文章对您有帮助,希望能留下您的点赞👍 关注💖 分享👥 留言💬thanks!!!