力扣刷题D1

双向指针问题01

1.167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)

题解:1.暴力解法直接两层循环,复杂度为0(n^2)

2.利用双向指针(当a[0]+a[n-1]>target,说明a[1]+a[n-1]>target是必然事件)

cpp 复制代码
class Solution {//利用代码有序这一特点,利用两个相向的指针,将复杂度0(n^2)化为0(n)
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int n=numbers.size();
        int i=0;int j=n-1;
        while(i!=j){
            if(numbers[i]+numbers[j]>target)
                j--;
            else if (numbers[i]+numbers[j]<target)i++;
            else return {i+1,j+1};
        }
        return {-1,-1};
    }
};

2.15. 三数之和 - 力扣(LeetCode)

思路:三数之和等于target ,可以将其化为两数之和的问题(a+b+c=target==》a+b=target-c)

代码:

cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        // i != j、i != k 且 j != k 
        //整数数组 nums  无序--》有序
        //答案中不可以包含重复的三元组
        int n=nums.size();
        int i,j,k;//把i固定,用j,k来双向遍历
        //nums.sort();
        ranges::sort(nums);
        vector<vector<int>> ans;

        for(int i=0;i<n-2;i++){//i=n-3;j=n-2;k=n-1
            if(i&&nums[i]==nums[i-1])
              continue;//跳过重复元素
               int j = i + 1, k = n - 1;
            while(j<k){//这里因为后续回跳过重复元素,所以不能用不等号
                int sum=nums[i]+nums[j]+nums[k];
                if(sum>0) k--;
                else if(sum<0)j++;
                else {
                    ans.push_back({nums[i],nums[j],nums[k]});
                    for (j++; j < k && nums[j] == nums[j - 1]; j++); // 跳过重复数字
                    for (k--; k > j && nums[k] == nums[k + 1]; k--); // 跳过重复数字
                }
            }
            //if(nums[i]==nums[i+1])
              //  continue;//跳过重复元素
        }
        return ans;
    }
};

课后练习:

2824. 统计和小于目标的下标对数目

给你一个下标从 0 开始长度为 n 的整数数组 nums 和一个整数 target ,请你返回满足 0 <= i < j < nnums[i] + nums[j] < target 的下标对 (i, j) 的数目。

cpp 复制代码
class Solution {
public:
    int countPairs(vector<int>& nums, int target) {
     //开始长度为 n 的整数数组 nums,数组无序
     int ans=0;
     int n=nums.size();
     sort(nums.begin(),nums.end());
     int i=0,j=n-1;
     while(i<j){
        if(nums[i] + nums[j] < target){
            ans+=(j-i);//ans要加上j到i之内所有数字。
            i++;
            
        }
        else j--;
     }   
     return ans;
    }
};

ans 的增量应该是计算满足条件的所有下标对,而不仅仅是每次找到一个满足 nums[i] + nums[j] < target 的时候增加 1。

实际上,当前 ij 满足条件时,你需要计数 ij-1 之间的所有对。可以通过累加 j-i 来解决这个问题。

16. 最接近的三数之和 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        //三个数,转化为三数之和问题,最接近使用一个min_disum;
        sort(nums.begin(),nums.end());
        int n=nums.size();
        int i,j,k;
        int min_disum=INT_MAX;//用来定义和与target的差
        int sum=0;
        int ans;
        for(i=0;i<n-2;i++){
            j=i+1;k=n-1;
            while(j<k){
                sum=nums[i]+nums[j]+nums[k];
                min_disum=min(min_disum,abs(sum-target));
                if(min_disum==abs(sum-target)){
                     ans=sum;
                }
                if(min_disum==0)
                    return sum;
                else if(sum>target){
                    k--;
                }
                else {
                    j++;
                }
            }
        }
        return ans;
    }
};

18. 四数之和 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    vector<vector<int>> fourSum(vector<int> &nums, int target) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        int n = nums.size();
        for (int a = 0; a < n - 3; a++) { // 枚举第一个数
            long long x = nums[a]; // 使用 long long 避免溢出
            if (a > 0 && x == nums[a - 1]) continue; // 跳过重复数字
            if (x + nums[a + 1] + nums[a + 2] + nums[a + 3] > target) break; // 优化一
            if (x + nums[n - 3] + nums[n - 2] + nums[n - 1] < target) continue; // 优化二
            for (int b = a + 1; b < n - 2; b++) { // 枚举第二个数
                long long y = nums[b];
                if (b > a + 1 && y == nums[b - 1]) continue; // 跳过重复数字
                if (x + y + nums[b + 1] + nums[b + 2] > target) break; // 优化一
                if (x + y + nums[n - 2] + nums[n - 1] < target) continue; // 优化二
                int c = b + 1, d = n - 1;
                while (c < d) { // 双指针枚举第三个数和第四个数
                    long long s = x + y + nums[c] + nums[d]; // 四数之和
                    if (s > target) d--;
                    else if (s < target) c++;
                    else { // s == target
                        ans.push_back({(int) x, (int) y, nums[c], nums[d]});
                        for (c++; c < d && nums[c] == nums[c - 1]; c++); // 跳过重复数字
                        for (d--; d > c && nums[d] == nums[d + 1]; d--); // 跳过重复数字
                    }
                }
            }
        }
        return ans;
    }
};

对于 Java、C++ 等语言,注意相加结果可能会超过 32 位整数范围,需要用 64 位整数存储四数之和。

611. 有效三角形的个数 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        //有效三角形,a+b>c;a-b<c;
        sort(nums.begin(),nums.end());
        int n=nums.size();
        int i,j,k;
        int ans=0;
        //如果a+b>c;--->a+b+n>c;---->如果a,b>c,则会有b-a个
        for(k=n-1;k>1;k--){
            i=0;j=k-1;
            while(i<j){
                int sum=nums[i]+nums[j]-nums[k];
                if(sum>0){
                    ans=ans+j-i;
                    j--;//sum应该变小
                }
                else //sum<0;数应该变大;
                    i++;
            }
        }
        return ans;
        
    }
};
相关推荐
Solitudefire35 分钟前
蓝桥杯刷题——day6
职场和发展·蓝桥杯
一行玩python39 分钟前
PugiXML,一个高效且简单的 C++ XML 解析库!
xml·开发语言·c++·算法
Sunyanhui11 小时前
牛客网 SQL1查询所有列
c++·算法
所有向日癸上升1 小时前
问题 C: B001 快乐的蠕虫
c语言·开发语言·算法
Cooloooo2 小时前
二叉搜索树Ⅲ【东北大学oj数据结构8-3】C++
数据结构·c++·算法
互联网杂货铺2 小时前
单元测试总结
自动化测试·软件测试·python·测试工具·职场和发展·单元测试·测试用例
sjsjs114 小时前
【多维DP】力扣2370. 最长理想子序列
算法·leetcode·动态规划
在西湖雾雨中起舞4 小时前
题目 2834: 与指定数字相同的数的个数
数据结构·c++·算法
抓个马尾女孩4 小时前
Python中列表复制A=B和A=B[:]的区别
数据结构·python·算法
陌繁4 小时前
LeetCode1.两数之和(超简单讲解)
数据结构·算法·leetcode