卡哥的题目建议: 大家能把 704 掌握就可以,35. 搜索插入位置 和 34. 在排序数组中查找元素的第一个和最后一个位置 ,如果有时间就去看一下,没时间可以先不看,二刷的时候在看。先把 704写熟练,要熟悉 根据 左闭右开,左闭右闭 两种区间规则 写出来的二分法。
3,确定在哪个范围里比较和查找,一开始大范围是在整个数组,当比较完了,我们就知道在前半部分或者后半部分的小范围里查找,还要更新小范围的边界值,在小范围里比较再细分成更小的范围,如此类推.........,这个范围数学化理解就是区间,区间可以分为左闭右闭,左闭右开,(这两种区间用得多),我自己比较好理解左闭右闭这种方式的。
我没用力扣的环境运行,用的是vs,看了视频后,就差不多能理解代码了,用左闭右闭方式的完整代码如下:
1 #include <iostream> 2 using namespace std; 3 const int N = 10; 4 int a[N]; //声明全局数组 5 int BinarySearch(int a[], int target) 6 { 7 int left = 0, right = sizeof(a) - 1; //左闭右闭区间范围为[left, right],即[0, n-1],left,right,也是数组下标 8 int middle; //数组的中间数的下标 9 while (left <= right) //在一个合法的区间里比较和查找,比如[1, 1],这个区间只有1,合法 10 { 11 middle = left + (right - left) / 2; //防止溢出 等同于(left + right)/2 12 if (target < a[middle]) //查找范围在数组的前半部分 13 { 14 right = middle - 1;//因为区间是左闭右闭,所以前半部分的右边界值不包含middle 15 } 16 else if (target > a[middle]) //查找范围在数组的后半部分 17 { 18 left = middle + 1;//因为区间是左闭右闭,所以后半部分的左边界值不包含middle 19 } 20 else if (target == a[middle])//目标数和数组中间数相等 21 { 22 return middle; //直接输出数组中间数的下标,break退出循环 23 break; 24 } 25 } 26 return -1; 27 } 28 int main() 29 { 30 int n; //数组的元素个数为 n 31 cout << "请输入数组的元素个数:" << endl; 32 cin >> n; 33 cout << "请输入数组:" << endl; 34 for (int i = 0; i < n; i++) 35 { 36 cin >> a[i]; //循环输入数组中的元素 37 } 38 cout << "请输入要查找的值:" << endl; 39 int target; //目标数 40 cin >> target; 41 cout << BinarySearch(a, target) << endl; 42 43 return 0; 44 }
关于代码中的middle = left + (right - left) / 2, ,不理解溢出的话,就死记住吧。
运行结果如下:
题目链接:https://leetcode.cn/problems/remove-element/
视频讲解:https://www.bilibili.com/video/BV12A4y1Z7LP
文章讲解:https://programmercarl.com/0027.%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.html
卡哥的题目建议: 暴力的解法,可以锻炼一下我们的代码实现能力,建议先把暴力写法写一遍。 双指针法 是本题的精髓,今日需要掌握,至于拓展题目可以先不看。
有两种方法:暴力解法和双指针法。
暴力解法思路:用两个for循环,第一个for循环用来遍历数组,第二个for循环用来前移数据覆盖,就跟单链表的删除操作类似。完整代码如下:
1 #include <iostream> 2 using namespace std; 3 const int N = 10; 4 int a[N]; //声明全局数组 5 int main() 6 { 7 int n; //数组的元素个数为 n 8 cout << "请输入数组的元素个数:" << endl; 9 cin >> n; 10 cout << "请输入数组:" << endl; 11 for (int i = 0; i < n; i++) 12 { 13 cin >> a[i]; //循环输入数组中的元素 14 } 15 cout << "请输入要移除元素的值:" << endl; 16 int val; 17 cin >> val; 18 for (int i = 0; i < n; i++)//第一个循环是为了把遍历数组 19 { 20 if (a[i] == val) //判断数组的哪个数和要移除的数相等 21 { 22 for (int j = i; j < n; j++)//如果有一个数相等的话,那就从当前位置开始进行前移覆盖操作 23 { 24 a[j] = a[j + 1];//数组的后一个数前移覆盖当前位置的数 25 } 26 i--; //覆盖后,数组的有效元素减一,更新i值 27 n--; //数前移移除后,原来数组的有效元素减一,更新n值 28 } 29 } 30 cout << n << endl; 31 return 0; 32 }
运行结果如下:
双指针法做题思路:也称快慢指针法,通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。这个解法不用知道为啥,为了方便操作就行。
快指针:寻找新数组的元素 ,新数组就是不含有要移除的元素的数组;
慢指针:指向更新新数组下标的位置。
完整代码如下:
1 #include <iostream> 2 using namespace std; 3 const int N = 10; 4 int a[N]; //声明全局数组 5 int main() 6 { 7 int n; //数组的元素个数为 n 8 cout << "请输入数组的元素个数:" << endl; 9 cin >> n; 10 cout << "请输入数组:" << endl; 11 for (int i = 0; i < n; i++) 12 { 13 cin >> a[i]; //循环输入数组中的元素 14 } 15 cout << "请输入要移除元素的值:" << endl; 16 int val; 17 cin >> val; 18 int slow = 0; //慢指针的变量 19 for (int fast = 0; fast < n; fast++) 20 { 21 if (val != a[fast]) //如果fast位置上的元素和要移除的元素不相等的话, 22 { 23 a[slow] = a[fast]; //就把fast位置上的元素覆盖成slow位置上的元素 24 slow++;//slow虽然是下标,但是它也记录了新数组的个数,自己看视频就会发现 25 } 26 } 27 cout << slow << endl; 28 return 0; 29 }
运行结果如下: