这里写自定义目录标题
一个菜鸡的力扣刷题记录01
自2022/12/25起开始刷题,并记录刷题过程以及在刷题过程中遇到或可能遇到的问题。
刷题顺序参考代码随想录
数组
数组部分将包含:二分查找、移除元素、有序数组的平方、长度最小的子数组与螺旋矩阵Ⅱ。
二分查找
主要是二分查找并涉及一些其他相关的题目。
二分查找应当先符合两点要求:
1、数组有序
2、无重复元素
704.二分查找
2022/12/25
该题应当注意两点:
1、不同的区间选择,不同的写法(左闭右闭,左闭右开)。
2、更新中间值为防止溢出,选择特殊的写法。
左闭右闭的情况下,
//左闭右闭
class Solution {
public:
int search(vector<int>& nums, int target) {
int right = 0, left = nums.size() - 1;//设置搜索区间
while (right <= left)
{
int mid = left + ((right - left) / 2);//更新中间值
//查找
if (nums[mid] > target)//若该值大于目标值
left = mid - 1;//更新上限
else if (nums[mid] < target)//该值小于目标值
right = mid + 1;//更新下限
else
return mid;//数值相同返回下标
}
return -1;
}
};
035.搜索插入位置
2022/12/25
该题相较于704_二分查找来说,仅需改动不存在的时候的返回值即可。
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int right = 0, left = nums.size() - 1;//设置搜索区间
while (right <=left)
{
int mid = left + ((right - left) / 2);//更新中间值
//继续查找
if (nums[mid] > target)//若该值大于目标值
left = mid - 1;//更新上限
else if (nums[mid] < target)//该值小于目标值
right = mid + 1;//更新下限
else
return mid;//数值相同返回下标
}
return right;//不存在返回应该插入的位置
}
};
034.在排序数组中查找元素的第一个和最后一个位置
2022/12/25
前者是看题解前自己写的代码,后者是官方题解。
自己写的代码
存在的问题: 时间复杂度很有可能达到O(n)
发现的问题: low >= 0 && nums[low] == target,如上,应当先判断是否越界,再判断是否相等,否则发生越界。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> result;
int right = 0, left = nums.size() - 1, mid = 0;//设置搜索区间
while (1)
{
mid = left + ((right - left) / 2);//更新中间值
if (right > left)//检查搜索区间是否合法
{
result = { -1,-1 };
break;
}//不存在将范围定在-1,-1
else if (nums[mid] == target)//检查数值
{
result = { mid, mid };//为结果赋初值
int low = mid, high = mid;//设置范围
while (low >= 0 && nums[low] == target) low--;//判断下界
result[0] = low + 1;//更新下界
while (high <= nums.size() - 1 && nums[high] == target) high++;//判断上界
result[1] = high - 1;//更新上界
break;
}
//继续查找
if (nums[mid] > target)//若该值大于目标值
left = mid - 1;//更新上限
else//该值小于目标值
right = mid + 1;//更新下限
}
但实际上这个方法速度可能会慢,不如先寻找左边界,再寻找右边界速度快。
后来本人代买如下:
class Solution{
public:
vector<int> searchRange(vector<int>& nums, int target){
if(nums.size() == 0) //检查数组是否为空
return {-1, -1};
int left = 0; //定义左
int right = nums.size() - 1; //定义右
int left_mid = left + (right - left) / 2; //定义左边界
int right_mid = left + (right - left) / 2; //定义右边界
while(true) //寻找左边界
{
//找到目标数值:
// 如果满足以下两点,则说明找到左边界:
// 1、当下为最左边的值
// 2、该值的左边不再是目标数值
if(nums[left_mid] == target)
if(left_mid - 1 < 0 || nums[left_mid - 1] != target)
break; //保存左边界并结束循环
else if(left >= right) //没有找到目标值
return {-1, -1}; //返回-1,-1
else if(nums[left_mid] >= target) //当 当下值 大于等于 目标指时,调整右侧
right = left_mid - 1;
else //否则调整左侧
left = left_mid + 1;
left_mid = left + (right - left) / 2; //重新定义左边界值
}
left = 0; //初始化
right = nums.size() - 1; //初始化
//寻找右边界
while(true)
{
//找到目标数值:
// 如果满足以下两点,则说明找到右边界:
// 1、当下为最右边的值
// 2、该值的右边不再是目标数值
if(nums[right_mid] == target)
if(right_mid + 1 > nums.size() - 1 || nums[right_mid + 1] != target)
break;
//能找到左边界,说明一定存在右边界。
else if(nums[right_mid] > target) //调整右侧
right = right_mid - 1;
else //当 该值 小于等于 目标值时,调整左侧
left = right_mid + 1;
right_mid = left + (right - left) / 2; //重新定义右边界值
}
return {left_mid, right_mid}; //返回找到的左右边界
}
};
069.X的平方根
2023/8/5
本体使用的二分法,但问题在于我一开始使用的是将中间的值进行平方与X进行比较,导致数值极大,存在溢出的问题,所以在看了题解以后使用了另一种方法。
class Solution {
public:
int mySqrt(int x) {
if(x == 1 || x == 0) //如果是1或者是0,那么返回x本身
return x;
int left = 1; //将左边界设置为1
int right = x / 2; //将右边界设置为 x/2
//如果right < 4 则可以直接从循环中跳出,得到1的答案。
while(left < right) //循环条件
{
int mid = left + (right - left + 1) / 2; //中点
if (mid > x / mid) //x/mid 小于 mid 的时候,说明右边界应当向左靠拢
right = mid - 1; //调整右边界
else //否则调整左边界
left = mid;
}
return left; //循环结束后的左边界就是所需的值
}
};
367.有效的完全平方数
2023/8/5
该题和上面那一道069几乎没什么区别。代码直接改一点点就可以。
class Solution {
public:
bool isPerfectSquare(int num) {
int x = num;
if(x == 1) //如果是1或者是0,那么返回x本身
return true;
int left = 1; //将左边界设置为1
int right = x / 2; //将右边界设置为 x/2
//如果right < 4 则可以直接从循环中跳出,得到1的答案。
while(left < right) //循环条件
{
int mid = left + (right - left + 1) / 2; //中点
if (mid > x / mid) //x/mid 小于 mid 的时候,说明右边界应当向左靠拢
right = mid - 1; //调整右边界
else //否则调整左边界
left = mid;
}
if(left * left == x) //循环结束后的左边界就是所需的值
return true;
else
return false;
}
};
移除元素
27.移除元素
2023/8/6
将要删除的元素用最后一个数去覆盖,但不如双指针的解法,快慢指针更简单易懂,代码也好实现。
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int count = nums.size();
for(int i = 0; i < count - 1;)
{
if(nums[i] != val)
i++;
else
{
count--;
nums[i] = nums[count];
}
}
if(count == 0)
return 0;
if(nums[count - 1] == val)
count--;
return count;
}
};
26.删除有序数组中的重复项
2023/8/6
使用双指针思想,快慢指针,和上一题思路一样。
class Solution {
public:
int removeDuplicates(vector<int>& nums)
{
int right = 1;
int left = 0;
if(nums.size() == 0)
return 0;
for(;right < nums.size();)
{
if(nums[left] != nums[right])
{
left++;
nums[left] = nums[right];
}
right++;
}
return left + 1;
}
};
283.移动零
2023/8/6
使用双指针思想,先通过第一个指针找到第一个零,然后将快指针中的数字赋予慢指针(0除外),将剩余的慢指针赋予0。
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int zero_count = 1; //数组中零的数量
int p; //双指针中的快指针
int q = 0; //双指针中的慢指针
int count = nums.size(); //数组数量
while(q < count) //寻找第一个0
{
if(nums[q] == 0) //找到第一个0,退出循环
break;
else //寻找数组中的0
q++;
}
p = q + 1; //初始化快指针
while(p < count) //将快指针中的值赋予慢指针
{
if(nums[p] == 0) //如果是零,则跳过
zero_count++;
else //非零,赋值
{
nums[q] = nums[p];
q++;
}
p++;
}
while(q < count) //将剩下的值赋予相应个数的0
{
nums[q] = 0;
q++;
}
return ;
}
};
844.比较含退格的字符串
2023/8/7
使用双指针思想,但这次是从后往前遍历,可以得到一个很好的结果。
自己没能做出来,看的题解,不难,但是思路没对。
class Solution {
public:
bool backspaceCompare(string s, string t) {
int skipS = 0; //S字符串中 # 的数量
int skipT = 0; //T字符串中 # 的数量
int scount = s.length() - 1; //从后往前遍历
int tcount = t.length() - 1; //从后往前遍历
while(scount >= 0 || tcount >= 0) //检查结束条件
{
while(scount >= 0) //先检查s字符串
{
if(s[scount] == '#') //如果是 # 号,则增加 skipS,并查看下一个
skipS++,scount--;
else if(skipS > 0) //如果不是 # 号,且skipS数量不为零,则减少 skipS,并查看下一个
skipS--,scount--;
else //如果不是#号,且skipS数量为零,则说明该字符可以进行比较
break;
}
while(tcount >= 0) //检查T字符串,方式同上
{
if(t[tcount] == '#')
skipT++,tcount--;
else if(skipT > 0)
skipT--,tcount--;
else
break;
}
if(scount >= 0 && tcount >= 0) //遍历都未结束时
{
if(s[scount] != t[tcount]) //如果字符串出现了不同,则返回false
return false;
else //否则 检查s和t的下一个字符串
scount--, tcount--;
}
else //如果遍历结束了
if(scount >= 0 || tcount >= 0) //而只有一个遍历结束,另一个没有结束,说明字符串长度不同。
return false;
}
return true;
}
};
977.有序数组的平方
2023/8/7
使用双指针思想,通过对左右指针的比较,从大到小进行处理。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int left = 0; //左指针
int right = nums.size() - 1; //右指针
int count = nums.size(); //数组数量
vector<int> res(count); //新建数组
while(left <= right) //循环结束条件,左右指针相遇
{
count--; //数量自减
if((nums[left] + nums[right]) > 0) //左右指针指向的数字谁更大
{
res[count] = nums[right] * nums[right]; //如果大于0,说明右指针中的数字更大
right--; //在新数组末尾存储更大的数的平方,并将右指针左移
}
else //同上
{
res[count] = nums[left] * nums[left];
left++;
}
}
return res;
}
};
有序数组的平方(题目重复)
长度最小的子数组
209.长度最小的子数组
2023/8/8
滑动窗口,start,end。
本题只有一个模糊的想法,最终还是看的题解,只能说能力还是太弱了。慢慢积累吧。
以下代码是O(n)的时间复杂度,还有一个O(logn)的时间复杂度。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int start = 0;
int end = 0;
int count = 0;
int sum = 0;
while(true)
{
if(end == nums.size() && sum < target)
return count;
if(sum < target && end < nums.size())
{
sum = sum + nums[end];
end++;
}
if(sum >= target )
{
if(end - start < count || count == 0)
count = end - start;
sum = sum - nums[start];
start++;
}
}
}
};
904.水果成篮
2023/8/9
这道题仍然是使用滑动窗口的思想,但是因为在具体是线上存在问题,调试了两次去看了题解。
发现题解和我的思路是一样的,只不过他用的哈希表,我是用各种判断。
那就说明我在某些判断条件上写错了,所以我又回过头再更改我自己的代码。
然后就对了。以下是我乱七八糟的代码。
class Solution {
public:
int totalFruit(vector<int>& fruits) {
int start = 0; //从第几棵树开始摘
int end = 0; //摘到第几棵了
int count = 0; //摘了几棵树的
while(end < fruits.size()) //最后一颗树
{
int type = 1; //出现的第集中水果
int a = fruits[start]; //第一种水果
int b; //等待出现的第二种水果
while(end < fruits.size()) //最后一颗树
{
if(a != fruits[end]) //如果与第一个水果不一样
{
if(type == 1) //且篮子里还没有第二种水果
{
b = fruits[end]; //将第二种水果放进篮子
type++; //表明篮子里的第二种水果
}
else if(b != fruits[end]) //与第一个不一样同时篮子里两种果子,又与第二个不一样
{
//作用:在start-end范围中,应当仅存在一种水果。
int top = start; //设定一个指针
int pd = 1; //应当保留哪种水果
while(top < end) //不能超过end
{
if(fruits[top] == a && pd == 2) //如果之前保留2号水果,而第一种出现了
{
start = top; //则说明应当删除2号
pd = 1; //保留一号
}
if(fruits[top] == b && pd == 1) //如果之前保留1号水果,而第二种出现了
{
start = top; //则说明应当删除1号水果
pd = 2; //保留二号
}
top++; //指针后移
}
break; //结束当前循环
}
}
end++;
if(end - start > count) //如果采摘的数量比当前记录的值大
count = end - start; //则保存
}
}
return count;
}
};
76.最小覆盖子串
2023/8/9
这道题仍然是使用滑动窗口的思想,问题不大,直接成的。
第一道困难级别的。
class Solution {
public:
string minWindow(string s, string t) {
string res = ""; //结果字符串
int left = 0; //左边界
int count = 0; //符合的字符串数
unordered_map <char,int> cnt; //哈希表
for(int right = 0; right < t.length(); right++) //初始化哈希表
cnt[t[right]]++;
for(int right = 0; right < s.length();right++) //遍历s串
{
auto it = cnt.find(s[right]); //右边界中的字符是否存在于t中
if (it != cnt.end()) //若存在
{
if(it->second > 0) //且数量大于零
{
count++; //则符合的字符数加一
it->second--; //该字符数减一
}
else
{
it->second--;
}
if(s[right] == s[left] && it->second < 0) //如果左边界和右边界的值相等且该值已经满足。
{
while(left < right)
{
auto its = cnt.find(s[left]); //its是否存在
if(its != cnt.end()) //当左边界下的字符在哈希表中找到时
{
if(cnt[s[left]] < 0) //且数值小于0时
cnt[s[left]]++; //令其自增
else //如果大于0时,说明不能再让左边界右移
break; //结束循环
}
left++;
}
}
if(count == t.length()) //如果符合的数量达到t串长度
{
int dis = right - left + 1; //当前串长度
if(dis < res.length() || res.empty()) //且未被初始化或长度大于当前串
res = s.substr(left, dis); //将当前串赋给结果串
cnt[s[left++]]++; //左边界下的字符数加一
count--; //符合字符数减一
while(left < right)
{
auto its = cnt.find(s[left]); //its是否存在
if(its != cnt.end()) //当左边界下的字符在哈希表中找到时
{
if(cnt[s[left]] < 0) //且数值小于0时
cnt[s[left]]++; //令其自增
else //如果大于0时,说明不能再让左边界右移
break; //结束循环
}
left++;
}
}
}
else //若右边界中的字符不存在t中时
{
if(left == right) //且左右边界指向同一点时
left++; //左右边界同时向右移动
}
}
return res;
}
};
螺旋矩阵Ⅱ
59.螺旋矩阵 Ⅱ
2023/8/10
一开始写的乱七八糟,瞄了一眼题解一下就透彻了。
是我自己想的太复杂了,还是菜啊 ,还是要多练。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
int t = 0;
int b = n - 1;
int l = 0;
int r = n - 1;
int k = 1;
vector<vector<int>> res(n, vector<int>(n));
while(k <= n * n)
{
for(int i = l; i <= r; i++, k++)
res[t][i] = k;
t++;
for(int i = t; i <= b; i++, k++)
res[i][r] = k;
r--;
for(int i = r; i >= l; i--, k++)
res[b][i] = k;
b--;
for(int i = b; i >= t; i--, k++)
res[i][l] = k;
l++;
}
return res;
}
};
54.螺旋矩阵
2023/8/10
和上一道题大差不差。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
int t = 0;
int l = 0;
int r = matrix[0].size() - 1;
int d = matrix.size() - 1;
int start = 0;
int end = (r+1) * (d+1);
vector<int> k(end);
while(start < end)
{
for(int i = l; i <= r && start < end; i++, start++)
k[start] = matrix[t][i];
t++;
for(int i = t; i <= d && start < end; i++, start++)
k[start] = matrix[i][r];
r--;
for(int i = r; i >= l && start < end; i--, start++)
k[start] = matrix[d][i];
d--;
for(int i = d; i >= t && start < end; i--, start++)
k[start] = matrix[i][l];
l++;
}
return k;
}
};
剑指 Offer 29.顺时针打印矩阵
2023/8/10
和上一道题几乎一摸一样,唯一的区别就是有一个空矩阵。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
if(matrix.empty())
return {};
int t = 0;
int l = 0;
int r = matrix[0].size() - 1;
int d = matrix.size() - 1;
int start = 0;
int end = (r+1) * (d+1);
vector<int> k(end);
while(start < end)
{
for(int i = l; i <= r && start < end; i++, start++)
k[start] = matrix[t][i];
t++;
for(int i = t; i <= d && start < end; i++, start++)
k[start] = matrix[i][r];
r--;
for(int i = r; i >= l && start < end; i--, start++)
k[start] = matrix[d][i];
d--;
for(int i = d; i >= t && start < end; i--, start++)
k[start] = matrix[i][l];
l++;
}
return k;
}
};
总结
链表
移除链表元素
203.移除链表元素
2023/8/11
好久没有接触链表了,一开始还没写对。
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* node = new ListNode(1);
node->next = head;
ListNode* node_next = node;
while(node_next->next != NULL)
{
if(node_next->next->val == val)
node_next->next = node_next->next->next;
else
node_next = node_next->next;
}
return node->next;
}
};
设计链表
707.设计链表
2023/8/14
好久不用链表了,写的满头包,错了好几次。
typedef struct ListNode
{
int val;
ListNode* next = NULL;
ListNode(int x): val(x), next(NULL){}
}ListNode;
class MyLinkedList {
public:
MyLinkedList() {
this->head = new ListNode(0);
}
int get(int index) {
ListNode* node = this->head;
int size = this->head->val;
if(size <= index)
return -1;
for(int i = 0; i <= index; i++)
node = node->next;
return node->val;
}
void addAtHead(int val) {
ListNode* node = new ListNode(val);
node->next = this->head->next;
this->head->next = node;
this->head->val++;
}
void addAtTail(int val) {
ListNode* node = new ListNode(val);
ListNode* n = this->head;
while(n->next != NULL)
n = n->next;
n->next = node;
this->head->val++;
}
void addAtIndex(int index, int val) {
int size = this->head->val;
ListNode* node = new ListNode(val);
if(size < index)
return;
ListNode* n = this->head;
for(int i = 0; i < index; i++)
n = n->next;
node->next = n->next;
n->next = node;
this->head->val++;
}
void deleteAtIndex(int index) {
if(index < 0 || index >= this->head->val)
return;
ListNode* n = this->head;
for(int i = 0; i < index; i++)
n = n->next;
n->next = n->next->next;
this->head->val--;
}
private:
ListNode* head;
};
翻转链表
206.反转链表
2023/8/15
很简单,稍微捋一下思路就可以,一遍过。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* re = new ListNode();
while(head != nullptr)
{
ListNode* node = new ListNode(head->val, re->next);
re->next = node;
head = head->next;
}
return re->next;
}
};
两两交换链表中的节点
24.两两交换链表中的节点
2023/8/15
还行,不是很难,就是要注意给指针赋值。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution{
public:
ListNode* swapPairs(ListNode* head){
ListNode* hd = new ListNode(0, head);
ListNode* h = hd;
ListNode* p = head;
while(p != nullptr)
{
ListNode* q = p->next;
if(q != nullptr)
{
p->next = q->next;
q->next = p;
h->next = q;
h = p;
p = p->next;
}
else
break;
}
return hd->next;
}
};
删除链表的倒数第N个节点
19.删除链表的倒数第N个节点
2023/8/15
快慢指针也很方便,也有算链表长度的函数,我没用。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* h = new ListNode(0, head);
ListNode* node = h;
int num = 0;
while(node->next != nullptr)
{
node = node->next;
num++;
}
node = h;
for(int i = 0; i < num - n; i++)
node = node->next;
node->next = node->next->next;
return h->next;
}
};
链表相交
面试题 02.07.链表相交
2023/8/15
还行,不难。
class Solution {
public:
int getLength(ListNode* node)
{
int num = 0;
while(node != nullptr)
{
node = node->next;
num++;
}
return num;
}
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* na = headA;
ListNode* nb = headB;
int a = getLength(na);
int b = getLength(nb);
if(a == 0 || b == 0)
return nullptr;
na = headA;
nb = headB;
for(; b > a; b--)
nb = nb->next;
for(; a > b; a--)
na = na->next;
while(na != nullptr)
{
if(na == nb)
break;
na = na->next;
nb = nb->next;
}
return na;
}
};
环形链表Ⅱ
142.环形链表Ⅱ
2023/8/16
这道题一共有三种做法:
第一种是我的暴力
第二种是哈希数组,使用unordered_set来指定唯一指针。
第三种是快慢指针,这个有点意思,需要用笔计算一下公式,前列推荐看一下。
typedef struct ListNode{
int val;
ListNode* next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
}ListNode;
class Solution{
public:
ListNode* detectCycle(ListNode* head){
ListNode* h = new ListNode;
h->next = head;
ListNode* node = h;
while(node->next != nullptr)
{
node = node->next;
if(node->next != nullptr)
{
if(node == node->next)
return node;
ListNode* n = head;
while(n != node)
{
if(node->next == n)
return n;
n = n->next;
}
}
else
break;
}
return nullptr;
}
};
总结
哈希表
有效的字母异位词
242.有效的字母异位词
2023/8/16
题目不难,就是忘了有关map的函数而已
class Solution{
public:
bool isAnagram(string s, string t) {
if (s.length() != t.length()) {
return false;
}
unordered_map<char, int> m;
for(int i = 0; i < s.length(); i++)
m[s[i]]++;
for(int i = 0; i < t.length(); i++)
{
m[t[i]]--;
if(m[t[i]] == 0)
m.erase(t[i]);
}
if(m.empty())
return true;
else
return false;
}
};
383.赎金信
2023/8/16
说实话,和上一道题没啥区别
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
unordered_map<char, int> map;
for(auto i : magazine)
map[i]++;
for(auto i : ransomNote)
{
map[i]--;
if(map[i] < 0)
return false;
}
return true;
}
};
49.字母异位词分组
2023/8/16
本题主要就是考察对map和vector使用的熟练程度。
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>> res;
unordered_map<string, vector<string>> map;
for(auto s : strs){
string key = s;
sort(key.begin(), key.end());
map[key].push_back(s);
}
for(const auto& m : map)
res.push_back(m.second);
return res;
}
};
438.找到字符串中所有字母异位词
2023/8/16
双指针,滑动窗口,具体实现的时候细心一点就好。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
unordered_map<char, int> map;
unordered_map<char, int> key;
vector<int> res;
int left = 0, right = 0;
for(auto str : p)
map[str]++;
key = map;
while(right < int(s.length())) //右指针不越界
{
auto iter = map.find(s[right]); //能否在key中找到字符
if(iter == map.end()) //找不到
{
right++; //右指针指向下一个
left = right; //左指针指向右指针
key = map; //重置key
}
else //找得到
{
key[s[right]]--; //减少该关键字下的数值
while(key[s[right]] < 0) //如果右指针指向的字符小于零了
{
key[s[left]]++; //把左指针上的字符加一
left++; //把左指针右移
} //直到右指针上的字符归零
if(key[s[right]] == 0) //如果恰好归零
key.erase(s[right]); //移除该字符
if(key.empty()) //如果空了
{ //说明异位词出现了
res.push_back(left); //左指针加入res
key[s[left]]++; //令左指针上的字符加一
left++; //左指针右移
}
right++; //右指针右移
}
}
return res;
}
};
两个数组的交集
349.两个数组的交集
2023/8/16
很简单,不多说了
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
vector<int> res;
unordered_set<int> num;
for(auto n : nums1)
num.insert(n);
for(auto n : nums2)
{
if(num.count(n) != 0)
{
num.erase(n);
res.emplace_back(n);
}
}
return res;
}
};
350.两个数组的交集Ⅱ
2023/8/16
和上一道题相比较,就是把set改成map,区别不大。
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
vector<int> res;
unordered_map<int, int> num;
for(auto n : nums1)
num[n]++;
for(auto n : nums2)
{
if(num[n] > 0)
{
res.emplace_back(n);
num[n]--;
}
}
return res;
}
};
快乐数
202.快乐数
2023/8/17
还行,不难
还可以用双指针去做,双指针能破有关循环的东西。
class Solution {
public:
bool isHappy(int n) {
unordered_set<int> num;
while(num.count(n) == 0)
{
vector<int> res;
num.emplace(n);
while(n != 0)
{
res.emplace_back( n % 10);
n = n / 10;
}
for(auto i : res)
n += i * i;
if(n == 1)
return true;
}
return false;
}
};
两数之和
1.两数之和
2023/8/19
好像脑子秀逗了,竟然没做出来,看了题解,很简单啊。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> map;
for(int i = 0; i < nums.size(); i++)
{
auto it = map.find(target - nums[i]);
if(it != map.end())
return {it->second, i};
map[nums[i]] = i;
}
return {};
}
};
四数相加Ⅱ
454.四数相加Ⅱ
2023/8/21
一开始没想到,想到了以后还是蛮简单的。
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> m;
int nums = 0;
for(auto i : nums1)
{
for(auto j : nums2)
m[i + j]++;
}
for(auto i : nums3)
{
for(auto j : nums4)
{
auto it = m.find(0 - i -j);
if(it != m.end())
{
nums += it->second;
}
}
}
return nums;
}
};
赎金信
前面做过了
三数之和
15.三数之和
2023/8/22
目前做过的感觉最有难度的一道题,也是自己比较菜,稍微复杂一点就想不出来了。
最后看的题解,连一次成功的提交都没有完成。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
unordered_map<int, int> m;
int len = nums.size();
int k = 0;
int n = 0;
sort(nums.begin(), nums.end());
for(auto k = 0; k < len - 2 && nums[k] <= 0; k++){
if(k > 0 && nums[k] == nums[k - 1]){
continue;
}
int i = k + 1;
int j = len - 1;
while(i < j){
int sum = nums[k] + nums[i] + nums[j];
if(sum < 0){
while(i < j && nums[i] == nums[++i]);
} else if (sum > 0){
while(i < j && nums[j] == nums[--j]);
} else {
res.push_back({nums[k], nums[i], nums[j]});
while(i < j && nums[i] == nums[++i]);
while(i < j && nums[j] == nums[--j]);
}
}
}
return res;
}
};
四数之和
18.四树之和
2023/8/23
比三数之和多了一重循环而已,注意溢出的问题。
class Solution{
public:
vector<vector<int>> fourSum(vector<int>& nums, int target){
vector<vector<int>> res;
int len = nums.size();
int a = 0;
sort(nums.begin(), nums.end());
for(; a + 3 < len;a++)
{
if(a > 0 && nums[a] == nums[a - 1])
{
continue;
}
for(auto b = a + 1; b < len - 2; b++)
{
if(b > a + 1 && nums[b] == nums[b - 1])
{
continue;
}
int c = b + 1;
int d = len - 1;
while(c < d)
{
auto sum = (long)nums[a] + nums[b] + nums[c] + nums[d];
if(sum < target)
{
while(c < d && nums[c] == nums[++c]);
} else if (sum > target)
{
while(c < d && nums[d] == nums[--d]);
} else
{
res.push_back({nums[a], nums[b], nums[c], nums[d]});
while(c < d && nums[c] == nums[++c]);
while(c < d && nums[d] == nums[--d]);
}
}
}
}
return res;
}
};