704. 二分查找
二分查找精髓:循环不变量
大家解释是:要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。
我的理解是:每一次循环维持目标值在定义的区间中,这个动作看成不变量。
// 左闭右闭原则
while (left<=right){
int i = (left + right) / 2;
if (nums[i] > target){
right = i-1 ;
}else if (nums[i] < target){
left = i+1 ;
}else{
return i;
}
}
// 左闭右开原则
while (left<right){
int i = (left + right) / 2;
if (nums[i] > target){
right = i ;
}else if (nums[i] < target){
left = i+1 ;
}else{
return i;
}
}
27. 移除元素
// 暴力法
emmm暴力法我没能写出来,值得借鉴:
- size控制遍历数组长度,防止死循环
- nums[j-1] = nums[j],不考虑遍历最后一位元素
没能写出原因:逻辑思维有点混乱,边界值考虑不全,没有对数组遍历长度进行控制,导致死循环。
public int removeElement(int[] nums, int val) {
int size = nums.length;
for (int i=0; i<size; i++){
if (nums[i] == val){
for (int j=i+1; j<size; j++){
nums[j-1] = nums[j];
}
-- i;
-- size;
}
}
return size;
}
// 双指针
暴力法,对于每一个等于 val
的元素,你都将数组后面的元素向前移动一位。这个过程的时间复杂度是 O(n2),因为对每个找到的元素,需要移动其后的所有元素。当数组很大时,这将非常低效。
借用卡哥的话,使用快慢指针的本质是理解快慢的含义。
public int removeElement(int[] nums, int val) {
int slow =0;
for (int quick=0; quick<nums.length; quick++){
if (nums[quick] != val){
nums[slow++] = nums[quick];
}
}
return slow;
}
nums[slow++] = nums[quick]; 还是很巧妙的,使用了后++运算符特性。
后感: 本以为二分法、双指针以及暴力法能够轻松解决,实际写起来还是有诸多问题(边界值)甚至是没有想到思路。目前对此还是有点疑惑感的,需要多周目。