因为时间进度的安排,我想去的公司的实习的招聘开始时间还不是太紧,因此还是从代码随想录二刷开始,重点要做到以下方面:
1、每一章的套路总结,以及常遇到的问题(以思维导图的方式记录下来),如果有模板把模板记住;
2、分析代码的时间复杂度和空间复杂度(不要写完了就写完了,这个是在一刷中没有注意的);
3、C++在刷算法题中的常见语法(简单的排序等、迭代器这种的);
4、熟悉刷题中ACM模式(后面机试和笔试都是相关的);
5、排序的十种算法(冒泡、插入排序、归并排序、快排等)
今日任务:
- 数组理论基础
- 二分查找
- 移除元素
- 长度最小的子数组
- 螺旋矩阵(再联系)
文章目录
一、数组的理论基础
1、数组的特点:
- 数组下标都是从0开始的;
- 数组在内存空间的地址是连续的;
- 数组只能被覆盖并不可以被删除。
题目一:704.二分查找(重点在边界处理)
Leetcode题目:【704.二分查找】
1.1 暴力解法:
class Solution {
public:
int search(vector<int>& nums, int target) {
for(int i = 0; i<nums.size(); i++){
if(nums[i] == target){
return i;
}
}
return -1;
}
};
时间复杂度:o(n);
空间复杂度:o(1);
1.2 二分查找法:
二分查找可以降低时间复杂度,变为logn;
采用二分查找法,其实就是左边区间不变量的问题,是左闭右闭还是左闭右开;
这个我选择左闭右闭,注意这里的终止条件是采用while的,这个就跟暴力的方法有区别
注意:因为我这里采用的是左闭右闭,所以left <= right是有意义的。
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size()-1;
while(left<=right){
int mid = (left + right)/2;
if(nums[mid] > target){
right = mid - 1;
}else if(nums[mid] < target){
left = mid + 1;
}else {
return mid;
}
}
return -1;
}
};
时间复杂度:o(logn);
空间复杂度:o(1)
题目二:27.移除元素
Leetcode题目:【27.移除元素】
直接用双指针的方法还是比较简单的,只不过需要注意下,最后的nums[slowindex++] = nums[fastindex],因为数组要改变,后面相当于做一个截断。
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowindex = 0, fastindex = 0;
for(int fastindex = 0; fastindex<nums.size(); fastindex++){
if(nums[fastindex] != val){
nums[slowindex++] = nums[fastindex];
}
}
return slowindex;
}
};
时间复杂度o(n);
空间复杂度o(1);
题目三:有序数组的平方
Leetcode题目:【977.有序数组的平方】
3.1 sort函数
这个很直接的思路就是利用一个sort函数,进行快排就好了;
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for(int i = 0; i<nums.size(); i++){
nums[i] = nums[i] * nums[i];
}
sort(nums.begin(), nums.end());
return nums;
}
};
时间复杂度:o(n) + o(logn);
空间复杂度:o(1)
3.2 双指针(以空间换取时间)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
// 非常新的思路,双指针,重开一个数组,倒着放
vector<int> result(nums.size());
int i, j, k = nums.size() - 1;
for(int i = 0, j = nums.size()-1; i<=j; ){
if(nums[i] * nums[i] < nums[j] * nums[j]){
result[k--] = nums[j] * nums[j];
j--;
}
else{
result[k--] = nums[i] * nums[i];
i++;
}
}
return result;
}
};
时间复杂度:o(n);
空间复杂度:o(n)。
注意此处代码的双指针不要想着直接在原数组上进行修改,可以重新开一个数组,只放大的元素即可。
题目四:209.长度最小的子数组
Leetcode题目:【209.长度最小的子数组】
4.1 暴力解法
暴力解法的思路也很简单,直接两层for循环判断,但是时间会超时。
时间复杂度为:o(n^2);
空间复杂度为:o(1);
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT_MAX;
for(int i = 0; i<nums.size(); i++){
int sum = 0;
for(int j = i; j<nums.size(); j++){
sum += nums[j];
if(sum >= target){
int len = j - i + 1;
result = result > len? len : result;
}
}
}
return result == INT_MAX ? 0 : result;
}
};
4.2 滑动窗口
此题也可以采用滑动窗口的方法,不断判断串口内的数据是否满足情况,满足情况,那前面的初始窗口指针就要后移。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT_MAX, i = 0, sum = 0, sublength = 0;
for(int j = 0; j<nums.size(); j++){
sum += nums[j];
while( sum >= target){
sublength = j - i + 1;
result = result > sublength? sublength:result;
sum -= nums[i++]; // 这里体现了滑动窗口的精髓,不断变更i
}
}
return result == INT_MAX ? 0 : result;
}
};
时间复杂度:o(n);
空间复杂度:o(1);
题目五:螺旋矩阵II(纯模拟题目)
Leetcode题目:【59.螺旋矩阵】
这个题非常麻烦,基本只需要放一圈就可以实现,然后直接用循环就可以实现。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
// 循环不变量,按照左闭右开来
vector<vector<int>> num_matrix(n, vector<int>(n));
int i = 0, j = 0, stay_x = 0, stay_y = 0, offset = 1;
int cycle = n/2; // 不管n是奇数还是偶数
int count = 1;
while(cycle--){
for(j = stay_y; j<n-offset; j++){
num_matrix[stay_x][j] = count++;
}
for(i = stay_x; i<n-offset; i++){
num_matrix[i][j] = count++;
}
for(;j>stay_y; j--){
num_matrix[i][j] = count++;
}
for(;i>stay_x; i--){
num_matrix[i][j] = count++;
}
stay_x++;
stay_y++;
offset++;
}
if(n%2 == 1) num_matrix[n/2][n/2] = n*n;
return num_matrix;
}
};
有下面几个注意点:
(1)需要另外定义三个变量,stay_x,stay_y,offset,同时也需要把i,j定义为全局的,这样后面会很省事;
(2)围圈的时候的下半部分的终止条件为j > stay_y;