算法打卡Day2

目录

前言

一、有序数组的平方

1.c语言暴力求解(存在编译bug)

2.cpp暴力求解

 3.cpp双指针求解

二、长度最小的子数组

1.非连续最小子序列和

2.连续最小子序列和-暴力求解

 3.连续最小子序列和-双指针滑动窗口

 三、螺旋矩阵

总结



前言

一月二十八日打卡


一、有序数组的平方

参考LeetCode977

1.c语言暴力求解(存在编译bug)

c语言暴力求解(快速排序)运行出问题,暂时没有成功debug

//暂时未找到bug
void QuickSort(int a[],int low,int high);
int Partition(int a[],int low,int high);
int* sortedSquares(int* nums, int numsSize, int* returnSize); 

int* sortedSquares(int* nums, int numsSize, int* returnSize) {
    for(int i=0;i<numsSize;i++){
        nums[i]=nums[i]*nums[i];
    }
    QuickSort(nums,0,numsSize);
    return nums;
}

void QuickSort(int a[],int low,int high){
    if(low<high){
        int pivotpos = Partition(a,low,high);
        QuickSort(a,low,pivotpos-1);
        QuickSort(a,pivotpos+1,high);
    }
}

int Partition(int a[],int low,int high){
    int pivot = a[low];
    while(low<high){
        while(low<high&&a[high]>=a[low])--high;
        a[low]=a[high];
        while(low<high&&a[low]<=a[high])++low;
        a[high]=a[low];
    }
    a[high] = pivot;
    return high;
}

2.cpp暴力求解

cpp同方法暴力求解 ,无bug通过

时间复杂度O(n+nlogn)

//Cpp暴力解法
class Solution {
public:
    vector<int> sortedSquares(vector<int>& A) {
        for (int i = 0; i < A.size(); i++) {
            A[i] *= A[i];
        }
        sort(A.begin(), A.end()); // 快速排序
        return A;
    }
};

 3.cpp双指针求解

双指针求解,时间复杂度O(n)

用两个指针首末移动代替排序nlogn的时间复杂度

//CPP双指针法
class Solution {
public:
    vector<int> sortedSquares(vector<int>& A) {
        int k = A.size() - 1;
        vector<int> result(A.size(), 0);
        for (int i = 0, j = A.size() - 1; i <= j;) { // 注意这里要i <= j,因为最后要处理两个元素
            if (A[i] * A[i] < A[j] * A[j])  {
                result[k--] = A[j] * A[j];
                j--;
            }
            else {
                result[k--] = A[i] * A[i];
                i++;
            }
        }
        return result;
    }
};

二、长度最小的子数组

参考LeetCode209

1.非连续最小子序列和

一开始对题目理解错了,没有发现是连续的子数组

我写成了不连续的子数组(满足16个案例)

算法思想:找出最大的然后删去,不断循环这个过程,直到和大于目标值

int minSubArrayLen(int target, int* nums, int numsSize);//求最小不连续子数组元素个数
int maxnum(int* nums,int numsSize);//求数组中的最大值
void deletemaxnum(int* nums,int max,int numsSize);//将最大元素改为-1

int minSubArrayLen(int target, int* nums, int numsSize) {
    int max=0;
    int sum=0;
    int number=1;
   while(number<=numsSize){
        max=maxnum(nums,numsSize);
        if(sum==0)sum=max;
        if(sum>=target){
            return number;
        }
        else{
            deletemaxnum(nums,max,numsSize);//删除最大元素
            max=maxnum(nums,numsSize);//赋值目前新最大元素
            sum+=max;//计算目前和的大小
            number++;
        }
    }
    return 0;
}

int maxnum(int* nums,int numsSize){
    int max=0;
    for(int i=0;i<numsSize;i++){
        if(nums[i]>max){
            max=nums[i];
        }
    }
    return max;
}

void deletemaxnum(int* nums,int max,int numsSize){
    for(int j=0;j<numsSize;j++){
        if(nums[j]==max){
            nums[j]=-1;
            break;
        }
    }
}

2.连续最小子序列和-暴力求解

cpp暴力求解

 算法思想:两个for循环更新sum值和result值

时间复杂度:O(n²)

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX; // 最终的结果
        int sum = 0; // 子序列的数值之和
        int subLength = 0; // 子序列的长度
        for (int i = 0; i < nums.size(); i++) { // 设置子序列起点为i
            sum = 0;
            for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为j
                sum += nums[j];
                if (sum >= s) { // 一旦发现子序列和超过了s,更新result
                    subLength = j - i + 1; // 取子序列的长度
                    result = result < subLength ? result : subLength;
                    break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                }
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

 3.连续最小子序列和-双指针滑动窗口

cpp-双指针-滑动窗口

算法思想:利用两个指针不断调节子序列的起始位置和终止位置,时间复杂度为O(n)

滑动窗口的精髓,或者说与两个for循环暴力解法不同的地方在于,滑动窗口第一个for循环中变量的身份是j(滑动窗口的终止位置),思考如何做到只用一个for循环解决问题,也就是思考怎么样变动滑动窗口的起始位置

j:滑动窗口终止位置

i:滑动窗口起始位置

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0; // 滑动窗口数值之和
        int i = 0; // 滑动窗口起始位置
        int subLength = 0; // 滑动窗口的长度
        for (int j = 0; j < nums.size(); j++) {
            sum += nums[j];
            // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
            while (sum >= s) {
                subLength = (j - i + 1); // 取子序列的长度
                result = result < subLength ? result : subLength;
                sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
}

 三、螺旋矩阵

参考LeetCode59

int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
    //初始化返回的结果数组的大小
    *returnSize = n;
    *returnColumnSizes = (int*)malloc(sizeof(int) * n);
    //初始化返回结果数组ans
    int** ans = (int**)malloc(sizeof(int*) * n);
    int i;
    for(i = 0; i < n; i++) {
        ans[i] = (int*)malloc(sizeof(int) * n);
        (*returnColumnSizes)[i] = n;
    }

    //设置每次循环的起始位置
    int startX = 0;
    int startY = 0;
    //设置二维数组的中间值,若n为奇数。需要最后在中间填入数字
    int mid = n / 2;
    //循环圈数
    int loop = n / 2;
    //偏移数
    int offset = 1;
    //当前要添加的元素
    int count = 1;

    while(loop) {
        int i = startX;
        int j = startY;
        //模拟上侧从左到右
        for(; j < startY + n - offset; j++) {
            ans[startX][j] = count++;
        }
        //模拟右侧从上到下
        for(; i < startX + n - offset; i++) {
            ans[i][j] = count++;
        }
        //模拟下侧从右到左
        for(; j > startY; j--) {
            ans[i][j] = count++;
        }
        //模拟左侧从下到上
        for(; i > startX; i--) {
            ans[i][j] = count++;
        }
        //偏移值每次加2
        offset+=2;
        //遍历起始位置每次+1
        startX++;
        startY++;
        loop--;
    }
    //若n为奇数需要单独给矩阵中间赋值
    if(n%2)
        ans[mid][mid] = count;

    return ans;
}

 

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
        int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
        int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
        int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int count = 1; // 用来给矩阵中每一个空格赋值
        int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int i,j;
        while (loop --) {
            i = startx;
            j = starty;

            // 下面开始的四个for就是模拟转了一圈
            // 模拟填充上行从左到右(左闭右开)
            for (j = starty; j < n - offset; j++) {
                res[startx][j] = count++;
            }
            // 模拟填充右列从上到下(左闭右开)
            for (i = startx; i < n - offset; i++) {
                res[i][j] = count++;
            }
            // 模拟填充下行从右到左(左闭右开)
            for (; j > starty; j--) {
                res[i][j] = count++;
            }
            // 模拟填充左列从下到上(左闭右开)
            for (; i > startx; i--) {
                res[i][j] = count++;
            }

            // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            startx++;
            starty++;

            // offset 控制每一圈里每一条边遍历的长度
            offset += 1;
        }

        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2) {
            res[mid][mid] = count;
        }
        return res;
    }
};

总结

1.利用好双指针解决数组问题

2.二维数组的运用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值