第一天记录
二分 + 双指针操作
- 题源 leetCode 704 + leetCode 27
- 题目传送门
- https://leetcode.cn/problems/binary-search/
- https://leetcode.cn/problems/remove-element/
1. 二分
// 提问 -- 这是一段有问题的代码,能看出问题在哪吗?
public static int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
int mid;
while (left <= right){
mid = (left + right) / 2;
if (target < nums[mid]){
right = mid;
}
else if ( target > nums[mid] ) {
left = mid;
}
else return mid;
}
return -1;
}
贴上正确代码
答案揭晓:
可以找到数组里存在且不为尾巴下标位置的数
数组里不存在的数字无法找到,会进入死循环, (4+5)/2 = 4 的循环
做法: 对左右下标进行移动,都已经不等于了,直接移动就好
// 上述错误的测试样例
public static void main(String[] args) {
int a[] = {-1,0,3,5,9,12};
int tar = 13;
int ans = search(a,tar);
System.out.println(ans);
}
2. 移除元素
- 暴力法,遍历处理
// 暴力法尝试,但似乎没那么暴力
public static int removeElement(int[] nums, int val) {
int removeCount = 0; // 移除的元素个数
int tempStart; // 哨兵处理
for (int i = 0; i < nums.length - removeCount; i++){
if (nums[i] == val){ // 遇到相等情况,开始移除 i
tempStart = i;
for ( ; tempStart < nums.length - 1 - removeCount; tempStart++){
nums[tempStart] = nums[tempStart+1];
}
removeCount++;
i--; // 回退一步 i,因为当前的目标元素被处理掉了,应该查询后边部分的数组
}
}
return nums.length - removeCount;
}
暴力法第一次出错,原因是
1. i 没有回退,遇到连续的val就会出问题
2. 待处理的数组长度发生了变化,但我仍然按照 nums.length - 1 处理了
这样会导致原先被处理完的元素又一次被记到removeCount
(另外两处的犯错点二忘了标…)
- 双指针法
- 相比暴力法,双指针只需一次循环,处理原先两次的两次循环
public static int removeElement(int[] nums, int val) {
int fast = 0;
int slow = 0;
for ( ; fast < nums.length; fast++){
if (nums[fast] == val){
continue;
}
nums[slow++] = nums[fast];
}
return slow;
}
暴露出的问题
- code不够优雅, 下次能够抽象出来的尽量放外面
- 对特殊情况的考虑太少
- 扩展题目优点心有余力不足了,希望自己能努努力每日多看一些