标题带星号是很重要的题
什么时候用两个指针进行数组逼近?
目前来看,当顺序表有序,进行查找一个等于XX值时可以用。有序+查找 同样可以想到二分查找。
167.两数之和 II - 输入有序数组
- 思路
我的思路:从数组两端逼近target,左右指针指向元素和大于target,则右指针左移;反之,左值针右移。
其他:确定一个元素,找target-nums[i],有序数组,二分查找。 - 代码
我的做法:
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int len = numbers.size();
int left = 0,right = len-1;
while(left < right){
if(numbers[left]+numbers[right] > target) --right;
else if(numbers[left]+numbers[right] < target) ++left;
else break;
}
return {left+1,right+1};
}
};
二分查找:
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int len = numbers.size();
int temp = 0,j = 0,i = 0;
for(i;i<len;++i){
temp = target - numbers[i];
int left = i+1,right = len-1;
while(left<=right){
int mid = left + (right-left)/2;
if(numbers[mid]>temp) right = mid - 1;
else if(numbers[mid]<temp) left = mid + 1;
else {j = mid;return {i+1,j+1};}
}
if(j != 0) break;
}
return {i+1,j+1};
}
};
- 总结学习
hash表可用来对无序数组进行查找,有序数组要想到二分法和双指针。
15三数之和
- 思路
为什么进行排序:避免计算重复
我没做出来的原因:题目要求不重复,我没有想到对数组排序后可能相邻元素有重复的。
重点:对相邻元素去重 continue关键字
第二遍做:
首先想到了 确定前两个数,用二分法找第三个数。但是没有想到先确定一个数然后双指针左右逼近。
- 代码
vector<vector<int>> threeSum(vector<int>& nums) {
int len = nums.size();
sort(nums.begin(),nums.end());
vector<vector<int>> res;
int left = 0,right = 0;
int i = 0;
for(i; i<len; ++i){
if(i>0 && nums[i] == nums[i-1]) continue;//去重
left = i + 1;
right = len - 1;
while(left<right){
//每个值判断一次,不能并列三个if(因为这样第一个if判断完就会在以后if进行判断),
if(nums[left]+nums[right]>(-nums[i])) --right;
else if(nums[left]+nums[right]<-nums[i]) ++left;
else {
res.push_back({nums[i],nums[left],nums[right]});
//去重,先将指针指向下一个数,再判断指针当前的值与上一个值是不是相同
++left;
--right;
//必须是while
while(left<right && nums[left-1] == nums[left]) ++left;
while(left<right && nums[right+1] == nums[right]) --right;
}
}
}
return res;
}
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
int len = nums.size();
vector<vector<int>> res;
if(len<2) return res;
for(int i = 0;i<len-1;i++){
if(i>0 && nums[i-1]==nums[i]) continue;
for(int j = i+1;j<len;j++){
if(j>i+1 && nums[j-1]==nums[j]) continue;
int right = len-1;
int left = j+1;
while(left<=right){
int mid = left + (right-left)/2;
if(nums[mid]>-(nums[i]+nums[j])){
right = mid - 1;
}else if(nums[mid]<-(nums[i]+nums[j])){
left = mid + 1;
}else{
res.push_back({nums[i],nums[j],nums[mid]});
break;
}
}
}
}
return res;
}
};
- 总结
双指针方法对,但是要会再加点别的,比如本题的去重。
18.四数之和
int类型 -2147483648 ~ 2147483647
cout << sizeof(int) << endl;//4
cout << sizeof(long) << endl;//4
cout << INT_MAX << endl;// 2^15 -1 = 2147483647
cout << LONG_MAX << endl;//2147483647
cout << UINT16_MAX << endl;//2^16-1 = 65535
cout << UINT32_MAX << endl;//2^32 -1 = 4294967295
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
int len = nums.size();
sort(nums.begin(),nums.end());
vector<vector<int>> res;
for(int i = 0;i<len-1;++i){
if(i>0 && nums[i] == nums[i-1]) continue;
for(int j = i+1;j<len;++j){
if(j>i+1 && nums[j] == nums[j-1]) continue;
int left = j + 1;
int right = len - 1;
while(left < right){
if((long)nums[left]+nums[right]+nums[i]+nums[j] < target) ++left;
else if((long)nums[left]+nums[right]+nums[i]+nums[j] > target) --right;
else{
res.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;
}
}
}
}
return res;
}
};
11. 盛最多水的容器
- 思路
为什么用双指针?
左右指针正好表示两个板子。
如何移动指针?
哪个指针表示的数比较小,就移动哪个。(不解释,希望下次做的时候能自己想到) - 代码
int maxArea(vector<int>& height) {
int len = height.size();
int left = 0;
int right = len-1;
int area = 0,max_area = 0;
int lens = 0;
while(left<right){
lens = right - left;
area = lens * min(height[right],height[left]);
if(area>max_area) max_area = area;
if(height[left] > height[right]) --right;
else ++left;
}
return max_area;
}
- 总结
双指针用于处理为排序的序列时,要确定好每一步那个指针移动。非常重要。