mirror of
https://gitlab.com/game-loader/hugo.git
synced 2025-04-20 05:52:07 +08:00
leetcode update
This commit is contained in:
parent
3617a14eb6
commit
e79bca54f5
@ -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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 题解
|
||||||
|
|
||||||
|
本题根据题目要求要构建一个可以同时修改从栈底开始向上几个元素的栈,如果用一个数组来实现栈的话,向数组末尾插入就是向栈顶插入,修改从栈底开始的几个值即为从数组头部开始遍历数组,修改对应的值。非常符合题目的要求。用一个变量记录当前栈的大小,在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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 题解
|
||||||
|
|
||||||
|
本题要将全部数字分为两两一组,并要求每组中的两个数组和可以被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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 题解
|
||||||
|
|
||||||
|
本题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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 题解
|
||||||
|
|
||||||
|
涉及此类和整除相关的题目,取余是基本步骤,取余的目的在于找到同余,余数相同的可视为具有某种相同的性质,数论中同余就是一种等价关系。
|
||||||
|
|
||||||
|
本题中对整个数组求和并取余后,余数即为应该删掉的子数组数字和对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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 题解
|
||||||
|
|
||||||
|
本题要先计算出数组和再求出平均分配给每个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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 题解
|
||||||
|
|
||||||
|
本题先统计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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user