【数据结构】03双指针

Q1: 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例 1:

输入:s = [“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
设置双指针,i指首,j指尾

void reverseString(char* s, int sSize) {

    int i, j;
    for(i=0, j=sSize-1; i<(int)(sSize/2); i++,j--){
        char temp = s[i];
        s[i] = s[j];
        s[j] = temp;
    }
    
}

Q2: 数组拆分

给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) ,使得从 1 到 n 的 min(ai, bi) 总和最大。

返回该 最大总和 。

示例 2:

输入:nums = [6,2,6,5,1,2]
输出:9
解释:最优的分法为 (2, 1), (2, 5), (6, 6). min(2, 1) + min(2, 5) + min(6, 6) = 1 + 2 + 6 = 9

int sort(const void* a, const void* b) {
    int q = *(int*)a;
    int p = *(int*)b;
    return q - p;
}
int arrayPairSum(int* nums, int numsSize) {

    qsort(nums, numsSize, sizeof(int), sort);

    int sum = 0 ;
    int i, j;
    for(i=0, j=1; j<numsSize; i+=2,j+=2){
        sum += fmin(nums[i], nums[j]);
    }

    return sum;


}

从小到大排序,连续两两求min累加。
优化: 排序后求下标为偶数的和。

Q3:两数之和 II - 输入有序数组

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

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

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

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

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* numbers, int numbersSize, int target, int* returnSize) {

    int* result = (int *)malloc(sizeof(int)*2);

    int i=0, j= numbersSize-1;
    bool flag=1;

    while( i<numbersSize ,j>0 ){
        if(numbers[i] + numbers[j] > target){
            j--;
        }
        else if(numbers[i] + numbers[j] < target){
            i++;
        }
        else{
            break;
        }
    }
    //printf("numbers[%d] : %d, numbers[%d] : %d\n", i, numbers[i], j, numbers[j]);

    result[0] = i+1;
    result[1] = j+1;
    *returnSize = 2;
    return result;
    
}

i指首,j指尾。 若n[i]+n[j] < target, i++; 若n[i]+n[j]>target, j–。

Q4: 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

int removeElement(int* nums, int numsSize, int val) {

    int fast= 0, slow=0;
    while(fast<numsSize){
        if(nums[fast] != val){
            nums[slow] = nums[fast];
            slow++;
        }
        fast++;
    }

    return slow;
    
}

使用快慢指针,快指针遍历数组,慢指针指向要填入的元素的位置,只有快指针指向的元素不等于目标值时,慢指针才能移动。

Q5: 最大连续1的个数

给定一个二进制数组 nums , 计算其中最大连续 1 的个数。

示例 1:

输入:nums = [1,1,0,1,1,1]
输出:3
解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.

int findMaxConsecutiveOnes(int* nums, int numsSize) {

    int fast=0, slow=-1;
    int sum =0; 
    while(fast < numsSize){
        
        if(nums[fast]==0){

            slow = fast;
            

        }
       
        
        fast++;

        sum = fmax(sum, fast-slow-1);

    }
   

    return sum;

    
}

快指针遍历数组,当快指针指向0时,满指针才做移动,移动到快指针的位置。每次快指针移动时都记录长度:快指针-慢指针。对应连续1的个数。

Q6: 长度最小的子数组

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

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

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

int minSubArrayLen(int target, int* nums, int numsSize) {
    int slow=0, fast=0;
    int min = 0;
    int sum=0;
    for(fast=0; fast<numsSize; fast++){
        
        sum = sum + nums[fast];
        if(sum >= target){
            while(sum - nums[slow] >= target){  //收缩慢指针的条件
                sum = sum -nums[slow];  //收缩慢指针
                slow++;
            }
            //min = (min===0)?(fast - slow + 1):fmin(min,fast - slow + 1); 
            if(min ==0){
                min = (fast - slow + 1);

            }
            else{
                min = fmin(min,fast - slow + 1);
            }
            //更新最小值,注意min为0时需要初始化min
        }
        


    }

    return min;
    
}

慢指针指向区间前端, 快指针指向后端。
快指针先移动到大于目标值的位置,让慢指针收缩。

你可能感兴趣的:(C\C++,数据结构)