2024年1月29日第五天编程训练,今天主要是进行一些题训练,包括简单题3道、中等题2道和困难题1道,今天总算把进度赶上了,虽然有很多不会的,但是总体还是有进步的。
链接: 反转元音字母
难度: 简单
题目:
思路:
与之前的反转字符串类似,无非是这里需要先记录下元音字母位置再反转。
代码:
class Solution {
public:
string reverseVowels(string s) {
vector<int> res;
for(int i = 0; i < s.size(); i++){
if(s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u'||
s[i] == 'A' || s[i] == 'E' || s[i] == 'I' || s[i] == 'O' || s[i] == 'U'){
res.push_back(i);
}
}
int n = res.size();
for(int i = 0; i < n/ 2; i++){
char c = s[res[i]];
s[res[i]] = s[res[n-i-1]];
s[res[n-i-1]] = c;
}
return s;
}
};
链接: 数组交集
难度: 简单
题目:
运行示例:
思路:
利用哈希表存储在第一个数组中出现的数字,然后和第二个数组中的元素进行判断。
代码:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int,int> map;
vector<int> ans;
for(int i = 0; i < nums1.size(); i++){
if(map[nums1[i]] == 0) map[nums1[i]] = 1;
}
for(int i = 0; i < nums2.size(); i++){
if(map[nums2[i]] == 1 && !(std::find(ans.begin(), ans.end(), nums2[i]) != ans.end())) ans.push_back(nums2[i]);
}
return ans;
}
};
链接: 数组的交集出现次数
难度: 简单
题目:
运行示例:
思路:
这道题与上一道题有相似之处,我都是用的哈希表,但是这道题题目我用了两个哈希表分别记录两个数组中元素出现的次数,然后进行对比得到结果。
官方的方法是用一个哈希表,通过改变哈希表中元素出现的次数的值来得到结果。
代码:
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int,int> map1,map2;
vector<int> ans;
for(int i = 0; i < nums1.size(); i++){
map1[nums1[i]]++;
}
for(int i = 0; i < nums2.size(); i++){
map2[nums2[i]]++;
}
for(auto p:map1){
int key = p.first;
int count = p.second;
if(map2[key] != 0){
int n = count > map2[key]?map2[key]:count;
cout<<n<<endl;
for(int i = 0; i < n; i++){
ans.push_back(key);
}
}
}
return ans;
}
};
官方代码
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
if (nums1.size() > nums2.size()) {
return intersect(nums2, nums1);
}
unordered_map <int, int> map;
for(int num: nums1){
map[num]++;
}
vector<int> intersection;
for(int num:nums2){
if(map[num]){
intersection.push_back(num);
map[num]--;
if(map[num] == 0){
map.erase(num);
}
}
}
return intersection;
}
};
链接: 二叉搜索树
难度: 中等
题目:
运行示例:
思路:
这道题与昨天的训练题类似,但是这道题只用求种类数相对简单,我们可以利用动态规划求当前节点左右自述的种类数再相乘即可得到结果。
代码:
class Solution {
public:
int numTrees(int n) {
vector<int> dp(n+1,0);
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i <= n; i++){
for(int j = 1; j <= i; j++){
dp[i] += dp[j-1] * dp[i-j];
}
}
return dp[n];
}
};
运行示例:
思路:
我本来用的是回溯的但是时间超过了,看了官方发现这是一道比较典型的动态规划问题,dp[i][j]表示s1的前i个字符与s2的前j个字符组成的字符串与s3的前i+j-1个字符之间的状态。
代码:
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
int n1 = s1.size();
int n2 = s2.size();
int n3 = s3.size();
if(n1+n2 != n3) return false;
vector<vector <bool>> dp(n1+1,vector<bool>(n2+1,false));
dp[0][0] = true;
for(int i = 0; i <= n1; i++){
for(int j = 0; j <= n2; j++){
int k = i + j -1;
if(i > 0) dp[i][j] = dp[i][j] || dp[i-1][j] && s1[i-1] == s3[k];
if(j > 0) dp[i][j] = dp[i][j] || dp[i][j-1] && s2[j-1] == s3[k];
}
}
return dp[n1][n2];
}
};
思路:
这个题与上一道题交错字符串类似,都是求匹配所以使用动态规划算法。
代码:
置换:
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n = nums.size();
for(int i = 0; i < n; i++){
while(nums[i] > 0 && nums[i] <= n && nums[nums[i] -1 ] != nums[i]){
swap(nums[nums[i] - 1], nums[i]);
}
}
for(int i = 0; i < n; i++){
if(nums[i] != i+1){
return i + 1;
}
}
return n + 1;
}
};