文章目录
- [1047. 删除字符串中的所有相邻重复项](https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/)
- [258. 各位相加](https://leetcode.cn/problems/add-digits/)
- [345. 反转字符串中的元音字母](https://leetcode.cn/problems/reverse-vowels-of-a-string/)
- [面试题 01.05. 一次编辑](https://leetcode.cn/problems/one-away-lcci/)
- [1137. 第 N 个泰波那契数](https://leetcode.cn/problems/n-th-tribonacci-number/)
- [93. 复原 IP 地址](https://leetcode.cn/problems/restore-ip-addresses/)
- [547. 省份数量](https://leetcode.cn/problems/number-of-provinces/)
- [106. 从中序与后序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/)
- [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/)
- [1103. 分糖果 II](https://leetcode.cn/problems/distribute-candies-to-people/)
- [238. 除自身以外数组的乘积](https://leetcode.cn/problems/product-of-array-except-self/)
- [162. 寻找峰值](https://leetcode.cn/problems/find-peak-element/)
- [541. 反转字符串 II](https://leetcode.cn/problems/reverse-string-ii/)
1047. 删除字符串中的所有相邻重复项
栈
class Solution {
public:
string removeDuplicates(string s) {
// stack
stack<char> sk;
for (char& x : s) {
if (!sk.empty() && x == sk.top()) {
sk.pop();
} else {
sk.push(x);
}
}
string str;
while (!sk.empty()) {
str += sk.top();
sk.pop();
}
reverse(str.begin(), str.end());
return str;
}
};
直接在string操作
back() 和 push_back() pop_back()
class Solution {
public:
string removeDuplicates(string s) {
string str;
for (char& x : s) {
if (!str.empty() && str.back() == x) {
str.pop_back();
} else {
str.push_back(x);
}
}
return str;
}
};
258. 各位相加
class Solution {
public:
int addDigits(int num) {
while (num >= 10) {
int count = 0;
while (num > 0) {
count += num % 10;
num /= 10;
}
num = count;
}
return num;
}
};
class Solution {
public:
int addDigits(int num) {
return (num - 1) % 9 + 1;
}
};
345. 反转字符串中的元音字母
暴力做法,可以省去reverse步骤,将idx从后往前遍历即可。
class Solution {
public:
bool flag (char& x) {
return x == 'a' || x == 'e' || x == 'i' || x == 'o' || x == 'u' || x == 'A' || x == 'E' || x == 'I' || x == 'O' || x == 'U';
}
string reverseVowels(string s) {
string str;
for (char& x : s) {
if (flag(x)) {
str += x;
}
}
reverse(str.begin(), str.end());
int idx = 0;
for (int i = 0; i < s.length(); ++i) {
if (flag(s[i])) {
s[i] = str[idx++];
}
}
return s;
}
};
双指针
class Solution {
public:
bool flag (char& x) {
return x == 'a' || x == 'e' || x == 'i' || x == 'o' || x == 'u' || x == 'A' || x == 'E' || x == 'I' || x == 'O' || x == 'U';
}
string reverseVowels(string s) {
int l = 0, r = s.length() - 1;
while (l < r) {
while (l < r && !flag(s[l])) {
++l;
}
while (l < r && !flag(s[r])) {
--r;
}
swap(s[l++], s[r--]);
}
return s;
}
};
面试题 01.05. 一次编辑
双指针
个人觉得很好的题解:https://leetcode.cn/problems/one-away-lcci/solution/fu-xue-ming-zhu-by-fuxuemingzhu-qswu/
class Solution {
public:
bool oneEditAway(string first, string second) {
// two points
int len1 = first.length(), len2 = second.length();
if (abs(len1 - len2) > 1) {
return false;
}
if (len1 < len2) return oneEditAway(second, first);
int i = 0, j = 0;
int flag = 0;
while (i < len1 && j < len2) {
if (first[i] != second[j]) {
++flag;
if (flag > 1) {
return false;
}
if (len1 != len2) {
--j;
}
}
++i; ++j;
}
return true;
}
};
这道题也可以用前缀后缀来做
只需要编辑一次的前后缀应该相同
来源:wangYiTiaoYu
class Solution {
public:
bool oneEditAway(string first, string second) {
int p1 = 0;
int q1 = first.size() - 1;
int p2 = 0;
int q2 = second.size() - 1;
while (p1 <= q1 && p2 <= q2) {
if (first[p1] == second[p1]) {
++p1;
++p2;
continue;
}
if (first[q1] == second[q2]) {
--q1;
--q2;
} else {
break;
}
}
return q1 - p1 + q2 - p2 <= 0 && abs(p1 - p2) <= 1 && abs(q1 - q2) <= 1;
}
};
1137. 第 N 个泰波那契数
不用压栈操作效率会更高
class Solution {
public:
int tribonacci(int n) {
// 不用递归了
int a = 0, b = 1, c = 1;
if (n < 3) {
return n == 0 ? 0 : 1;
}
for (int i = 3; i <= n; ++i) {
int temp = c;
c = a + b + c;
a = b;
b = temp;
}
return c;
}
};
93. 复原 IP 地址
回溯做法
边界判断条件:是否有四个ip位,left是否已到最右边
class Solution {
public:
vector<string> res;
void DFS(string str, string s, int num, int left) {
if (left == s.length() && num == 4) {
res.push_back(str);
return;
}
if (num >= 4 || left >= s.length()) {
return;
}
string temp = (num == 0 ? "" : ".");
for (int right = left; right < left + 3; ++right) {
if (s[left] == '0') {
DFS(str + temp + "0", s, num + 1, left + 1);
break;
}
if (stoi(s.substr(left, right - left + 1)) <= 255) {
DFS(str + temp + s.substr(left, right - left + 1), s, num + 1, right + 1);
}
}
}
vector<string> restoreIpAddresses(string s) {
int len = s.length();
if (len > 12) return res;
DFS("", s, 0, 0);
return res;
}
};
547. 省份数量
深度优先搜索
class Solution {
public:
#define k 200
// static const int k = 200;
int vis[k];
// vector<int> vis;
void DFS(vector<vector<int>>& isConnected, int i) {
for (int j = 0; j < isConnected[i].size(); ++j) {
if (isConnected[i][j] == 1 && vis[j] != 1) {
vis[j] = 1;
DFS(isConnected, j);
}
}
}
int findCircleNum(vector<vector<int>>& isConnected) {
int n = isConnected.size(), res = 0;
// vis.resize(n, 0);
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; ++i) {
if (vis[i] == 0) {
++res;
DFS(isConnected, i);
}
}
return res;
}
};
广度优先搜索
class Solution {
public:
int findCircleNum(vector<vector<int>>& isConnected) {
int n = isConnected.size(), res = 0;
int vis[200] = {0};
queue<int> q;
for (int i = 0; i < n; ++i) {
if (!vis[i]) {
q.push(i);
++res;
while (!q.empty()) {
int k = q.front(); q.pop();
vis[k] = 1;
for (int j = 0; j < isConnected[k].size(); ++j) {
if (isConnected[k][j] == 1 && vis[j] == 0) {
q.push(j);
}
}
}
}
}
return res;
}
};
并查集
class Solution {
public:
int Find(vector<int>& parent, int idx) {
if (parent[idx] != idx) {
parent[idx] = Find(parent, parent[idx]);
}
return parent[idx];
}
void Union(vector<int>& parent, int idx1, int idx2) {
parent[Find(parent, idx1)] = Find(parent, idx2);
}
int findCircleNum(vector<vector<int>>& isConnected) {
int n = isConnected.size(), res = 0;
vector<int> parent(n);
for (int i = 0; i < n; ++i) {
parent[i] = i;
}
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (isConnected[i][j] == 1) {
Union(parent, i, j);
}
}
}
for (int i = 0; i < n; ++i) {
if (parent[i] == i) {
++res;
}
}
return res;
}
};
106. 从中序与后序遍历序列构造二叉树
递归构树,保存中序映射节点,减少遍历次数
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
unordered_map<int, int> mp;
TreeNode* Build(vector<int>& inorder, vector<int>& postorder, int in_l, int in_r, int post_l, int post_r) {
if (in_l > in_r || post_l > post_r) {
return nullptr;
}
TreeNode* node = new TreeNode(postorder[post_r]);
int idx = mp[postorder[post_r]];
int post_len = idx - in_l;
node->left = Build(inorder, postorder, in_l, idx - 1, post_l, post_l + post_len - 1);
node->right = Build(inorder, postorder, idx + 1, in_r, post_l + post_len, post_r - 1);
return node;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
int len = inorder.size();
for (int i = 0; i < len; ++i) {
mp[inorder[i]] = i;
}
TreeNode* node = Build(inorder, postorder, 0, len - 1, 0, len - 1);
return node;
}
};
567. 字符串的排列
暴力超时
class Solution {
public:
bool flag = false;
void DFS(string& s2, unordered_map<char, int>& mp, int& len, int idx) {
if (len == 0 || flag) {
flag = true;
return;
}
if (mp[s2[idx]]) {
--mp[s2[idx]]; --len;
DFS(s2, mp, len, idx + 1);
++mp[s2[idx]]; ++len;
}
}
bool checkInclusion(string s1, string s2) {
int len1 = s1.length(), len2 = s2.length();
if (len1 > len2) return false;
unordered_map<char, int> mp;
for (char& x : s1) {
++mp[x];
}
for (int i = 0; i < len2; ++i) {
DFS(s2, mp, len1, i);
if (flag) break;
}
return flag;
}
};
滑动窗口
class Solution {
public:
bool checkInclusion(string s1, string s2) {
int len1 = s1.length(), len2 = s2.length();
if (len1 > len2) return false;
vector<int> ans1(26), ans2(26);
for (int i = 0; i < len1; ++i) {
++ans1[s1[i] - 'a'];
++ans2[s2[i] - 'a'];
}
if (ans1 == ans2) return true;
for (int i = len1; i < len2; ++i) {
--ans2[s2[i - len1] - 'a'];
++ans2[s2[i] - 'a'];
if (ans1 == ans2) return true;
}
return false;
}
};
双指针
class Solution {
public:
bool checkInclusion(string s1, string s2) {
int len1 = s1.length(), len2 = s2.length();
if (len1 > len2) return false;
vector<int> cnt(26);
for (char& x : s1) {
--cnt[x - 'a'];
}
int left = 0;
for (int right = 0; right < len2; ++right) {
int x = s2[right] - 'a';
++cnt[x];
while (cnt[x] > 0) {
--cnt[s2[left] - 'a'];
++left;
}
if (right - left + 1 == len1) {
return true;
}
}
return false;
}
};
1103. 分糖果 II
推导过程见lt官方题解
基本思想为等差数列求和
class Solution {
public:
vector<int> distributeCandies(int candies, int num_people) {
// n * (n + 1) / 2
int n = num_people;
int p = (int)(sqrt(2 * candies + 0.25) - 0.5);
int remaining = candies - p * (p + 1) / 2;
int rows = p / n, cols = p % n;
vector<int> dp(n, 0);
for (int i = 0; i < n; ++i) {
dp[i] = (i + 1) * rows + n * rows * (rows - 1) / 2;
if (i < cols) dp[i] += i + 1 + rows * n;
}
dp[cols] += remaining;
return dp;
}
};
238. 除自身以外数组的乘积
先写一个开空间的
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
// 不能用除法,先开空间试下
int len = nums.size();
vector<int> left(len, 1), right(len, 1);
// int temp_l = 1, temp_r = 1;
for (int i = 1; i < len; ++i) {
left[i] = left[i - 1] * nums[i - 1];
right[len - 1 - i] = right[len - i] * nums[len - i];
}
for (int i = 0; i < len; ++i) {
left[i] *= right[i];
}
return left;
}
};
按题目要求完成
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int len = nums.size();
vector<int> right(len, 1);
for (int i = len - 2; i >= 0; --i) {
right[i] = right[i + 1] * nums[i + 1];
}
for (int i = 1; i < len; ++i) {
right[i] = right[i] * nums[i - 1];
nums[i] *= nums[i - 1];
}
return right;
}
};
162. 寻找峰值
题目默认两边边界都是负无穷
二分往大的一边查找即可
并且题目规定了nums[i] != nums[i + 1]
class Solution {
public:
int findPeakElement(vector<int>& nums) {
// log(n)一般是二分
int l = 0, r = nums.size() - 1, pos = 0;
while (l <= r) {
int mid = l + (r - l) / 2;
if (mid < nums.size() - 1 && nums[mid] < nums[mid + 1]) {
pos = mid + 1;
l = mid + 1;
} else {
r = mid - 1;
}
}
return pos;
}
};
541. 反转字符串 II
简单题
class Solution {
public:
string reverseStr(string s, int k) {
int len = s.length();
for (int i = 0; i < len; i += 2 * k) {
reverse(s.begin() + i, s.begin() + min((i + k), len));
}
return s;
}
};