leetcode update

This commit is contained in:
gameloader 2024-10-05 21:24:52 +08:00
parent 3617a14eb6
commit e79bca54f5

View File

@ -14529,3 +14529,361 @@ public:
} }
}; };
``` ```
## day216 2024-09-30
### 1381. Design a Stack With Increment Operation
Design a stack that supports increment operations on its elements.
Implement the CustomStack class:
CustomStack(int maxSize) Initializes the object with maxSize which is the maximum number of elements in the stack.
void push(int x) Adds x to the top of the stack if the stack has not reached the maxSize.
int pop() Pops and returns the top of the stack or -1 if the stack is empty.
void inc(int k, int val) Increments the bottom k elements of the stack by val. If there are less than k elements in the stack, increment all the elements in the stack.
![0930hE2q4SQyqQL7](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/0930hE2q4SQyqQL7.png)
### 题解
本题根据题目要求要构建一个可以同时修改从栈底开始向上几个元素的栈如果用一个数组来实现栈的话向数组末尾插入就是向栈顶插入修改从栈底开始的几个值即为从数组头部开始遍历数组修改对应的值。非常符合题目的要求。用一个变量记录当前栈的大小在push和pop时先判断栈是否已空或已满。
除了可以使用vector也可以使用一般的数组定义一个数组指针在构造函数中按需动态分配数组内存。
### 代码
```cpp
class CustomStack {
private:
int count;
int maxLen;
vector<int> stackvector;
public:
CustomStack(int maxSize) {
count = 0;
maxLen = maxSize;
}
void push(int x) {
if (count < maxLen){
stackvector.push_back(x);
count++;
}
}
int pop() {
if (count>0){
int result = stackvector[count-1];
stackvector.pop_back();
count--;
return result;
}
return -1;
}
void increment(int k, int val) {
for(int i=0;i<k&&i<count&&i<maxLen;i++){
stackvector[i] += val;
}
}
};
/**
* Your CustomStack object will be instantiated and called as such:
* CustomStack* obj = new CustomStack(maxSize);
* obj->push(x);
* int param_2 = obj->pop();
* obj->increment(k,val);
*/
```
## day217 2024-10-01
### 1497. Check If Array Pairs Are Divisible by k
Given an array of integers arr of even length n and an integer k.
We want to divide the array into exactly n / 2 pairs such that the sum of each pair is divisible by k.
Return true If you can find a way to do that or false otherwise.
![1001e0GB8YrcDSmd](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1001e0GB8YrcDSmd.png)
### 题解
本题要将全部数字分为两两一组并要求每组中的两个数组和可以被k整除。对于整除的问题一般可以通过取模将余数相同的数字筛选出来这些数字可视为拥有相同的“性质”无需关心其原本的数字大小。想实现组合的两个数字可以被k整除只需这两个数字对k取模后的余数和可以被k整除。则统计各个余数对应的数字个数再按照余数和为k将对应的组组合如k=5则余数为1和余数为4的数字个数相同则这两个组的数字可以两两配对使得其被k整除看两个组的数字个数是否相同全部相同且余数为0的组的个数为偶数则能够组合成功否则不能。
注意本题中数字可能为负数则要考虑负数取模的情况。在c++和其他一些语言中,对负数取模,计算方式是先绝对值取模再根据原数字的符号添加符号。如`-1%5=-1`。为了让负数取模的结果也为正数,即数学中的取模方式,可以用`(num%k+k)%k`使得正负数均得到正数的模。
### 代码
```cpp
class Solution {
public:
bool canArrange(vector<int>& arr, int k) {
vector <vector<int>> remain(k);
for (int num : arr){
remain[(num%k+k)%k].push_back(num);
}
if (remain[0].size() % 2 == 1){
return false;
}
if (k%2 == 1){
for (int i=1; i<=k/2;i++){
if (remain[i].size() != remain[k-i].size()){
return false;
}
}
}else{
for (int i=1; i<k/2;i++){
if (remain[i].size() != remain[k-i].size()){
return false;
}
}
if (remain[k/2].size()%2 == 1){
return false;
}
}
return true;
}
};
```
## day218 2024-10-02
### 1331. Rank Transform of an Array
Given an array of integers arr, replace each element with its rank.
The rank represents how large the element is. The rank has the following rules:
Rank is an integer starting from 1.
The larger the element, the larger the rank. If two elements are equal, their rank must be the same.
Rank should be as small as possible.
![1002FuIQoMmox8I2](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1002FuIQoMmox8I2.png)
### 题解
本题rank就是数字在数组中所有数字中的位次复制数组构造pair并排序用pair类型将数组中的数字和其对应的下标组合起来对pair的数字排序后遍历有序数组若数字和前一个数字相同则rank不变否则rank加1将rank填入result数组pair中数字对应的下标位置。
### 代码
```cpp
class Solution {
public:
vector<int> arrayRankTransform(vector<int>& arr) {
vector<pair<int,int>> sorted_rank(arr.size());
vector<int> result(arr.size());
for(int i = 0; i < arr.size(); ++i) {
sorted_rank[i] = {arr[i], i};
}
sort(sorted_rank.begin(), sorted_rank.end(), [](pair<int,int> p, pair<int, int> q){
return p.first < q.first;
});
int rank_num = 0;
for(int i = 0; i < result.size(); ++i) {
int value = sorted_rank[i].first;
int index = sorted_rank[i].second;
if(i == 0 || sorted_rank[i-1].first != value) {
++rank_num;
}
result[index] = rank_num;
}
return result;
}
};
```
## day219 2024-10-03
### 1590. Make Sum Divisible by P
Given an array of positive integers nums, remove the smallest subarray (possibly empty) such that the sum of the remaining elements is divisible by p. It is not allowed to remove the whole array.
Return the length of the smallest subarray that you need to remove, or -1 if it's impossible.
A subarray is defined as a contiguous block of elements in the array.
![1003OjeSw7Bf5SvI](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1003OjeSw7Bf5SvI.png)
### 题解
涉及此类和整除相关的题目,取余是基本步骤,取余的目的在于找到同余,余数相同的可视为具有某种相同的性质,数论中同余就是一种等价关系。
本题中对整个数组求和并取余后余数即为应该删掉的子数组数字和对p取余的值设为k。如何求得所有和对p取余余数为k的子数组呢。可以利用前缀和如果到下标i的前缀数组和对p取余为m到下标i+n的前缀数组和对p取余为(m+k)%p则i到i+n之间的子数组对p取余得到的就应该是k。则我们可以将已经遍历过的前缀数组数组和取余的余数作为key该余数对应的已遍历的最后一个下标作为value保存起来。这样遍历数组对任一下标i我们知道其前缀和余数为m再去遍历余数对应的下标map找到(m-k)%p这个余数对应的下标。计算当前下标到找到的下标的距离与保存的最小长度比较取较小。再用当前下标更新余数对应的map。这样求和后遍历一遍数组即可得到结果。
### 代码
```cpp
class Solution {
public:
int minSubarray(vector<int> &nums, int p) {
int n = nums.size();
long totalrem = accumulate(nums.begin(), nums.end(), 0l) % p;
if(totalrem == 0) {
return 0;
}
unordered_map<int, int> presums;
presums[0] = -1;
long sum = 0;
int minlen = INT_MAX;
for(int i = 0; i < n; i++) {
sum += nums[i];
long rem = sum % p;
long target = (((rem - totalrem) % p) + p) % p;
if(presums.contains(target)) {
minlen = min(i - presums[target], minlen);
}
presums[rem] = i;
}
return (minlen == INT_MAX or minlen == n) ? -1 : minlen;
}
};
```
## day220 2024-10-04
### 2491. Divide Players Into Teams of Equal Skill
You are given a positive integer array skill of even length n where skill[i] denotes the skill of the ith player. Divide the players into n / 2 teams of size 2 such that the total skill of each team is equal.
The chemistry of a team is equal to the product of the skills of the players on that team.
Return the sum of the chemistry of all the teams, or return -1 if there is no way to divide the players into teams such that the total skill of each team is equal.
![1004CPuvIeBvG5B7](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1004CPuvIeBvG5B7.png)
### 题解
本题要先计算出数组和再求出平均分配给每个team的skill为多少记为k。统计所有skill值的个数放入map从小到大遍历skill值并判断k-skill的个数是否与skill相同相同则计算skill和k-skill的乘积与个数相乘加和到最终结果中。继续遍历不同则直接返回-1。
注意到本题中skill的值最大为1000故统计频率可以直接用数组替代map开辟一个长度为1001的整数数组下标表示skill值表示出现频率即可。
### 代码
```cpp
class Solution {
public:
long long dividePlayers(vector<int>& skill) {
int n = skill.size();
long long sum = 0;
vector<int> freq(1001, 0);
// 计算总和并统计频率
for (int sk : skill) {
sum += sk;
freq[sk]++;
}
// 检查是否可以平均分配
if (sum % (n / 2) != 0) {
return -1;
}
int targetSum = sum / (n / 2);
long long chemistry = 0;
for (int i = 1; i <= targetSum/2; i++) {
if (freq[i] == 0){
continue;
}
int complement = targetSum - i;
if (complement < i) break; // 避免重复检查
if (i == complement) {
if (freq[i] % 2 != 0) {
return -1;
}
chemistry += (long long)i * complement * (freq[i] / 2);
} else {
if (freq[i] != freq[complement]) {
return -1;
}
chemistry += (long long)i * complement * freq[i];
}
}
return chemistry;
}
};
```
## day221 2024-10-05
### 567. Permutation in String
Given two strings s1 and s2, return true if s2 contains a
permutation
of s1, or false otherwise.
In other words, return true if one of s1's permutations is the substring of s2.
![1005o0z59CxviRXY](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1005o0z59CxviRXY.png)
### 题解
本题先统计s1字符串中各个字母的个数。由于要寻找s2中某个子字符串是s1中字母的组合则使用一个s1长度的滑动窗口在s2字符串上滑动并计数窗口内各个字母的个数滑动过程中不断将窗口右侧的字母个数加一判断是否与s1匹配左侧的减一判断是否与s1匹配。用一个变量记录当前窗口中已经匹配的字母的个数每次滑动后判断匹配的字母个数是否达到26个达到26个则直接返回true。
### 代码
```cpp
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if (s1.size() > s2.size()) {
return false;
}
vector<int> count(26, 0);
vector<int> window(26, 0);
for (char c : s1) {
count[c - 'a']++;
}
for (int i = 0; i < s1.size(); i++) {
window[s2[i] - 'a']++;
}
int matched = 0;
for (int i = 0; i < 26; i++) {
if (window[i] == count[i]) {
matched++;
}
}
if (matched == 26) return true;
// 滑动窗口
for (int right = s1.size(); right < s2.size(); right++) {
int left = right - s1.size();
// 添加右边的新字符
int r = s2[right] - 'a';
window[r]++;
if (window[r] == count[r]) matched++;
else if (window[r] == count[r] + 1) matched--;
// 移除左边的旧字符
int l = s2[left] - 'a';
window[l]--;
if (window[l] == count[l]) matched++;
else if (window[l] == count[l] - 1) matched--;
if (matched == 26) return true;
}
return false;
}
};
```