Day 01 总结
- 自己实现过程中遇到哪些困难
- 特殊例子,或者特殊情况没有考虑完全,明明是一道简单题,但不能答对。
- 写第三题的时候,发现自己对于一些特殊情况并不能很好的照顾到,设计的算法表面上看起来似乎是对的,没有问题,但是跑起来测试之后会有很多漏洞。
- 我应该在设计完算法之后试着去寻找一些反例,或者思考一下测试数据的多种可能性,往往我设计的算法都只能通过测试用例,其中潜在原因就是思考的并不全面,也没想到漏洞在哪里。
- 请问对于这种情况,我应该如何去解决呢?
- 今日收获,记录一下自己的学习时长
- 14:00 - 16:00
- 解惑(补充)
- 对于第三题来说,看了卡哥的讲解视频,我一下就发现了自己的错误在哪里。数组的最大值是一定可以在两端找到的,但是对于最小值,并不能确定其索引的位置,有可能出现两个最小值,也有可能数组的形状并不是V字形(单调递减),所以寻找最小值向左右扩散是会遇到特殊情况的。
- 所以我的算法会遇到不能处理的情况,是因为我没有总结出题目的规律性和潜在的特殊性。
- 需要充分了解到问题,才能设计解决问题的通用办法, 不要陷入在debug的陷阱中,而是去思考全局的方向是否出现错误。
- 也就是说,并不是有特殊情况的存在,使得我的算法失效,而是我没有深入理解问题的本质。
704. 二分查找(简单)
实现思路:
由变量 left 和 变量 right 确定一个数组区间,通过公式 mid = left + (right - left) / 2 计算出中间位置的索引。
对比对索引位置的值与 target 值,因为数组有序,如果查找到的值比目标值小,则继续搜索左区间,反之搜索右区间。对于左区间来说,所有的数必然小于当前搜索位置,所以 left 值不需要变动,只需要更新 right 值。搜索右区间同理。
确定数组区间边界:
需要明确 left 和 right 的意义
如果 left 的值代表区间最左边的值的索引,right 代表区间最右边的值的索引,那么该区间是一个左边闭合,右边也闭合,即,左闭右闭的区间,那么在更新 left 值的时候,left = mid + 1,更新 right 值的时候,right = mid - 1。循环终止条件,即当前区间长度 >= 1的表达式为 left >= right。如果为左闭右边开区间,left 的更新方式不变,right = mid。循环终止条件,当前区间长度 >= 1的表达式为 left > right, 因为 right 的位置不属于区间内,left 不会与 right 重合。
Java代码实现:
class Solution {
/*
* 左闭右闭
*/
public int search1(int[] nums, int target) {
int right = nums.length-1;
int left = 0;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {return mid;}
if (nums[mid] < target) {left = mid + 1;} // 搜索右区间
else right = mid-1; // 搜索左区间
}
return -1;
}
/*
* 左闭右开
*/
public int search2(int[] nums, int target) {
int right = nums.length;
int left = 0;
while (left < right) {
int mid = left + (right - left) / 2;
System.out.println(mid);
if (nums[mid] == target) {return mid;}
if (nums[mid] < target) {left = mid + 1;}
else right = mid;
}
return -1;
}
}
27. 移除元素(简单)
力扣题目链接:
实现思路:
在同一个数组中,将符合条件的元素向后移动,并不改变其他元素的相对顺序。在同一数组中首先想到使用双指针,slow 指针定位需要向后移动的元素,fast指针定位需要向前移动的元素,然后在一次循环当中进行交换,并更新两个指针的位置。
代码实现:
class Solution {
public int removeElement(int[] nums, int val) {
int slow=0,fast=0;
for (; fast<nums.length; fast++) {
int temp = nums[slow];
nums[slow] = nums[fast];
nums[fast] = temp;
if (nums[slow] != val) slow++;
}
return slow;
}
}
977. 有序数组的平方
力扣题目链接:
文章讲解:
实现思路:
我一开始的思路:
对数组排序还要求 O(n) 的复杂度必然需要使用额外空间,所以需要创建一个新的数组。
由于负数的存在,在平方后,整个数组先是从高到底下降的趋势,然后在从某一个位置开始逐渐增高,呈现一个V字山谷的形状。在了解到这个变化趋势之后,可以先定位到谷底的位置,将该数组插入到新数组的第一个位置,然后从谷底开始左右扩散,拿出更小的的值依次放入数组中,实现排序。
但是实测发现,会出现很多bug,对于很多情况都不能处理,例如
[25,9,4,1]
[100000000,0,0,25,49,99980001,100000000]
错误出现的原因:谷底并不唯一
文章的双指针思路:
从数组的最左侧和最右侧开始,选择更大的数字放入新数组的最右侧,省去了寻找谷底的步骤,更加简洁易懂和好实现。
代码实现:
class Solution {
public int[] sortedSquares(int[] nums) {
int n = nums.length;;
for (int i=0; i<nums.length; i++) {
nums[i] *= nums[i];
}
int left =0,
right = nums.length-1;
int[] result = new int[n];
for (int i=n-1; i>=0; i--) {
int temp;
if (nums[left] >= nums[right]) temp = nums[left++];
else temp = nums[right--];
result[i] = temp;
}
return result;
}
}

947

被折叠的 条评论
为什么被折叠?



