代码随想录笔记--数组篇

目录

1--二分查找法

2--二分查找法进阶

2-1--寻找第一个等于目标值的位置

2-2--寻找最后一个等于目标值的位置

3--双指针算法

3-1--快慢指针移除元素

3-2--有序数组的平方

4--滑动窗口算法

5--循环不变量


1--二分查找法

        二分查找法用于有序数组的元素查找,一般可以分为左闭右闭写法、左闭右开写法、左开右闭写法,其中左闭右闭写法最常用;

#include <iostream>
#include <vector>

class Solution {
public:
    // 左闭右闭写法
    int search1(std::vector<int>& arr, int target){
        int left = 0, right = arr.size() - 1;
        while(left <= right){ // 因为是左闭右闭写法,当left == right时[left, right]也是合法的,因此left <= right
            int mid = left + (right - left) / 2;
            if(arr[mid] > target){
                right = mid - 1;
            }
            else if(arr[mid] < target){
                left = mid + 1;
            }
            else return arr[mid];
        }
        return -1; // 表示未找到
    }

    // 左闭右开写法
    int search2(std::vector<int>& arr, int target){
        int left = 0, right = arr.size();
        while(left < right){ // 因为是左闭右开写法,当left == right时[left, right)是非法的,因此left < right
            int mid = left + (right - left) / 2;
            if(arr[mid] > target){
                right = mid; // 右开
            }
            else if(arr[mid] < target){
                left = mid + 1; // 左闭
            }
            else return arr[mid];
        }
        return -1; // 表示未找到
    }

    // 左开右闭写法
    int search3(std::vector<int>& arr, int target){
        int left = -1, right = arr.size() - 1;
        while(left < right){ // 因为是左闭右开写法,当left == right时(left, right]是非法的,因此left < right
            int mid = left + (right - left) / 2;
            if(arr[mid] > target){
                right = mid - 1; // 右闭
            }
            else if(arr[mid] < target){
                left = mid; // 左开
            }
            else return arr[mid];
        }
        return -1; // 表示未找到
    }
};

int main(int argc, char *argv[]){
    std::vector<int> test = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    int target = 2;
    Solution S1;
    int res1 = S1.search1(test, target);
    int res2 = S1.search2(test, target);
    int res3 = S1.search3(test, target);
    std::cout << res1 << ", " << res2 << ", " << res3 << std::endl;
    return 0;
}

2--二分查找法进阶

2-1--寻找第一个等于目标值的位置

等于号 = 放在哪个条件判断的依据:当 arr[mid] == target 时,应该往哪一边继续二分寻找;

#include <iostream>
#include <vector>

class Solution {
public:
    // 左闭右闭写法
    int search1(std::vector<int>& arr, int target){
        int left = 0, right = arr.size() - 1;
        int res = -1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(arr[mid] >= target){
                res = mid; // 记录可能的位置
                right = mid - 1;
            }
            else if(arr[mid] < target){
                left = mid + 1;
            }
        }
        if(res == -1 || arr[res] != target) return -1; //未找到target
        return res;
    }

};

int main(int argc, char *argv[]){
    std::vector<int> test = {1, 2, 2, 2, 3, 3, 4};
    int target = 2;
    Solution S1;
    int res1 = S1.search1(test, target);
    std::cout << res1 << std::endl;
    return 0;
}

2-2--寻找最后一个等于目标值的位置

等于号 = 放在哪个条件判断的依据:当 arr[mid] == target 时,应该往哪一边继续二分寻找;

#include <iostream>
#include <vector>

class Solution {
public:
    // 左闭右闭写法
    int search1(std::vector<int>& arr, int target){
        int left = 0, right = arr.size() - 1;
        int res = -1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(arr[mid] > target){
                right = mid - 1;
            }
            else if(arr[mid] <= target){
                res = mid; // 记录可能的位置
                left = mid + 1;
            }
        }
        if(res == -1 || arr[res] != target) return -1; //未找到target
        return res;
    }

};

int main(int argc, char *argv[]){
    std::vector<int> test = {1, 2, 2, 2, 3, 3, 4};
    int target = 2;
    Solution S1;
    int res1 = S1.search1(test, target);
    std::cout << res1 << std::endl;
    return 0;
}

3--双指针算法

3-1--快慢指针移除元素

#include <iostream>
#include <vector>

class Solution {
public:
    int removeElement(std::vector<int>& nums, int val) {
        int slow = 0, fast = 0;
        while(fast < nums.size()){
            if(nums[fast] != val){
                nums[slow] = nums[fast];
                slow++;
                fast++;
            }
            else{
                fast++;
            }
        }
        return slow;
    }
};

int main(int argc, char argv[]){
    // nums = [3,2,2,3], val = 3
    std::vector<int> test = {3, 2, 2, 3};
    int val = 3;
    Solution S1;
    int res = S1.removeElement(test, val);
    std::cout << res << std::endl;
}

3-2--有序数组的平方

主要思路:

        由于数组包含负数,则平方后的数组符合:大→小→大的排列规律;可以利用双指针算法从两端向中间遍历,取最大值放在结果数组(提前开辟); 

#include <iostream>
#include <vector>

class Solution {
public:
    std::vector<int> sortedSquares(std::vector<int>& nums) {
        std::vector<int> res(nums.size(), 0);
        int i = 0, j = nums.size() - 1, k = nums.size() - 1;
        while(i <= j){
            if(nums[i]*nums[i] > nums[j]*nums[j]){
                res[k] = nums[i]*nums[i];
                k--;
                i++;
            }
            else{
               res[k] = nums[j]*nums[j]; 
               k--;
               j--;
            }
        }
        return res;
    }
};

int main(int argc, char argv[]){
    // nums = [-4,-1,0,3,10]
    std::vector<int> test = {-4, -1, 0, 3, 10};
    Solution S1;
    std::vector<int> res = S1.sortedSquares(test);
    for(auto v : res) std::cout << v << " ";
    return 0;
}

4--滑动窗口算法

主要思路:

         维护一个滑动窗口,当满足滑动窗口内元素和 》= target 时,判断是否更新最小长度;

#include <iostream>
#include <vector>

class Solution {
public:
    int minSubArrayLen(int target, std::vector<int>& nums) {
        int i = 0, j = 0;
        int sum = 0, min_len = nums.size() + 1;
        while(j < nums.size()){
            sum += nums[j];
            while(sum >= target){
                min_len = std::min(min_len, j - i + 1);
                //缩小滑动窗口范围
                sum = sum - nums[i];
                i++; 
                
            }
            j++; //寻找下一个满足条件的滑动窗口
        }

        return min_len == nums.size() + 1 ? 0 : min_len;
    }
};

int main(int argc, char argv[]){
    // target = 7, nums = [2,3,1,2,4,3]
    std::vector<int> test = {2, 3, 1, 2, 4, 3};
    int target = 7;
    Solution S1;
    int res = S1.minSubArrayLen(target, test);
    std::cout << res << std::endl;
    return 0;
}

5--循环不变量

主要思路:

        定义循环不变量:遵循左闭右开的循环遍历规则;

#include <iostream>
#include <vector>

class Solution {
public:
    std::vector<std::vector<int>> generateMatrix(int n) {
        std::vector<std::vector<int>> res(n, std::vector<int>(n, 0));
        int offset = 1, count = 1;
        int start_x = 0, start_y = 0, i, j;
        int loop = n / 2;
        while(loop--){
            i = start_x;
            j = start_y;
            // 上边界左闭右开
            for(; j < n - offset; j++){
                res[i][j] = count;
                count++;
            }
            // 右边界上闭下开
            for(; i < n - offset; i++){
                res[i][j] = count;
                count++;
            }
            // 下边界右闭左开
            for(; j > start_y; j--){
                res[i][j] = count;
                count++;
            }
            // 左边界下闭上开
            for(; i > start_x; i--){
                res[i][j] = count;
                count++;
            }
            offset++;
            start_x++;
            start_y++;
        }
        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2 == 1) {
            res[n/2][n/2] = count;
        }
        return res;
    }
};

int main(int argc, char argv[]){
    // n = 4
    int test = 4;
    Solution S1;
    std::vector<std::vector<int>> res = S1.generateMatrix(test);
    for(auto v : res){
        for(auto item : v) std::cout << item << " ";
        std::cout << std::endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43863869/article/details/132536628