文章目录
注意
本篇内容来自代码随想录和leetcode,仅供自己记录与学习使用,如有侵权,请立即联系我。
感谢码农前辈们的付出。
数组知识
数组:存放在连续存储空间上的相同数据类型的集合,可以很方便的通过下标索引的方式获取到下标对应的数据
数组下标从0开始
数组内存空间是连续的
因为数据的内存空间是连续的,所以我们在增加或删除元素的时候,需要移动其他元素的地址
注意C++中vector和array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组(?)
数组的元素是不能删的,只能覆盖一维数组的长度可以发生变化吗
二维数组(先行后列)在内存中的空间地址是连续的吗?C++中的二维数组是连续分布的
#include <iostream>
using namespace std;
int array[2][3]={{0, 1, 2},{3, 4, 5}}; //数组的声明方式
cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2];
cout << &array[1][0] << " " << &array[1][1] << " " << &array[1][2];
//输出结果: 0x115fa28 0x115fa2c 0x115fa30
// 0x115fa34 0x115fa38 0x115fa3c(地址长短由谁决定?)
// 一个int型数据占4个字节大小
Java是没有指针的,同时也不对程序员暴露其元素的地址,寻址操作由虚拟机完成
二分查找
给定一个n个元素有序(升序的)整形数组nums和一个目标值,写一个函数搜索其中的target,如果目标值存在则返回下标,否则返回-1
Q: 如果有重复应该如何处理?
提示:1. 可以假设nums中的所有元素是不重复的
2. n将在[1,10000]之间(有何影响)
3. nums的每个元素都将在[-9999, 9999]之间(有何影响)
先写个暴搜,丢掉升序条件
Q: 对于无序数组,怎样的查找方式能取得更快的效果?
先排序,再查找吗?
Q: 在遍历vetcor中元素时,使用引用更慢?为什么
class Solution {
public:
int search(vector<int>& nums, int target) {
int index = 0;
for (int num:nums) // for(int &num:nums) 更慢!
{
if(num==target)
return index;
index++;
}
return -1;
}
};
我写的二分查找
感觉其中的难点问题有两个
一是停止条件的确定
二是左右指针更新值的确定
我写的二分查找,相比于暴力搜索,并未取得更高的内存与速度优势。当然暴力搜索的时间复杂度为
O
(
n
)
O(n)
O(n),二分查找的时间复杂度应该在
O
(
log
n
)
O(\log n)
O(logn)
Q: leetcode为什么在运行过后一次,再次运行时能取得更快的速度? 是对中间数据有缓存吗?
刷新页面能解决这个问题,刷新似乎也解决不了这个问题哈哈哈
Q: 为什么时间复杂度是
O
(
log
n
)
O(\log n)
O(logn),而不是
n
0.5
n^{0.5}
n0.5
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = nums.size();
int mid = (n-1)/2;
int left = 0, right = n-1;
while(left < right)
{
if(target > nums[mid])
left = mid+1;
else if(target < nums[mid])
right = mid;
else
break;
mid = (left+right)/2;
}
// 写完上面的逻辑,发现对于长度为一的数组无法处理
if (nums[mid]==target)
return mid;
else
return -1;
}
};
代码随想录
循环不变量,每一次对边界的处理都需要坚持根据区间的定义来做
改善地方:1. mid的获取方式
···
int middle = left + ((right - left) >> 1); // 防止溢出 等同于(left + right)/2
···
2. mid第一次获取也可以放在循环中进行
3. right指针的定义不同,mid的定义也不同,我写了个两不像
4. 他们写的怎么这么快!!!!倒是挺好记的哈哈哈,为什么我记不住! 就记住要左闭右开,而且把这个思想给贯彻到底
// 版本二
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
int middle = left + ((right - left) >> 1);
if (nums[middle] > target) {
right = middle; // target 在左区间,在[left, middle)中
} else if (nums[middle] < target) {
left = middle + 1; // target 在右区间,在[middle + 1, right)中
} else { // nums[middle] == target
return middle; // 数组中找到目标值,直接返回下标
}
}
// 未找到目标值
return -1;
}
};
- 他们的左闭右闭也记一下
// 版本一
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right] 其实就是最右端
while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=
int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
if (nums[middle] > target) {
right = middle - 1; // target 在左区间,所以[left, middle - 1]
} else if (nums[middle] < target) {
left = middle + 1; // target 在右区间,所以[middle + 1, right]
} else { // nums[middle] == target
return middle; // 数组中找到目标值,直接返回下标
}
}
// 未找到目标值
return -1;
}
};
x的平方根
给你一个非负整数
x
x
x,计算并返回
x
x
x的算数平方根,结果只保留整数部分
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5
提示: 0 < = x < = 2 31 − 1 0 <= x <= 2^{31} - 1 0<=x<=231−1
在面试中,面试官让我手撕过这道题,面试官要求保留结果一定的位数,我当时说已一定步长去搜索,结果当然是g,他们连感谢信都不发我,生气!,但是我觉得面试官很有水平,他是做网络虚拟化的,我好像下来了解过,但是现在忘了,记得他的手撕环境上写的 Talk is cheap, show me the code,啊,我感觉我很cheap。
Q: warning: operator ‘>>’ has lower precedence than ‘+’; ‘+’ will be evaluated first [-Wshift-op-parentheses]
8 | int middle = left + (right - left) >> 1;
如果说 >> 优先级低于 + ,上式就不能运行了吗? 为什么 不能最后算 >>1 呢
Q:Line 25: Char 5: error: non-void function does not return a value in all control paths [-Werror,-Wreturn-type]
这是编译器检查出的错误吗,要求所有分支都有返回值,若分支从不会被运行呢?虽然此处已经被运行了,这里待检验
我写的
- 磕磕绊绊写出来的,针对各种报错问题加了很多if,总体思想是基于二分法,对每一个middle判断其是否是正确的平方根,或在平方根的一步之内。
- middle 使用long int 类型是因为测试用例中有一个非常大的数2147395599,在做middlemiddle乘法时,会超出int的数据范围。故而有这个问题middlemiddle的数据结果会暂存在于middle数据类型相同的临时变量中,是这样吗?
- 算法和空间复杂度都处在垫底水平 哈哈
class Solution {
public:
// 定义target在一个左闭右开的区间中 [right, left)
int mySqrt(int x) {
int left = 0;
int right = x;
while(left < right){
long int middle = left + ((right - left) >> 1);
if(middle * middle > x)
{
if((middle - 1) < 0)
return middle;
if(((middle-1)*(middle-1)) < x)
return middle - 1;
right = middle;
}
else if(middle * middle < x)
{
if((middle+1)*(middle+1) > x)
return middle;
else if(((middle+1)*(middle+1)) == x)
return middle + 1;
left = middle + 1;
}
else
return middle;
}
return 0;
}
};
优化?
感觉除了计算上能优化一下,不算乘法算加法外没什么可以优化的地方?不知道大神们是怎么写的
官方题解
先看一下人家写的二分查找
写的真好:x平方根的整数部分ans是满足
k
2
≥
x
k^2\geq x
k2≥x的最大
k
k
k值,因此我们可以对k进行二分查找,从而得到答案。
Q: 大于等于 是 \geq,小于等于是 \leq
- 羡慕呀,我也想写出这样的代码
- 感觉这样的二分好像更方便 // 定义target在左闭右闭的区间里[left, right]
- 这里使用了long long做类型转换,学到了,但是这里使用long好像也行,要看
x
2
x^2
x2的范围了,复习一下int数据类型长度吧,long的长度和操作系统有关,所以使用long long应该是没有一点问题的。
// 优雅
class Solution {
public:
int mySqrt(int x) {
int l = 0, r = x, ans = -1;
while(l <= r){
int mid = l + (r-l)/2;
if((long long)mid * mid <= x)
{
ans = mid;
l = mid + 1;
}
else
r = mid - 1;
}
return ans;
}
};
袖珍计算器算法
不允许使用任何内置指数函数和算符,用指数函数exp和对数函数ln来代替平方根函数,真行啊,就直接算
x
0.5
=
e
l
n
x
∗
0.5
=
e
1
2
l
n
x
x^{0.5} = e^{lnx}*0.5 =e^{\frac{1}{2}lnx}
x0.5=elnx∗0.5=e21lnx
然后他喊我注意,指数函数和对数函数的返回值都是浮点数,运算过程中会存在误差。(关于浮点数运算我一概不知哈哈哈,平时都只用int),听他们的意思是会算小,所以在使用袖珍计算器计算得到结果后,要找出ans与ans+1到底谁是正确答案。
依旧非常优雅
Q: log这底数如何设置啊?
啊,只有两种log()和log10(),如果需要自定义底数的话需要换底,以m为底n的对数,是
l
o
g
(
n
)
/
l
o
g
(
m
)
log(n)/log(m)
log(n)/log(m),有些许麻烦哦。
在头文件中定义
Q:这里如果不对0进行判断,0也是ok的呀,log(0)是负无穷大(等等,负无穷是多少,leetcode里输出是-inf),然后e负无穷趋近0,被int一取成0了,是这样的吗?
不是,如图,e完就零了
class Solution {
public:
int mySqrt(int x) {
if(x==0){
return 0;
}
int ans = exp(0.5*log(x));
return (long long)(ans + 1)*(ans + 1) <= x ? ans+1:ans;
}
};
牛顿迭代法不想看哈哈哈
来个网友的这内联汇编
// 我也想用汇编干他们,可惜我好像只想得起来mov了
int mySqrt(int x){
double s = x;
__asm__ (
"movq %1, %%xmm0;"
"sqrtsd %%xmm0, %%xmm1;"
"movq %%xmm1, %0"
:"+r"(s)
:"r"(s)
);
return s;
}
搜索插入位置
给定一个排序数组和一个目标值,在数组中找到该目标值,并返回其索引。如果目标值不存在于数组中,则返回它应该被顺序插入的位置。
使用时间复杂度为
O
(
l
o
g
n
)
O(log n)
O(logn)的算法。
提示: nums无重复元素,升序排列的数组
Q: 通过引用方式传递vector容器?有何优势?
int searchInsert(vector<int>& nums, int target);
Q:比普通的二分查找更进一步,面对更加广泛的情况,那么如果我找到了它应该被顺序插入的位置,再对数组进行插入,也是一件麻烦事情啊!
直接借鉴代码随想录吧
自己的理解:前面是正常的二分查找,如果找到了就返回target值在升序数组中的索引下标middle。否则就没有找到,前一步是left=right,不论target与nums[middle]谁大谁小,都会导致left>right,且left=right+1,所以应该插入的位置是右边的位置,即left的位置或者是right+1的位置。
代码随想录首先对所有的情况进行了分析,抛开这道题,感觉这种列举所有情况的思路,我之前觉得情况太多,太过繁杂,如果分析的话会使用很多if,一定有一种方式能够绕开它,来获得一种通式解法;而当我面临选择困境时,友人帮我分析情况时,也列举了所有可能的情况,当时的我觉得十分受用,可能在生活中,在繁杂的生活中,不存在任何一种通式的解决办法,摆在我们面前的也就几个选择罢了,那么代码会比生活更复杂吗?我不这么认为,那么多使用几个if不行吗?哈哈哈~
回到正题,可能的插入位置有四种
- 插入位置0
- 插入数组中两数之间
- 在数组中找到了目标值
- 插入数组末尾
暴力解法
暴力解题 不一定时间消耗就非常高,关键看实现的方式,就像是二分查找时间消耗不一定就很低,是一样的。
非常nice的解题方式
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
for(int i = 0; i < nums.size(); ++i){
// 处理三种情况
// 1. 插入位置0,此时nums[0]>target
// 2. 目标值插入数组中间i,此时nums[i]>target
// 3. 目标值在nums中找到,此时nums[i]=target
if(nums[i]>=target){
return i;
}
}
// 对应第四种情况,目标值大于nums中所有值,应放在数组最后
// 或者nums为空数组,那么插入在0的位置
return nums.size();
}
};
二分查找
以后大家只要看到面试题里给出的数组是有序数组,都可以想一想是否可以使用二分法。
同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的。
然后在二分查找的循环中,坚持循环不变量的原则,很多细节问题,自然会知道如何处理了。
时间复杂度:
O
(
l
o
g
n
)
O(log n)
O(logn)
空间复杂度:
O
(
1
)
O(1)
O(1)
Q: 什么是循环不变量,以下分析均来自左侧链接?
在计算机科学中,循环不变量(loop invariant),是一组在循环体内、每次迭代均保持为真的某种性质,通常被用来证明程序或算法的正确性。
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
// 左闭右闭
int left = 0;
int right = nums.size() - 1;
int ans;
while(left <= right){
int middle = left + ((right - left) >> 1);
if(nums[middle] < target)
{
left = middle + 1;
}
else if (nums[middle] > target)
{
right = middle - 1;
}
else
return middle;
}
return left;
}
};
在排序数组中查找元素的第一个和最后一个位置
给定一个按照非递减(非递减?那就是不是递减就可以?那瞎胡排不也行吗?)顺序排列的整数数组nums,和一个目标值target。找出target在nums中开始和结束的位置。
如果数组中不存在target,返回[-1,-1]。
设计时间复杂度为
O
(
l
o
g
n
)
O(logn)
O(logn)的算法。
实例:nums = [5,7,7,8,8,10] ,target = 8
输出:[3,4]
这个题也在面试中间见过,原来它属于这里哈哈,关键是可以用二分查,查到之后嘞,二分不一定会查到开头吧,可能查到其中任何一个下标吧,那么之后呢,如何确定这个小窗的范围呢?
提示:
−
1
0
9
-10^9
−109<=nums[i]<=
1
0
9
10^9
109
−
1
0
9
-10^9
−109<=target[i]<=
1
0
9
10^9
109 有什么用暂时不想想?
先写一个暴搜吧
感觉暴搜也是有方法和技巧的,一味直接上,搞不出来。
分析一下各种情况吧,没找到直接返回[-1,-1],这个写到最后吧
借助下标遍历整个nums,若nums[i] = target, 记录i作为left
k从1开始,若i+k大于nums.size()-1,即找到末尾了,返回[i, nums.size()-1]
若i+k不大于nums.size()-1 同时
n
u
m
s
[
i
+
k
]
≠
t
a
r
g
e
t
nums[i+k]\neq target
nums[i+k]=target,则结束,返回区间[i, i+k-1]
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
for(int i = 0; i < nums.size(); ++i){
if(nums[i]==target)
{
for(int k = 1; i + k<nums.size(); ++k)
{
if(nums[i+k]!=target)
return {i, i+k-1};
}
return {i,(int)nums.size()-1};
}
}
return {-1, -1};
}
};
写出来了,时间复杂度
O
(
N
)
O(N)
O(N)
Q:nums.size()-1 写成这样时,会被报这个错
Line 12: Char 27: error: non-constant-expression cannot be narrowed from type ‘size_type’ (aka ‘unsigned long’) to ‘int’ in initializer list [-Wc++11-narrowing]
12 | return {i,nums.size()-1};
| ^~~~~~~~~~~~~
Line 12: Char 27: note: insert an explicit cast to silence this issue
12 | return {i,nums.size()-1};
| ^~~~~~~~~~~~~
| static_cast( )
1 error generated.
看起来是说nums.size()的返回值是unsigned long,而数字1的默认类型是int,在做减法运算时,结果的类型会统一成较小的类型,编译器推荐我使用一个显式的类型转换static_cast(),那么问题来了static_cast()与直接在变量前面加(int)有什么区别?
经过检索,后者是C风格的类型转换符,前者是C++中的类型转换符,相比于后者,前者更加明确和安全(不想研究了,略)
首先,我本地调试的结果如下:
可以看到nums.size()的类型可能跟随系统有所不同,但不同类型用于逻辑比较运算符就相安无事。
想一想咋二分吧
我感觉别无他法,先找到一个位置,再在附近进行搜索吧,但是感觉又十分麻烦,若是这样,二分查找的作用就是缩小了暴力搜索的范围
当然,首先没找到就返回[-1,-1]
其次若找到了是否target值一定在[left, right]的包围中? 是的
再以left和right为左右区间暴搜吗? 太让人头大了 写着看吧
逻辑还是较为清楚的,同时我也尽量重复利用了left和right,哭哭,想要会员来帮我分析一下时间复杂度,这样写还是不是
O
(
l
o
g
n
)
O(log n)
O(logn)了,但是肯定比直接暴搜低吧。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while(left <= right){
int middle = left + ((right - left) >> 1);
if(nums[middle] > target)
right = middle - 1;
else if(nums[middle] < target)
left = middle + 1;
else{
// we get target here
for(; left <= right; ++left){
if(nums[left] == target)
break;
}
for(;left<=right; --right){
if(nums[right] == target)
break;
}
return {left, right};
}
}
// 未找到
return {-1, -1};
}
};
看看代码随想录的大哥们是如何优雅的吧
分了三种情况
情况一:target在数组范围的右边或者左边
情况二:target在数组范围中,但是数组中不存在target
情况三:target在数组范围中,且数组中存在target
原来是直接写两个二分,分别搜索target在数组中的左边界和右边界,关键是我不知道二分这样用啊,如何找到左边界和右边界呢?
确定好:计算出来的右边界是x的右边界,左边界同理。
寻找左边界,就要在
n
u
m
s
[
m
i
d
d
l
e
]
=
=
t
a
r
g
e
t
nums[middle] == target
nums[middle]==target的时候更新right
寻找右边界,就要在
n
u
m
s
[
m
i
d
d
l
e
]
=
=
t
a
r
g
e
t
nums[middle] == target
nums[middle]==target的时候更新left
- 感觉看完之后下回还是写不出来。但我知道了使用二分法可以对含重复元素的非递减数组进行处理,搜索到其中值的范围,单纯的二分法应用场景太少了。
- 对于二分法的灵活应用,寻找左边界,就要在 n u m s [ m i d d l e ] = = t a r g e t nums[middle] == target nums[middle]==target的时候更新right,这个逻辑有点拧,但还是非常迷人的。和前面x的平方根里面leetcode的官方解法很像。并且确实快啊!
- 合并先不看了,小脑瓜顶不住了。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int rightBorder = getRightBorder(nums, target);
int leftBorder = getLeftBorder(nums, target);
// 对应情况一
if(rightBorder == -2 || leftBorder == -2) return {-1, -1};
// 对应情况三
if(rightBorder - leftBorder > 1) return {leftBorder+1, rightBorder -1};
// 对应情况二
return {-1,-1};
}
private:
// 二分查找,寻找target的右边界(不包含target)
int getRightBorder(vector<int>& nums, int target){
int left = 0;
int right = nums.size() - 1;
int rightBorder = -2;
while(left <= right){
int middle = left + ((right - left) >> 2);
if(nums[middle] > target){
right = middle - 1;
}
else{ // 包含了两种情况,一种是nums[middle] < target
// 另外一种是nums[middle] = target
// 如果rightBorder未被幅值,则说明整个nums中的元素都大于target
// 此时对应情况一中的一种情况,即target位于数组范围的左边
left = middle + 1;
rightBorder = left;
// 明明是寻找右边界,却使用左边界赋值
// 感觉逻辑上不是很通顺啊
// 这样理解退出while循环前一步,left=right=middle,
// 若此时nums[left] = target或者nums[left] < target(在数组范围右侧)
// 则left = right + 1 = middle + 1, 对应范围的右边界
// 或者我们考虑nums = {2,2,2,2},target =2这种情况,
// left会从零开始,逐渐自增1,直到=right,最后=right+1=4
// 这样我们就找到了右边界,现在考虑nums={1,3,4,5},target=2
// 此时rightBorder会是多少? 此时left =rightBorder= 1,这应该会与右边界的判断一同作为条件
// 来对情况二进行判断
}
}
return rightBorder;
}
// 对称的,我们寻找target的左边界(不包含target)
// 如果leftBorder没有被赋值,则表示target在数组范围的右边,对应情况一的中的第二种情况
int getLeftBorder(vector<int>& nums, int target){
int left = 0;
int right = nums.size() - 1;
int leftBorder = -2;
while(left <= right){
int middle = left + ((right - left) >> 2);
if(nums[middle] < target)
left = middle + 1;
else{
// 对应两种情况,一是nums[middle] = target
// 二是nums[middle] > target
right = middle - 1;
leftBorder = right;
// 现在考虑nums={1,3,4,5},target=2
// 此时leftBorder是多少,此时right = leftBorder = 0
// 果然和rightBorder联合起来
// 因为leftBorder和rightBorder都不包括target
// 所以若target在数组范围内并存在,则其首先其二者都不为-2
// 其次rightBorder与leftBorder之间距离大于1
}
}
return leftBorder;
}
};
有效的完全平方数
给你一个正整数num,如果num是一个完全平方数,则返回true,否则返回false。
要求不能使用任何内置的库函数
提示: 1 < = n u m < = 2 31 − 1 1<=num<=2^{31}-1 1<=num<=231−1
直接二分搜吧
梦回面试,我当时在算这个东西,我对每个num都从1开始搜不是很笨,所以当时我在思考 x > \sqrt x> x>什么和 x < \sqrt x< x<什么,从这个下限开始搜,就节省了一些,虽然肯定起不到砍一刀的威能但是也能帮帮忙。先写二分吧。
class Solution {
public:
bool isPerfectSquare(int num) {
int left = 0;
int right = num;
while(left <= right){
int middle = left + ((right - left) >> 1);
if((long long)middle*middle > num){
right = middle - 1;
}
else if((long long)middle*middle < num){
left = middle + 1;
}
else
return true;
}
return false;
}
};
写完了,让我想想我一直想干的事情,拿一张纸搞一下好像有点low吼,去函数模拟器吧。
可以看到我们首先需要对1进行一个特殊处理,然后用这两个函数分别当上限和下限,试试。
不对这个
x
x
x还是很大啊,能不能搞个
x
\sqrt x
x在点
(
1
,
1
)
(1,1)
(1,1)处的切线,用我仅存的数学知识计算一下
y
=
0.5
x
+
0.5
y=0.5x+0.5
y=0.5x+0.5
这样就不用对1进行特殊处理了吧,试试
class Solution {
public:
bool isPerfectSquare(int num) {
int left = log(num)+1;
int right = 0.5*num+0.5;
while(left <= right){
int middle = left + ((right - left) >> 1);
if((long long)middle*middle > num){
right = middle - 1;
}
else if((long long)middle*middle < num){
left = middle + 1;
}
else
return true;
}
return false;
}
};
若对1进行特殊处理,可以使用2处的切线,会更快。
OK,这样肯定更快。
官方答案
我已经想到了,袖珍计算器不行了吧,或者能否判断一个数有没有小数呢?若能应该可行,不管了,直接看吧。
使用内置的库函数
根据完全平方根的性质,我们只需要判断num的平方根 x x x是否为整数即可。对于不能判断浮点数的值是否为整数的语言,可以通过向下取整后平方回去看和num是否相等。太优雅了!
class Solution {
public:
bool isPerfectSquare(int num) {
int x = (int)sqrt(num);
return x*x == num;
}
};
有点搞不懂,为什么要在sqrt前加个强转。
暴力
如果num为完全平方数,那么一定存在正整数 x x x满足 x × x = n u m x\times x=num x×x=num。于是我们可以于是我们可以从 1 开始,从小到大遍历所有正整数,寻找是否存在满足 x×x=num 的正整数 x。在遍历中,如果出现正整数 x 使 x×x>num,那么更大的正整数也不可能满足 x×x=num,不需要继续遍历了。
class Solution {
public:
bool isPerfectSquare(int num) {
long x = 1,square = 1;
while(square <= num){
if(square == num)
return true;
++x;
square = x*x;
}
return false;
}
};
跳过牛顿迭代法啦啦
感想
终于完成了二分查找,花了很多时间,但是没关系,相信我会越做越快的。加油!
VScode环境配置 - 待完善呜呜呜搞不定
-
安装VScode
-
为了在Windows上安装GCC,你需要安装MinGW
直接从官网下载超慢的
link
环境变量
环境变量 (environment variables) 是在操作系统中用来指定操作系统运行环境的一些参数。环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所使用到的信息。
Windows 和 DOS 操作系统中的 path 环境变量,当要求系统运行一个程序而没有告诉它程序所在的完整路径时,系统除了在当前目录下面寻找此程序外,还应到 path 中指定的路径去找。用户通过设置环境变量,来更好的运行进程。
系统变量针对所有用户起作用,为了安全起见,一般配置用户环境变量。
用户变量只对当前用户起作用,不建议为了省事而配置系统环境变量。
link
-
更改 launch.json文件
Ctrl+Shift+b
参考文献
循环不变量 :https://segmentfault.com/a/1190000041715631
代码随想录: https://www.programmercarl.com/
Leetcode: https://leetcode.cn/