dodola · blog

LeetCode Hot 100记录(19/100)

3,606 words 12 min read #算法#LeetCode#刷题记录 算法 LeetCode Hot 100 1/1

哈希(3/3)

1. 两数之和

题意

给定一个整数数组  nums  和一个整数目标值  target,请你在该数组中找出  和为目标值 target  的那  两个  整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。

你可以按任意顺序返回答案。

代码

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> mp;
int n = nums.size();
for (int i = 0; i < n; i++) {
if (mp.count(target - nums[i])) {
return {mp[target - nums[i]], i};
}
mp[nums[i]] = i;
}
return {};
}
};

49. 字母异位词分组

题意

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

代码

class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> mp;
for (auto& s : strs) {
string t = s;
sort(t.begin(), t.end());
mp[t].push_back(s);
}
vector<vector<string>> v;
for (auto& i : mp) {
v.push_back(move(i.second));
}
return v;
}
};

128. 最长连续序列

题意

给定一个未排序的整数数组  nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为  O(n)  的算法解决此问题。

代码

class Solution {
public:
int longestConsecutive(vector<int>& nums) {
if (nums.empty())
return 0;
if (nums.size() == 1)
return 1;
sort(nums.begin(), nums.end());
int ans = 1, mx = 1;
int n = nums.size();
for (int i = 1; i < n; i++) {
if (nums[i] == nums[i - 1])
continue;
if (nums[i] == nums[i - 1] + 1) {
mx++;
} else {
mx = 1;
}
ans = max(mx, ans);
}
return ans;
}
};

双指针(4/4)

283. 移动零

题意

给定一个数组  nums,编写一个函数将所有  0  移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

代码

class Solution {
public:
void moveZeroes(vector<int>& nums) {
int pre = 0, cur = 0;
while (cur < nums.size()) {
if (nums[cur]) {
if (pre != cur)
swap(nums[pre], nums[cur]);
pre++;
}
cur++;
}
}
};

11. 盛最多水的容器

题意

给定一个长度为  n  的整数数组  height 。有  n  条垂线,第  i  条线的两个端点是  (i, 0)  和  (i, height[i]) 。

找出其中的两条线,使得它们与  x  轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明: 你不能倾斜容器。

代码

class Solution {
public:
int maxArea(vector<int>& height) {
int l = 0, r = height.size() - 1;
int cur = (r - l) * min(height[l], height[r]);
int ans = cur;
while (l < r) {
ans = max(ans, cur);
if (height[l] < height[r]) {
l++;
} else {
r--;
}
cur = (r - l) * min(height[l], height[r]);
}
return ans;
}
};

15. 三数之和

题意

给你一个整数数组  nums ,判断是否存在三元组  [nums[i], nums[j], nums[k]]  满足  i != ji != k  且  j != k ,同时还满足  nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为  0  且不重复的三元组。

注意: 答案中不可以包含重复的三元组。

代码

class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> res;
int i = 0;
while (i + 2 < n) {
if (nums[i] > 0) {
break;
}
if (i > 0 && nums[i] == nums[i - 1]) {
i++;
continue;
}
int l = i + 1, r = n - 1;
while (l < r) {
if (nums[i] + nums[l] + nums[r] < 0) {
l++;
} else if (nums[i] + nums[l] + nums[r] > 0) {
r--;
} else {
res.push_back({nums[i], nums[l], nums[r]});
while (l < r && nums[l] == nums[l + 1]) {
l++;
}
while (l < r && nums[r] == nums[r - 1]) {
r--;
}
l++, r--;
}
}
i++;
}
return res;
}
};

42. 接雨水

题意

给定  n  个非负整数表示每个宽度为  1  的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

代码

class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
int lmx = 0, rmx = 0, mx = 0;
int ans = 0;
int l = 0, r = n - 1;
while (l < r) {
lmx = max(lmx, height[l]);
rmx = max(rmx, height[r]);
if (height[l] < height[r]) { // 低的存水上限已经定了
ans += lmx - height[l];
l++;
} else {
ans += rmx - height[r];
r--;
}
}
return ans;
}
};

滑动窗口(2/2)

3. 无重复字符的最长子串

题意

给定一个字符串  s ,请你找出其中不含有重复字符的  最长子串  的长度。

代码

class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n = s.size();
if (!n) {
return 0;
}
unordered_map<char, int> cnt;
int l = 0, r = 1;
int ans = 1;
cnt[s[0]]++;
while (r < n) {
while (r < n && cnt[s[r]] == 0) {
cnt[s[r]]++;
r++;
}
ans = max(r - l, ans);
while (l < r && cnt[s[r]] != 0) {
cnt[s[l]]--;
l++;
}
if (r < n) {
cnt[s[r]]++;
r++;
}
}
return ans;
}
};

438. 找到字符串中所有字母异位词

题意

给定两个字符串  s  和  p,找到  s  中所有  p  的  异位词  的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

代码

class Solution {
public:
vector<int> findAnagrams(string s, string p) {
if (s.size() < p.size() || s.empty() || p.empty()) {
return {};
}
vector<int> ts(26, 0), tp(26, 0);
int n = s.size(), m = p.size();
for (int i = 0; i < m; i++) {
ts[s[i] - 'a']++, tp[p[i] - 'a']++;
}
int mc = 0;
for (int i = 0; i < 26; i++) {
mc += tp[i] == ts[i];
}
int l = 0, r = m;
vector<int> pos;
while (r <= n) {
if (mc == 26) {
pos.push_back(l);
}
if (r == n)
break;
mc -= tp[s[l] - 'a'] == ts[s[l] - 'a'];
mc -= tp[s[r] - 'a'] == ts[s[r] - 'a'];
ts[s[l] - 'a']--, ts[s[r] - 'a']++;
mc += tp[s[l] - 'a'] == ts[s[l] - 'a'];
mc += tp[s[r] - 'a'] == ts[s[r] - 'a'];
l++, r++;
}
return pos;
}
};

子串(3/3)

560. 和为 K 的子数组

题意

给你一个整数数组  nums  和一个整数  k ,请你统计并返回  该数组中和为  k  的子数组的个数 。

子数组是数组中元素的连续非空序列。

代码

class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int n = nums.size();
vector<int> pre(n + 1, 0);
unordered_map<int, int> mp;
int ans = 0;
mp[0] = 1;
for (int i = 0; i < n; i++) {
pre[i + 1] = pre[i] + nums[i];
ans += mp[pre[i + 1] - k];
mp[pre[i + 1]]++;
}
return ans;
}
};

239. 滑动窗口最大值

题意

给你一个整数数组  nums,有一个大小为  k  的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的  k  个数字。滑动窗口每次只向右移动一位。

返回  滑动窗口中的最大值 。

代码

vector<int> maxSlidingWindow(vector<int> &nums, int k) {
deque<int> q;
int n = nums.size();
for (int i = 0; i < k; i++) {
while (!q.empty() && nums[q.back()] < nums[i]) {
q.pop_back();
}
q.push_back(i);
}
vector<int> ans = {nums[q.front()]};
for (int i = k; i < n; i++) {
while (!q.empty() && q.front() <= i - k) {
q.pop_front();
}
while (!q.empty() && nums[q.back()] < nums[i]) {
q.pop_back();
}
q.push_back(i);
ans.push_back(nums[q.front()]);
}
return ans;
}

76. 最小覆盖子串

题意

给你一个字符串  s 、一个字符串  t 。返回  s  中涵盖  t  所有字符的最小子串。如果  s  中不存在涵盖  t  所有字符的子串,则返回空字符串  "" 。

代码

class Solution {
public:
string minWindow(string s, string t) {
int n = s.size(), m = t.size();
if (n < m) {
return "";
}
vector<int> mc(128, 0), cur(128, 0);
for (int i = 0; i < m; i++) {
mc[t[i]]++, cur[s[i]]++;
}
int tot = 0;
for (char c = 'A'; c <= 'Z'; c++) {
if (mc[c] <= cur[c]) {
tot++;
}
}
for (char c = 'a'; c <= 'z'; c++) {
if (mc[c] <= cur[c]) {
tot++;
}
}
int L = 0, R = 0;
string ans = "";
int l = 0, r = m;
if (tot == 52) {
if (R == 0 || r - l < R - L) {
L = l, R = r;
}
}
while (r < n) {
while (tot != 52 && r < n) {
tot -= cur[s[r]] >= mc[s[r]];
cur[s[r]]++;
tot += cur[s[r]] >= mc[s[r]];
r++;
}
while (l < r && mc[s[l]] < cur[s[l]]) {
tot -= cur[s[l]] >= mc[s[l]];
cur[s[l]]--;
tot += cur[s[l]] >= mc[s[l]];
l++;
}
if (tot == 52) {
if (R == 0 || r - l < R - L) {
L = l, R = r;
}
}
tot -= cur[s[l]] >= mc[s[l]];
cur[s[l]]--;
tot += cur[s[l]] >= mc[s[l]];
l++;
while (l < r && mc[s[l]] == 0) {
tot -= cur[s[l]] >= mc[s[l]];
cur[s[l]]--;
tot += cur[s[l]] >= mc[s[l]];
l++;
}
}
return s.substr(L, R - L);
}
};

普通数组(5/5)

53. 最大子数组和

题意

给你一个整数数组  nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

代码

class Solution {
public:
int maxSubArray(vector<int>& nums) {
int pre = 0;
int mx = nums.front();
for (int i : nums) {
pre = max(pre + i, i);
mx = max(mx, pre);
}
return mx;
}
};

56. 合并区间

题意

以数组  intervals  表示若干个区间的集合,其中单个区间为  intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回  一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

代码

class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end());
vector<vector<int>> v;
int l = -1, r = -1;
for (auto& a : intervals) {
if (l == -1) {
l = a[0], r = a[1];
continue;
}
if (a[0] > r) {
v.push_back({l, r});
l = a[0];
}
r = max(r, a[1]);
}
v.push_back({l, r});
return v;
}
};

57. 轮转数组

题意

给定一个整数数组  nums,将数组中的元素向右轮转  k  个位置,其中  k  是非负数。

代码

class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
k %= n;
reverse(nums.begin(), nums.end());
reverse(nums.begin(), nums.begin() + k);
reverse(nums.begin() + k, nums.end());
}
};

58. 除自身以外数组的乘积

题意

给你一个整数数组  nums,返回 数组  answer ,其中  answer[i]  等于  nums  中除  nums[i]  之外其余各元素的乘积  。

题目数据  保证  数组  nums之中任意元素的全部前缀元素和后缀的乘积都在   32 位  整数范围内。

请  不要使用除法, 且在  O(n)  时间复杂度内完成此题。

代码

class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int n = nums.size();
vector<int> pre(n, 1), suf(n, 1);
pre[0] = nums[0], suf[n - 1] = nums[n - 1];
for (int i = 1; i < n; i++) {
pre[i] = pre[i - 1] * nums[i];
suf[n - i - 1] = suf[n - i] * nums[n - i - 1];
}
vector<int> arr;
for (int i = 0; i < n; i++) {
if (i - 1 >= 0 && i + 1 <= n - 1)
arr.push_back(pre[i - 1] * suf[i + 1]);
else if (i == 0)
arr.push_back(suf[1]);
else
arr.push_back(pre[n - 2]);
}
return arr;
}
};

59. 缺失的第一个正数

题意

给你一个未排序的整数数组  nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为  O(n)  并且只使用常数级别额外空间的解决方案。

代码

class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n; i++) {
if (nums[i] <= 0)
continue;
while (nums[i] <= n && nums[i] - 1 >= 0 &&
nums[nums[i] - 1] != nums[i]) {
swap(nums[i], nums[nums[i] - 1]);
}
}
for (int i = 0; i < n; i++) {
if (nums[i] != i + 1)
return i + 1;
}
return n + 1;
}
};

矩阵(2/4)

73. 矩阵置零

题意

给定一个  $m \times n$  的矩阵,如果一个元素为  0 ,则将其所在行和列的所有元素都设为  0 。请使用  原地  算法。

代码

class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int n = matrix.size();
if (!n)
return;
int m = matrix[0].size();
vector<bool> row(n), col(m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (matrix[i][j] == 0) {
row[i] = col[j] = true;
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (row[i] || col[j])
matrix[i][j] = 0;
}
}
}
};

54. 螺旋矩阵

题意

给你一个  m  行  n  列的矩阵  matrix ,请按照  顺时针螺旋顺序 ,返回矩阵中的所有元素。

代码

class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
int n = matrix.size();
if (!n)
return {};
if (n == 1)
return matrix[0];
int m = matrix[0].size();
if (m == 1) {
vector<int> v;
for (int i = 0; i < n; i++)
v.emplace_back(matrix[i][0]);
return v;
}
int x = 0, y = 0, k = 0;
vector<pair<int, int>> dxy = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
vector<int> v = {matrix[x][y]};
matrix[x][y] = -101;
while (v.size() < n * m) {
int px = x + dxy[k].first, py = y + dxy[k].second;
if (px < 0 || px >= n || py < 0 || py >= m ||
matrix[px][py] == -101) {
k = (k + 1) % 4;
px = x + dxy[k].first, py = y + dxy[k].second;
}
v.push_back(matrix[px][py]);
matrix[px][py] = -101;
x = px, y = py;
}
return v;
}
};

48. 旋转图像

题意

给定一个  $n\times n$ 的二维矩阵  matrix  表示一个图像。请你将图像顺时针旋转 90 度。

你必须在  原地  旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要  使用另一个矩阵来旋转图像。

240. 搜索二维矩阵 II

Comments

Quiet notes for this article.