69. x的平方根
方法一:遍历
思路
逐个遍历判断
- 时间复杂度: O ( n ) O(\sqrt n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
int mySqrt(int x) {
for (long i = 0; i <= x; ++i) {
if (i * i == x) {
return i;
} if (i * i > x) {
return i - 1;
}
}
return 0;
}
};
方法二:二分查找
思路
二分查找,左闭右闭,查找不到返回右边界值。
- 时间复杂度: O ( log n ) O(\log n) O(logn)
- 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
int mySqrt(int x) {
int left = 0;
int right = x;
while (left <= right) {
long long mid = (right - left) / 2 + left;
if (mid * mid == x) {
return mid;
} else if (mid * mid < x) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return right;
}
};
367. 有效的完全平方数
方法一:遍历
思路
逐个遍历判断
- 时间复杂度: O ( n ) O(\sqrt n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
bool isPerfectSquare(int num) {
for (long long i = 1; i <= num; ++i) {
if (i * i == num) return true;
if (i * i > num) return false;
}
return false;
}
};
方法二:二分查找
思路
二分查找,左闭右闭,查找不到返回false。
- 时间复杂度: O ( log n ) O(\log n) O(logn)
- 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
bool isPerfectSquare(int num) {
int left = 0;
int right = num;
while (left <= right) {
long long mid = (right + left) / 2;
if (mid * mid == num) return true;
else if (mid * mid < num) left = mid + 1;
else right = mid - 1;
}
return false;
}
};
看完讲解的思考
无
代码实现遇到的问题
没有注意到数值取值范围的问题
- short:2字节,共2*8=16bit, − 2 15 ∼ 2 15 − 1 -2^{15} \sim 2^{15}-1 −215∼215−1
- int:4字节, − 2 31 ∼ 2 31 − 1 -2^{31} \sim 2^{31}-1 −231∼231−1
- long:Windows和32位Linux上是4字节,64位Linux上是8字节, − 2 31 ∼ 2 31 − 1 -2^{31} \sim 2^{31}-1 −231∼231−1 或 − 2 63 ∼ 2 63 − 1 -2^{63} \sim 2^{63}-1 −263∼263−1
- long long:8字节, − 2 63 ∼ 2 63 − 1 -2^{63} \sim 2^{63}-1 −263∼263−1
27. 移除元素
方法一:快慢双指针
思路
设置两个指针索引,一个快指针fast
一个慢指针slow
,fast
负责检测元素是否需要被移除,slow
负责保留不用移除的元素。
当nums[fast] == val
时,元素不用保留,fast
直接往后走;
当nums[fast] != val
时,元素需要保留,将nums[fast]
和nums[slow]
替换位置,slow
当前位置已是需要保留的元素,所以slow
往后移一步,由于fast
走的比slow
快,所以替换给fast
的元素一定是fast
检测过且不需要的,所以fast
也往后移一步。
直到fast
达到数组边界,所有元素检测完毕,且将要保留的元素移到了数组左端。
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
int fast = 0;
int size = nums.size();
while (fast < size) {
if (nums[fast] == val) {
++fast;
} else {
swap(nums[slow++], nums[fast++]);
}
}
return slow;
}
};
方法二:左右双指针
思路
设置左指针left
和右指针right
,此时left
的作用相当于方法一的slow
,right
的作用相当于方法一的fast
,基本思想都差不多。
左右双指针的好处时不用重复移动要移除的元素,当要移除的元素在数组开头时,例如[1,2,3,4]要移除1,方法一的话需要不断移动1的位置。直到1到达最右端,而方法二可以直接移动到最右端而不用多次移动。
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
if (nums[left] == val) {
swap(nums[left], nums[right--]);
} else {
++left;
}
}
return left;
}
};
看完讲解的思考
对于为啥方法二比方法一好没有想到,看了题解才发现。
代码实现遇到的问题
快慢指针的移动方式一开始没有理清楚。
最后的碎碎念
刚开始的题目还是简单些,不过刷题的效率有点低,老是不专注,支楞起来啊bro!