代码随想录算法训练营
—day1
文章目录
前言
今天是算法营的第一天,希望自己能够坚持下来!
今日任务:
数组理论基础,704. 二分查找,27. 移除元素 977.有序数组的平方
一、数组理论基础
数组是存放在连续内存空间上的相同类型数据的集合。
需要注意的是:
1.数组下标都是从0开始的。
2.数组内存空间的地址是连续的。
3.数组的元素是不能删的,只能覆盖。
所以对于数组的增加和删除元素,需要移动覆盖其他的元素。
二、704. 二分查找
二分查找的前提是:
1.数组有序
2.无重复元素
思路:
1.确定取值范围,[0,n]还是[0,n)
2.确定二分的各个条件 if,else的逻辑
1.方法一:左闭右闭
代码如下:
class Solution {
public:
int search(vector<int>& nums, int target) {
//[0,n]
//找target=nums[m]
int l = 0, r = nums.size() -1; //数组下标是从0开始的,最大是n-1
while (l <= r) {
int m = l - (l-r)/2;
if (target == nums[m])
{
return m;
}
else if (target < nums[m])
{
//[a,m-1]
r = m - 1;
} else
{
//[m+1, r]
l = m + 1;
}
}
return -1;
}
};
2.方法二:左闭右开
代码如下(示例):
class Solution {
public:
int search(vector<int>& nums, int target) {
//[0, n)
int l = 0, r = nums.size();
while (l < r) {
int m = l - (l - r) / 2;
if (nums[m] > target) {
//[l, m)
r = m;
} else if (nums[m] < target) {
//[m+1, r)
l = m + 1;
} else {
return m;
}
}
return -1;
}
};
三、27. 移除元素
1.暴力解法
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//暴力解法,双循环
int n = nums.size();
for (int i = 0; i < n; i++)
{
if (nums[i] == val)
{
//找到目标值后,后面的数组整体向前移动
for (int j = i+1; j < n; j++)
{
nums[j-1] = nums[j];
}
i--; //因为更新了数组,nums[i]的值已经更新了,需要重新判断新的nums[i]
n--; //更新数组的新大小
}
}
return n;
}
};
2.双指针
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//双指针法
//定义两个指针
//快指针:寻找新数组所需要的元素,替换到慢指针上
//慢指针:需要替换元素的位置(val=nums[slow]的位置)
int slow = 0 , fast = 0;
while(fast < nums.size()) {
if (val!= nums[fast]) {
nums[slow] = nums[fast];
slow ++;
}
fast ++;
}
return slow;
}
};
977.有序数组的平方
1.暴力解法
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
//暴力解法,时间复杂度O(n+nlogn)
for (int i=0; i < nums.size(); i++)
{
nums[i] = nums[i] * nums[i];
}
sort(nums.begin(), nums.end()); //快速排序
return nums;
}
};
2.双指针
思路:
- 有序数组,平方后的最大只会出现在头或尾
- 使用双指针,比较头尾平方后的数谁更大,把更大的放在新数组里
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
//定义一个新数组,用于存放结果
//k指向新数组的最后
int k = nums.size()-1;
vector<int> ret (nums.size(), 0);
for(int i=0,j=nums.size()-1;i<=j;) //当i=j时,也需要处理那单个元素
{
if (nums[i]*nums[i] < nums[j]*nums[j])
{
ret[k--] = nums[j]*nums[j];
j--;
} else {
ret[k--] = nums[i]*nums[i];
i++;
}
}
return ret;
}
};
总结
今天主要是学会了二分法和双指针的用法。
双指针有两种:
1.同一边开始遍历的快慢指针;
2.分别从头尾遍历的双指针;
明天继续加油!