刷题11 双指针

一、同向双指针


209. 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3]
输入:target = 4, nums = [1,4,4]
输出:1
int minSubArrayLen(int target, int* nums, int numsSize) {
    int l=0,r=0;
    int sum=0;
    int ans=INT_MAX;
    while(r=target){
            ans=fmin(ans,r-l+1);
            sum-=nums[l];
            l++;
        }
        r++;
    }
    return ans==INT_MAX?0:ans;
}


713. 乘积小于 K 的子数组

给你一个整数数组 nums 和一个整数 k ,请你返回子数组内所有元素的乘积严格小于 k 的连续子数组的数目。

输入:nums = [10,5,2,6], k = 100
输出:8
解释:8 个乘积小于 100 的子数组分别为:[10]、[5]、[2],、[6]、[10,5]、[5,2]、[2,6]、[5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于 100 的子数组。
int numSubarrayProductLessThanK(int* nums, int numsSize, int k) {
    int l=0,r=0;
    int sum=1;
    int ans=0;
    while(r=k){
            sum/=nums[l];
            l++;
        }
        ans+=r-l+1;
        r++;
    }
    return ans;
}


LCR 016. 无重复字符的最长子串

 给定一个字符串 s ,请你找出其中不含有重复字符的 最长连续子字符串 的长度。

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子字符串是 "abc",所以其长度为 3。
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子字符串是 "b"所以其长度为 1。

        此题不是只有字母,因此无法通过,有除字母以外的字符之外出现的话需要用map进行记录。 

int lengthOfLongestSubstring(char * s){
    if(s=="") return 0;
    int flag[128]={0};
    int l=0,r=0;
    int ans=0;
    int n=strlen(s);
    while(r1){
            flag[s[l]-'a']--;
            l++;
        }  
        if(l

        c++版本:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n=s.size();
        int left=0;
        int answer=0;
        set st;
        for(int right=0;right


1574. 删除最短的子数组使剩余数组有序

 给你一个整数数组 arr ,请你删除一个子数组(可以为空),使得 arr 中剩下的元素是 非递减 的。一个子数组指的是原数组中连续的一个子序列。请你返回满足题目要求的最短子数组的长度。

输入:arr = [1,2,3,10,4,2,3,5]
输出:3
解释:我们需要删除的最短子数组是 [10,4,2] ,长度为 3 。剩余元素形成非递减数组 [1,2,3,3,5] 。
另一个正确的解为删除子数组 [3,10,4] 。
int findLengthOfShortestSubarray(int* arr, int arrSize){
    int r=arrSize-1;
    while(r&&arr[r-1]<=arr[r]){
        r--;
    }
    //当前数列已经是递增的
    if(r==0) return 0;
    int ans=r;
    //枚举左区间起点
    for(int l=0;l==0||arr[l-1]<=arr[l];++l){
        while(r


1004. 最大连续1的个数 III

 给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个 0 ,则返回 数组中连续 1 的最大个数 。

输入:nums = [1,1,1,0,0,0,1,1,1,1,0], K = 2
输出:6
解释:[1,1,1,0,0,1,1,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 6。
输入:nums = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
输出:10
解释:[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 10。
int longestOnes(int* nums, int numsSize, int k) {
    int l=0,r=0;
    int zero=0;
    int ans=0;
    while(rk){
            if(nums[l]==0) zero--;
            l++;
        }
        ans=fmax(ans,r-l+1);
        r++;
    }
    return ans;
}


1234. 替换子串得到平衡字符串

 有一个只含有 'Q', 'W', 'E', 'R' 四种字符,且长度为 n 的字符串。

假如在该字符串中,这四个字符都恰好出现 n/4 次,那么它就是一个「平衡字符串」。给你一个这样的字符串 s,请通过「替换一个子串」的方式,使原字符串 s 变成一个「平衡字符串」。

你可以用和「待替换子串」长度相同的 任何 其他字符串来完成替换。请返回待替换子串的最小可能长度。如果原字符串自身就是一个平衡字符串,则返回 0

输入:s = "QWER"
输出:0
解释:s 已经是平衡的了。
输入:s = "QQWE"
输出:1
解释:我们需要把一个 'Q' 替换成 'R',这样得到的 "RQWE" (或 "QRWE") 是平衡的。
int balancedString(char* s) {
    int hash[26]={0};
    int l=0,r=0;
    int len=strlen(s);
    int n=len/4;
    int ans=len;
    //记录每个字母出现的次数
    for(int i=0;i


1658. 将 x 减到 0 的最小操作数

 给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -1 。

输入:nums = [1,1,4,2,3], x = 5
输出:2
解释:最佳解决方案是移除后两个元素,将 x 减到 0 。

方法一:逆向思维+双指针
把问题转换成「从 nums 中移除一个最长的子数组,使得剩余元素的和为 x。换句话说,要从 nums 中找最长的子数组,其元素和等于 s−x,这里 s 为 nums 所有元素之和。

int minOperations(int* nums, int numsSize, int x) {
    //从nums中移除一个最长的子数组,使得剩余元素的和为x
    int target=0;
    for(int i=0;itarget){
            sum-=nums[l];
            l++;
        }
        if(sum==target){
            ans=fmax(ans,r-l+1);
        }
    }
    return ans<0?-1:numsSize-ans;
}

二、对撞双指针


15. 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
class Solution {
public:
    vector> threeSum(vector& nums) {
         vector> result;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size(); i++) {
            // 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
            if (nums[i] > 0) {
                return result;
            }
            if (i > 0 && nums[i] == nums[i - 1]) {//去重
                continue;
            }
            int left = i + 1;
            int right = nums.size() - 1;
            while (right > left) {
                if (nums[i] + nums[left] + nums[right] > 0) right--;
                else if (nums[i] + nums[left] + nums[right] < 0) left++;
                else {
                    result.push_back(vector{nums[i], nums[left], nums[right]});
                    // 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
                    while (right > left && nums[right] == nums[right - 1]) right--;
                    while (right > left && nums[left] == nums[left + 1]) left++;
                    // 找到答案时,双指针同时收缩
                    right--;
                    left++;
                }
            }

        }
        return result;
    }
};


167. 两数之和 II - 输入有序数组

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列  ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1  index2

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
int* twoSum(int* numbers, int numbersSize, int target, int* returnSize) {
    int *res=malloc(sizeof(int)*2);
    *returnSize=2;
    int l=0,r=numbersSize-1;
    while(ltarget){
            r--;
        }else{
            res[0]=l+1;res[1]=r+1;
            return res;
        }
    }
    return res;
}


11. 盛最多水的容器

 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
int maxArea(int* height, int heightSize) {
    int mmax=0;
    int i=0,j=heightSize-1;
    while(immax) mmax=cur;
        if(height[i]

你可能感兴趣的:(leetcode刷题打卡,数据结构)