代码随想录顺序刷题-数组

目录

704. 二分查找

35. 搜索插入位置

34. 在排序数组中查找元素的第一个和最后一个位置

69. x 的平方根

367. 有效的完全平方数

27. 移除元素

26. 删除有序数组中的重复项

283. 移动零

844. 比较含退格的字符串

977. 有序数组的平方

209. 长度最小的子数组

904. 水果成篮

76. 最小覆盖子串

59. 螺旋矩阵 II

54. 螺旋矩阵

LCR 146. 螺旋遍历二维数组



704. 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

二分模板题

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int l = 0, r=nums.size()-1;

	    while (l < r)
	    {
            int mid = (l + r)/ 2;
            if (nums[mid] == target) return mid;
            else if (nums[mid] > target) r = mid - 1;
            else l = mid + 1;
	    }

        if (nums[l] == target) return l; //当查找到l==r时,nums[l]||nums[r]可能为答案
        else return -1;
    }
};

35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

依旧是二分模板题,当while循环不满足条件时,此时l==r。

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int l = 0, r = nums.size() - 1;

        while (l < r)
        {
            int mid = (l + r) / 2;
            if (nums[mid] == target) return mid;
            else if (nums[mid] > target) r = mid;
            else l = mid + 1; 
        }

        if (nums[l] == target) return l;
        else if (nums[l] < target) return l + 1;
        else return l;
    }
};



34. 在排序数组中查找元素的第一个和最后一个位置

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

依旧是二分模板题,y总的模板真好用。。。

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if (!nums.size()) return vector<int>{-1, -1}; // 当nums为空时

        // 寻找左边界
        int l = 0, r = nums.size() - 1;
        while (l < r)
        {
            int mid = (l + r) / 2;
            if (nums[mid] >= target) r = mid;
            else l = mid + 1;
        }

        int res1,res2;
        if (nums[l] != target)
        {
            res1=-1;

        }else{
            res1=l;
        }

        //寻找右边界
        l = 0, r = nums.size() - 1;
        while (l < r) 
        {
            int mid = (l + r + 1) / 2; 
            if (nums[mid] <= target) l = mid;
            else r = mid - 1;
        }
       
        if (nums[l] != target)
        {
            res2=-1;

        }else{
            res2=l;
        }

        return vector<int>{res1, res2}; 
    }
};


 

69. x 的平方根 

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5

浮点数二分,本题需要返回x的算术平方根向下取整的整数结果,如x=8时结果为2,x=4时结果为2。当mid*mid>x时,则mid不可能是结果,当mid*mid<=x时,mid可能是结果。

class Solution {
public:
    int mySqrt(int x) {
        int l = 0, r = 0x3f3f3f3f;
        while (l < r) 
        {
            int mid = l + (r - l + 1) / 2; //代替mid=(l+r)/2这种可能爆int的写法
            if (mid > x / mid) r = mid - 1; //防止mid爆int
            else l = mid;
        }
        return r;
    }
};

367. 有效的完全平方数

给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false

完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。

不能使用任何内置的库函数,如  sqrt

这题和上一题x的平方根是一样的思路

class Solution {
public:
    bool isPerfectSquare(int num) {
        int l = 0, r = 0x3f3f3f3f;
        while (l < r)
        {
            int mid = l + (r - l + 1) / 2 ;
            if (mid > num / mid) r = mid - 1;
            else l = mid;
        }
        return l * l == num; 
    }
};


27. 移除元素

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

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

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

本题可以采用双指针来完成,可以定义一个慢指针指向新数组(不含val元素的数组)的末尾,一个快指针遍历原数组。当快指针找到val时,则跳过该元素;否则将快指针所在元素赋给当前慢指针的下一个位置。

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int i, j;
        for (i = 0, j = 0; i < nums.size(); i++)
        {
            if (nums[i] != val)
            {
                nums[j] = nums[i];
                j++;
            }
        }
        return j;
    }
};

26. 删除有序数组中的重复项

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。

思路和上一题一样

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int i, j;
        int flag = nums[0]; // 用于储存快指针的上一个元素
        for (i = 1, j = 1; i < nums.size(); i++)
        {
            flag = nums[j-1];
            if (nums[i] != flag) 
            {
                nums[j] = nums[i];
                j++;
            }     
        }
        return j;
    }
};

283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

依然是和前两题一模一样的思路

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int i, j;
        for (i = 0, j = 0; i < nums.size(); i++)
        {
            if (nums[i] != 0)
            {
                nums[j] = nums[i];
                j++;
            }
        }

        while (j < nums.size()) //把0补上
        {
            nums[j++] = 0;
        }
    }
};

844. 比较含退格的字符串

给定 st 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true# 代表退格字符。

注意:如果对空文本输入退格字符,文本继续为空。

分别定义两个指针指向两个字符串的末尾,以及两个变量来储存当前遇到的连续的#号数目,若变量>0时则使指针多前进一步(不包括指针当前指向的仍是#号时),然后使变量大小-1。在指针移动完后比较两个指针指向的字符,若不相等则结束循环;若有一个指针已遍历到头也结束循环。

class Solution {
public:
    bool backspaceCompare(string s, string t) {
        int snum = 0, tnum = 0; //用于记录#  int的默认值不是0吗。。。
        int i = s.size() - 1, j = t.size() - 1; //双指针
        while (1)
        {
            while (i >= 0)
            {
                if (s[i] == '#') snum++;
                else if (snum) snum--;
                else break; // 已经将跳过了s个非#字符
                i--;
            }

            while (j >= 0)
            {
                if (t[j] == '#') tnum++;
                else if (tnum) tnum--;
                else break; // 已经将跳过了t个非#字符
                j--;
            }

            if (i < 0 || j < 0) break; //有一个字符串已经遍历完
            if (s[i] != t[j]) return false;

            i--;
            j--;
        }

        if(i == -1 && j == -1) return true;
        return false;
    }
};





977. 有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

本题可以直接使用各种排序来做,这里依然使用双指针的方法。基于原数组已经是排序好的这一特性,定义两个指针分别指向原数组的开头和末尾,若指向元素的平方数大于对方,使该平方数添加到答案当中,并则使当前指针移动一步。

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

209. 长度最小的子数组

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

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

一道非常标准的滑动窗口题

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        int res = 0x3f3f3f3f;
        int st, ed; // 滑动窗口下标
        int sum = 0; //滑动窗口的和
        for (st = 0, ed = 0; ed < n; ed++)
        {
            sum += nums[ed];
            while (sum >= target)
            {
                res = min(res, ed - st + 1);
                sum -= nums[st];
                st++;
            }
        }

        if (res != 0x3f3f3f3f) return res;
        else return 0;
    }
};

904. 水果成篮

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

  • 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
  • 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
  • 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。

给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

和上一题差不多的思路,不过这题调整滑动窗口的左边界更加困难,可以用一个哈希表来储存当前滑动窗口内水果种类及其个数。

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int n = fruits.size();
        int st, ed; //滑动窗口下标
        unordered_map<int, int> cnt; //储存滑动窗口内两种水果的个数
        int ans = 0;

        for (st = 0, ed = 0; ed < n; ed++)
        {
            cnt[fruits[ed]]++;
            
            while (cnt.size() > 2)
            {
                auto it = cnt.find(fruits[st]);
                it->second--; //将滑动窗口最左元素移除
                if(it->second == 0)
                {
                    cnt.erase(it);
                }
                st++; //滑动窗口左移一位
            }
            ans = max(ans, ed - st + 1);
        }
        return ans;
    }
};

76. 最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 ""

注意:

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

这题仍然是滑动窗口问题,但是与前两题不同的是,这题需要寻找最小的滑动窗口。这题记录滑动窗口中的值与上题类似,可以用一个哈希表来存储。在ed不断扩张滑动窗口时可以判断是否能够缩小st,若可以则缩小。

可以定义一个变量cnt来记录当前窗口内的字符是否已经满足t字符串,当滑动窗口中某个字符为t中字符,并且并非冗余字符时cnt++;当cnt等于t的size时可以判断当前滑动窗口是否是最小的覆盖子串。

class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char, int> tcnt, scnt; //用于存储t中的字符出现个数,以及滑动窗口中字符出现的个数
        int st, ed, cnt = 0; // cnt用于记录当前滑动窗口中满足条件的字符个数(不包括重复的) cnt在整个过程只增不减
        string res = s + "initialize a max string"; // 储存结果

        for (auto tmp : t) //初始化
        {
            tcnt[tmp]++;
        }

        for (st = 0, ed = 0; ed < s.size(); ed++)
        {
            scnt[s[ed]]++;

            if (tcnt[s[ed]] >= scnt[s[ed]]) // 当前字符是t中的字符,且没有超过t中该字符的个数 
            {
                cnt++;
            }

            while (scnt[s[st]] > tcnt[s[st]]) //当前的ed位置出现了新的st位置的字符,可以把滑动窗口往右缩
            {
                scnt[s[st]]--;
                st++;
            }

            if (cnt == t.size())
            {
                if (ed - st + 1 < res.size()) //求最小的子串
                {
                    res = s.substr(st, ed - st + 1);
                }
            }
        }
        if (res == s + "initialize a max string") return "";
        return res;
    }
};





59. 螺旋矩阵 II

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

矩阵模拟题,k神好强Qrt

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0));
        int left = 0, right = n - 1, top = 0, bottom = n - 1; //边界
        int cnt = 1;

        while (cnt <= n * n)
        {
            // 从左到右
            for (int j = left; j <= right; j++)
            {
                res[top][j] = cnt++; 
            }
            top++;

            //从上到下
            for (int i = top; i <= bottom; i++)
            {
                res[i][right] = cnt++;
            }
            right--;

            //从右到左
            for (int j = right; j >= left; j--)
            {
                res[bottom][j] = cnt++;
            }
            bottom--;

            //从下到上
            for (int i = bottom; i >= top; i--)
            {
                res[i][left] = cnt++;
            }
            left++;
        }

        return res;
    }
};

54. 螺旋矩阵

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

这题思路大体与上题一样,但是注意上题是一个正方形矩阵,而本题不一定为正方形,所以可能出现重复遍历一些元素的情况,所以要加上一些判断,判断当前是否已经遍历完矩阵。(不理解的话就自己模拟一遍吧)

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> res;
        int left = 0, right = matrix[0].size() - 1;
        int top = 0, bottom = matrix.size() - 1;
        int cnt = 1;
        int n = matrix.size(), m = matrix[0].size();

        while (cnt <= n * m)
        {
            for (int j = left; j <= right && cnt <= n * m; j++)
            {
                res.push_back(matrix[top][j]);
                cnt++;
            }
            top++;

            for (int i = top; i <= bottom && cnt <= n * m; i++)
            {
                res.push_back(matrix[i][right]);
                cnt++;
            }
            right--;

            for (int j = right; j >= left && cnt <= n * m; j--)
            {
                res.push_back(matrix[bottom][j]);
                cnt++;
            }
            bottom--;

            for (int i = bottom; i >= top && cnt <= n * m; i--)
            {
                res.push_back(matrix[i][left]);
                cnt++;
            }
            left++;
        }
        return res;
    }
};

LCR 146. 螺旋遍历二维数组

给定一个二维数组 array,请返回「螺旋遍历」该数组的结果。

螺旋遍历:从左上角开始,按照 向右、向下、向左、向上 的顺序 依次 提取元素,然后再进入内部一层重复相同的步骤,直到提取完所有元素。

与上面一模一样的题目。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值