持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情
48. 旋转图像
思路
(操作分解) O(n^2)
我们对观察样例,找规律发现:先以左上-右下对角条线为轴做翻转,再以中心的竖线为轴做翻转,就可以顺时针翻转90度。
因此可以得出一个结论,顺时针90度应该是左上/右下对角线翻转+左右翻转,或者右上/左下对角线翻转+上下翻转。
过程如下:
- 先以左上-右下对角条线为轴做翻转;
- 再以中心的竖线为轴做翻转;
时间复杂度分析:O(n^2), 额外空间:O(1) 。
c++代码
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for(int i = 0; i < n; i++)
for(int j = 0; j < i; 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]);
}
};
49. 字母异位词分组
思路
(哈希 + 排序) O(NLlogL)
定义从string 映射到vector<string>的哈希表:unordered_map<string, vector<string>>。然后将每个字符串的所有字符从小到大排序,将排好序的字符串作为key,然后将原字符串插入key对应的vector<string>中。
具体过程如下:
-
1、定义一个
string映射到vector<string>的哈希表。 -
2、遍历
strs字符串数组,对于每个字符串str:- 将
str排序,作为哈希表的key值; - 将原
str放入对应key值位置处;
- 将
-
3、最后遍历整个哈希表,将对应的
vector<string>存入res中。
时间复杂度分析: 对于每个字符串,哈希表和vector的插入操作复杂度都是 O(1),排序复杂度是 O(LlogL)。所以总时间复杂度是 O(NLlogL)。
c++代码
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> hash; //哈希表
for(string str : strs){
string nstr = str;
sort(nstr.begin(), nstr.end()); //排序 将其作为key值
hash[nstr].push_back(str);
}
vector<vector<string>> res;
for(auto item : hash){
res.push_back(item.second);
}
return res;
}
};
53. 最大子数组和
思路
(动态规划) O(n)
状态表示: f[i]表示以nums[i]为结尾的最大连续子数组和。
状态计算:
如何确定f[i]的值? 以nums[i]为结尾的连续子数组共分为两种情况:
- 只有
nums[i]一个数,则f[i] = nums[i]; - 以
nums[i]为结尾的多个数,则f[i] = f[i - 1] + nums[i]。
两种情况取最大值,因此状态转移方程为: f[i] = max(f[i - 1] + nums[i], nums[i])。
初始化:
f[0] = nums[0]。
最后遍历每个位置的f[i],然后其中的最大值即可。
时间复杂度分析: 只遍历一次数组,O(n)。
c++代码
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
vector<int> f(n + 1, 0);
int res = nums[0];
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;
}
};