4.Triplet Sum to Zero or Three sum(medium)
问题描述
给定一个未排序的数组,找出其中所有唯一的三元组加起来为零。
Example 1:
Input: [-3, 0, 1, 2, -1, 1, -2]
Output: [-3, 1, 2], [-2, 0, 2], [-2, 1, 1], [-1, 0, 1]
Explanation: There are four unique triplets whose sum is equal to zero.
Example 2:
Input: [-5, 2, -1, -2, 3]
Output: [[-5, 2, 3], [-2, -1, 3]]
Explanation: There are two unique triplets whose sum is equal to zero.
解题的关键:
这题挺经典
1.简单来说就是我们先确定一个数A,然后在剩下数里面找到两个数(B与C)来满足题目的要求(A+B+C=target)。但如果直接在剩下的数中找的话复杂度太高了,而且还存在重复的数的情况,所以先排序,然后再进行上述操作即可,后面的部分跟我们前面做的题目思路是一样的
vector<vector<int> > threeSum(vector<int> &num) {
vector<vector<int> > res;
sort(num.begin(), num.end());
for (int i = 0; i < num.size(); i++) {
//处理一下重复的数
while (i + 1 < num.size() && num[i + 1] == num[i]) i++;
int target = -num[i];
int front = i + 1;
int back = num.size() - 1;
while (front < back) {
}
int sum = num[front] + num[back];
if (sum < target)
front++;
else if (sum > target)
back--;
else {
vector<int> triplet = {num[i], num[front], num[back]};
res.push_back(triplet);
while (front < back && num[front] == triplet[1]) front++;
while (front < back && num[back] == triplet[2]) back--;
}
}
return res;
}
5.Triplet Sum Close to Target (medium)
问题描述
给定一个未排序数的数组和一个目标数,在数组中找到一个和尽可能接近目标数的三元组,返回三元组的和。 如果有多个这样的三元组,则返回总和最小的三元组的总和。
Example 1:
Input: [-2, 0, 1, 2], target=2
Output: 1
Explanation: The triplet [-2, 1, 2] has the closest sum to the target.
Example 2:
Input: [-3, -1, 1, 2], target=1
Output: 0
Explanation: The triplet [-3, 1, 2] has the closest sum to the target.
Example 3:
Input: [1, 0, 1, 1], target=100
Output: 3
Explanation: The triplet [1, 1, 1] has the closest sum to the target.
解题的关键:
1.大体思路和上题是相同的,但是要有一个数来保存并更新与target最小的差距
static int searchTriplet(vector<int>& arr, int targetSum) {
sort(arr.begin(), arr.end());
int smallestDifference = numeric_limits<int>::max();
for (int i = 0; i < arr.size() - 2; i++) {
int left = i + 1, right = arr.size() - 1;
while (left < right) {
//计算和目标的差距
int targetDiff = targetSum - arr[i] - arr[left] - arr[right];
if (targetDiff == 0) {
// 如果找到三个数和目标相等,直接返回即可
return targetSum;
}
//更新最小的差距,注意我们需要返回的是差距最小的三个数的和
//return target-最小的差距 = 差距最小的三个数和,所以要保证smallestDifference 是正数
if (abs(targetDiff) < abs(smallestDifference) ||
(abs(targetDiff) == abs(smallestDifference) && targetDiff > smallestDifference)) {
smallestDifference = targetDiff;
}
if (targetDiff > 0) {
left++; // we need a triplet with a bigger sum
} else {
right--; // we need a triplet with a smaller sum
}
}
}
return targetSum - smallestDifference;
}
6.Subarrays with Product Less than a Target (medium)
问题描述
给定一个具有正数和正目标数的数组,找到其乘积小于目标数的所有连续子数组。
Example 1:
Input: [2, 5, 3, 10], target=30
Output: [2], [5], [2, 5], [3], [5, 3], [10]
Explanation: There are six contiguous subarrays whose product is less than the target.
Example 2:
Input: [8, 2, 6, 5], target=50
Output: [8], [2], [8, 2], [6], [2, 6], [5], [6, 5]
Explanation: There are seven contiguous subarrays whose product is less than the target.
解题的关键:
1.注意是连续的子数组,所以不可以排序了。这题有点滑动窗口的意思了,窗口内的数的积小于target,然后窗口内的数的子数组依次放入即可,但窗口必须要向前移动,窗口收缩的时机就是窗口内的数的积大于等于target,这就需要一个数来计算窗口内数的积,窗口收缩时还得将窗口头部的数除去
2.窗口内的数的连续子数组依次放入是比较棘手的地方,我也就直接说解法了,因为这种东西我也想不出来,嗯背吧:
当窗口为[1,5]时此时解应该是{[1],[5],[1,5]}
当窗口为[1,5,3]时此时解应该是{[1],[5],[1,5],[3],[5,3],[1,5,3]} 所以,窗口内每多一个数后,要从窗口尾部来开始将子数组从一个到n个放入结果中[3],[5,3],[1,5,3]
vector<vector<int>> findSubarrays(const vector<int>& arr, int target) {
vector<vector<int>> result;
double product = 1;
int left = 0;
for (int right = 0; right < arr.size(); right++) {
product *= arr[right];
//窗口缩小
while (product >= target && left < arr.size()) {
product /= arr[left++];
}
deque<int> tempList;
//从窗口尾部开始,子数组的长度依次增大
for (int i = right; i >= left; i--) {
//保证顺序,所以得用双端队列,从头部插入
tempList.push_front(arr[i]);
vector<int> resultVec;
//将deque中的数放入resulvec中
move(begin(tempList), end(tempList), back_inserter(resultVec));
result.push_back(resultVec);
}
}
return result;
}
7.Dutch National Flag Problem (medium)
给定一个包含 0、1 和 2 的数组,对数组进行就地排序。 您应该将数组的数字视为对象,因此,我们不能计算 0、1 和 2 来重新创建数组。
荷兰国旗由红、白、蓝三种颜色组成; 由于我们的输入数组也包含三个不同的数字,这就是为什么它被称为荷兰国旗问题。
Example 1:
Input: [1, 0, 2, 1, 0]
Output: [0, 0, 1, 1, 2]
Example 1:
Input: [1, 0, 2, 1, 0]
Output: [0, 0, 1, 1, 2]
解题的关键:
1.可以先思考一下,一个数轴,我们可以用两个点把数轴分成三个部分,这道题也是同理,我们用两个指针就可以区分这三种数,而且找到前两种,第三种自然也就分好了,用low ,high 两个指针处理low左边的小于1,high右边的大于1
void sort(vector<int> &arr) {
int low = 0, high = arr.size() - 1;
for (int i = 0; i <= high;) {
if (arr[i] == 0) {
swap(arr, i, low);
i++;
low++;
} else if (arr[i] == 1) {
i++;
} else { // the case for arr[i] == 2
swap(arr, i, high);
// decrement 'high' only, after the swap the number at index 'i' could be 0, 1 or 2
high--;
}
}
}
7.Quadruple Sum to Target or 4Sum(medium)
问题描述
给出一个未排序的数组和一个目标数,找出其中所有唯一的四元数,其总和等于目标数。
Example 1:
Input: [4, 1, 2, -1, 1, -3], target=1
Output: [-3, -1, 1, 4], [-3, 1, 1, 2]
Explanation: Both the quadruplets add up to the target.
Example 2:
Input: [2, 0, -1, 1, -2, 2], target=2
Output: [-2, 0, 2, 2], [-1, 0, 1, 2]
Explanation: Both the quadruplets add up to the target.
解题的关键:
1.跟3sum一个思路,再加一层循环即可,两个循环确定两个数,双指针再确定一个数即可
2.重复数字处理不处理都可
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> total;
int n = nums.size();
if(n<4) return total;
sort(nums.begin(),nums.end());
for(int i=0;i<n-3;i++)
{
if(i>0&&nums[i]==nums[i-1]) continue;
if(nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target) break;
if(nums[i]+nums[n-3]+nums[n-2]+nums[n-1]<target) continue;
for(int j=i+1;j<n-2;j++)
{
if(j>i+1&&nums[j]==nums[j-1]) continue;
if(nums[i]+nums[j]+nums[j+1]+nums[j+2]>target) break;
if(nums[i]+nums[j]+nums[n-2]+nums[n-1]<target) continue;
int left=j+1,right=n-1;
while(left<right){
int sum=nums[left]+nums[right]+nums[i]+nums[j];
if(sum<target) left++;
else if(sum>target) right--;
else{
total.push_back(vector<int>{nums[i],nums[j],nums[left],nums[right]});
do{left++;}while(nums[left]==nums[left-1]&&left<right);
do{right--;}while(nums[right]==nums[right+1]&&left<right);
}
}
}
}
return total;
}
8.Comparing Strings containing Backspaces (medium)
问题描述
给出两个含有退格键的字符串(用字符’#'标识),检查这两个字符串是否相等。
Example 1:
Input: str1="xy#z", str2="xzz#"
Output: true
Explanation: After applying backspaces the strings become "xz" and "xz" respectively.
Example 2:
Input: str1="xy#z", str2="xyz#"
Output: false
Explanation: After applying backspaces the strings become "xz" and "xy" respectively.
Example 3:
Input: str1="xp#", str2="xyz##"
Output: true
Explanation: After applying backspaces the strings become "x" and "x" respectively.
In "xyz##", the first '#' removes the character 'z' and the second '#' removes the character 'y'.
Example 4:
Input: str1="xywrrmp", str2="xywrrmu#p"
Output: true
Explanation: After applying backspaces the strings become "xywrrmp" and "xywrrmp" respectively.
解题的关键:
1,直观来看,从前往后处理退格不方便,可以从尾部往前处理,而且不一定只有一个位置出现退格,所以要循环处理,不能只处理一次。从尾部开始碰到#开始计数,然后退格
int backspace(const string &str,int pos)
{
int count=0;
while(pos>=0)
{
if(str[pos]=='#') ++count;
else if(count >0) count--;
else
{
break;
}
--pos;
}
return pos;
}
bool comp(const string &str1,const string &str2)
{
int first =str1.size()-1;
int second = str2.size()-1;
while(first>=0 && second>=0)
{
int l1=backspace(str1,first);
int l2=backspace(str2,second);
//先处理后比较
if(l1<0 && l2<0) return true;
if(l1<0 && l2>0) return false;
if(l1>0 && l2<0) return false;
if(str1[l1]!=str2[l2]) return false;
first = l1-1;
second = l2-1;
}
return true;
}