数据结构-线性表(数组)-双指针->数组逼近(左右指针)167 & 15* & 18 &11*

标题带星号是很重要的题

什么时候用两个指针进行数组逼近?

目前来看,当顺序表有序,进行查找一个等于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;
    }
  • 总结
    双指针用于处理为排序的序列时,要确定好每一步那个指针移动。非常重要。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线性表是一种常见的数据结构,它表示具有相同数据类型的一组元素的有序序列。线性表中的元素之间存在一种顺序关系,每个元素都有一个前驱和一个后继(除了第一个元素没有前驱,最后一个元素没有后继)。线性表可以用顺序存储结构或链式存储结构实现。 在顺序存储结构中,线性表的元素按照顺序存储在连续的内存空间中,可以通过元素的下标来访问和操作元素。插入或删除元素时,需要移动其他元素,因此操作的时间复杂度较高。 链式存储结构中,线性表的每个元素都包含一个数据域和一个指针域,指针指向下一个元素。通过指针的链接,元素可以按照任意顺序存储在内存中,插入和删除操作只需要改变指针的指向,因此时间复杂度较低。 线性表常见的操作包括插入、删除、查找、获取长度等。其中插入和删除操作需要注意保持线性表的顺序关系。 常见的线性表数组、链表、栈和队列。数组是最简单的线性表,通过下标可以直接访问元素;链表是动态存储结构,插入和删除操作方便,但访问元素需要遍历链表;栈是一种特殊的线性表,只允许在表的一端进行插入和删除操作;队列也是一种特殊的线性表,只允许在表的一端进行插入操作,在另一端进行删除操作。这些数据结构在实际应用中都有各自的应用场景和优缺点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值