【每日刷题】Day103
🥕个人主页:开敲🍉
🔥所属专栏:每日刷题🍍
🌼文章目录🌼
1. LCR 007. 三数之和 - 力扣(LeetCode)
3. 209. 长度最小的子数组 - 力扣(LeetCode)
1. LCR 007. 三数之和 - 力扣(LeetCode)
//思路:双指针。
//本题的思路确实难想,但是本题的重点不在于思路,而是在于细节的处理。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums)
{
vector<vector<int>> ans;
//按照升序排序
sort(nums.begin(),nums.end());
int n = nums.size();
//for循环,i作为每次固定位置的下标
for(int i = 0;i<n;)
{
//小优化,如果nums[i]已经>0了,那么后面的数也一定是>0的,则不可能有 == 0 的三元组。
if(nums[i]>0) break;
//left、right作为区间,target为固定值的相反数
int left = i+1,right = n-1,target = -nums[i];
while(left<right)
{
int sum = nums[left]+nums[right];
//右边数太大,right--
if(sum>target) right--;
//左边数太小,left++
else if(sum<target) left++;
//找到三元组,将三元组计入答案中,进行细节处理
else
{
ans.push_back({nums[left],nums[right],nums[i]});
left++;
right--;
//如果left遍历到与left-1相同的数,则必定会组成重复的三元组,直接跳过,同时需要防止越界
while(left<right&&nums[left]==nums[left-1]) left++;
//如果right遍历到与right+1相同的数,同上,直接跳过。
while(left<right&&nums[right]==nums[right+1]) right--;
}
}
//先让i++往下遍历
i++;
//如果i遍历到与i-1相同的数,与上述相同,直接跳过
while(i<n&&nums[i]==nums[i-1]) i++;
}
return ans;
}
};
2. 18. 四数之和 - 力扣(LeetCode)
//思路:与三数之和类似,区别在于三数之和是排序后固定一个数,而四树之和排序后固定两个数。
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target)
{
vector<vector<int>> ans;
int n = nums.size();
sort(nums.begin(),nums.end());
//两个for循环固定两个数
for(int i = 0;i<n-3;)
{
for(int j = i+1;j<n-2;)
{
int left = j+1;
int right = n-1;
//left和right双指针在区间内遍历查找
while(left<right)
{
//剩下步骤与 "三数之和" 一样
long long val_left = nums[left],val_right = nums[right],val_i = nums[i],val_j = nums[j];
long long sum = val_left+val_right+val_i+val_j;
if(sum>target)
right--;
else if(sum<target)
left++;
else
{
ans.push_back({nums[i],nums[j],nums[left],nums[right]});
left++;
right--;
while(left<right&&nums[left]==nums[left-1])
{
left++;
}
while(left<right&&nums[right]==nums[right+1])
{
right--;
}
}
}
j++;
while(j<n&&nums[j]==nums[j-1])
{
j++;
}
}
i++;
while(i<n&&nums[i]==nums[i-1])
{
i++;
}
}
return ans;
}
};
3. 209. 长度最小的子数组 - 力扣(LeetCode)
//思路:滑动窗口。滑动窗口是什么?上图
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int left = 0;
int right = -1;
//sum记录left与right区间内值的和
int sum = 0;
//ans用于记录最小长度
int ans = 10000000;
while(right!=nums.size())
{
//如果小于目标值,则当前子数组不符合,right继续遍历,left不动
if(sum<target)
{
right++;
//防止越界
if(right==nums.size())
break;
//记录区间和
sum+=nums[right];
}
else
{
//记录最小长度
ans = ans<(right-left+1)?ans:(right-left+1);
//记录left当前值
int tmp = nums[left];
left++;
//left向左移动,sum-=tmp
sum-=tmp;
}
}
//如果没有找到符合题意的子数组则返回0
if(ans==10000000)
ans = 0;
return ans;
}
};