代码随想录算法训练营二刷第一天| 704. 二分查找,27. 移除元素

代码随想录算法训练营二刷第一天| 704. 二分查找,27. 移除元素

一、704. 二分查找

题目链接:
思路:维护好循环不变量。另外一个点注意别让加和超出int类型的限制,可以变为加差。
解法一:左闭右闭

public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1, mid = 0;
        while (left <= right) {
            mid = left + ((right - left) >> 1);
            if (target > nums[mid]) {
                left = mid + 1;
            } else if (target < nums[mid]) {
                right = mid - 1;
            }else {
                return mid;
            }
        }
        return -1;
    }

解法二:左闭右开

public int search(int[] nums, int target) {
        int left = 0, right = nums.length, mid = 0;
        while (left < right) {
            mid = left + ((right - left) >> 1);
            if (target > nums[mid]) {
                left = mid + 1;
            } else if (target < nums[mid]) {
                right = mid;
            }else {
                return mid;
            }
        }
        return -1;
    }

二、35.搜索插入位置

题目链接:
思路:经典二分查找。

public int searchInsert(int[] nums, int target) {
        int left = 0, right = nums.length - 1, mid = 0;
        while (left <= right) {
            mid = left + ((right - left) >> 1);
            if (target > nums[mid]) {
                left = mid + 1;
            } else if (target < nums[mid]) {
                right = mid - 1;
            } else {
                return mid;
            }
        }
        return left;
    }

三、34. 在排序数组中查找元素的第一个和最后一个位置

题目链接
思路:分别用二分查找查左边界和右边界,查找区间的左边界,要在mid小于等于target时一直记录从左边逼近边界,而右边不做记录,同理求右边界也是如此。

class Solution {
    public int[] searchRange(int[] nums, int target) {
        if (nums.length == 0) {
            return new int[]{-1, -1};
        }
        int left = getLeftBorder(nums, target);
        int right = getRightBorder(nums, target);
        if (left == -2 || right == -2) {
            return new int[]{-1, -1};
        }
        if (right - left > 1) {
            return new int[]{left + 1, right - 1};
        }
        return new int[]{-1, -1};
    }
    int getLeftBorder(int[] nums, int target) {
        int left = 0, right = nums.length - 1, mid = 0, leftBorder = -2;
        while (left <= right) {
            mid = left + ((right - left) >> 1);
            if (target <= nums[mid]) {
                right = mid - 1;
                leftBorder = right;
            }else {
                left = mid + 1;
            }
        }
        return leftBorder;
    }
    int getRightBorder(int[] nums, int target) {
        int left = 0, right = nums.length - 1, mid = 0, rightBorder = -2;
        while (left <= right) {
            mid = left + ((right - left) >> 1);
            if (target >= nums[mid]) {
                left = mid + 1;
                rightBorder = left;
            }else {
                right = mid - 1;
            }
        }
        return rightBorder;
    }
}

四、69.x 的平方根

题目链接
思路:求平方根有小数的向下取整,这种情况下只要中值计算小于等于mid就一直搜集结果,和上面求边界的思路类似,当然注意防止溢出,要用long

class Solution {
    public int mySqrt(int x) {
        int left = 0, right = x, result = 0;
        while (left <= right) {
            int mid = left + ((right - left) >> 1);
            if ((long) mid * mid <= x) {
                result = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return result;
    }
}

五、367. 有效的完全平方数

题目链接
思路:二分查找搜索即可,但是同样注意乘积使用long。

class Solution {
    public boolean isPerfectSquare(int num) {
        int left = 0, right = num, mid = 0;
        while (left <= right) {
            mid = left + ((right - left) >> 1);
            long temp = (long) mid * mid;
            if (temp == num) {
                return true;
            } else if (num < temp) {
                right = mid - 1;
            }else {
                left = mid + 1;
            }
        }
        return false;
    }
}

六、27. 移除元素

题目链接
思路:用一个变量k计数,记录相等元素的个数,不等则向前移动k个位置,最后返回数组长度减去k,因为k是要删除的元素。

class Solution {
    public int removeElement(int[] nums, int val) {
        int k = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == val) {
                k++;
            }else {
                nums[i-k] = nums[i];
            }
        }
        return nums.length - k;
    }
}

双指针解法:一个快指针,一个慢指针,快指针向前遍历,快指针指向的元素不等于target,就将元素赋值给慢指针,慢指针再前进一步,这个思路和上面有一个变量记录要移动的距离类似,有异曲同工之妙。

class Solution {
    public int removeElement(int[] nums, int val) {
        int slow = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != val) {
                nums[slow++] = nums[i];
            }
        }
        return slow;
    }
}

双向指针法:一个关键点维护好循环不变量,然后从左寻找等于target的值(即要被覆盖的值),从右寻找不等于target的值(即要保留的值),找到之后即覆盖一次。

class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            while (left <= right && nums[left] != val) {
                left++;
            }
            while (left <= right && nums[right] == val) {
                right--;
            }
            if (left <= right) {
                nums[left++] = nums[right--];
            }
        }
        return left;
    }
}

七、26. 删除有序数组中的重复项

题目链接
思路:因为数组是有序的,所以相同的元素都是紧挨着的,只需要比较相邻元素即可,只要当前元素与上一个元素相等就给元素k加1,当不相等时,就要往前移动k个位置,数组的长度即为删除掉K个元素之后的长度。

class Solution {
    public int removeDuplicates(int[] nums) {
        if (nums.length == 1) return 1;
        int k = 0;
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] == nums[i-1]) {
                k++;
            }else {
                nums[i-k] = nums[i];
            }
        }
        return nums.length - k;
    }
}

八、283. 移动零

题目链接
思路:这个移动零和前面删除元素类似,快慢指针然后交换元素即可。

class Solution {
    public void moveZeroes(int[] nums) {
        int slow = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != 0) {
                int temp = nums[slow];
                nums[slow++] = nums[i];
                nums[i] = temp;
            }
        }
    }
}

九、844. 比较含退格的字符串

题目链接
思路:从前往后要拼接字符串,从后往前就简单了,有#就记录,没有就跳过#数量,数量没了就比较是否相等,不等就返回false

class Solution {
    public boolean backspaceCompare(String s, String t) {
        int i = s.length() - 1, j = t.length() - 1;
        int skipS = 0, skipT = 0;
        while (i >= 0 || j >= 0) {

            while (i >= 0) {
                if (s.charAt(i) == '#') {
                    skipS++;
                    i--;
                } else if (skipS > 0) {
                    skipS--;
                    i--;
                }else {
                    break;
                }
            }
            while (j >= 0) {
                if (t.charAt(j) == '#') {
                    skipT++;
                    j--;
                } else if (skipT > 0) {
                    skipT--;
                    j--;
                }else {
                    break;
                }
            }
            if (i >= 0 && j >= 0) {
                if (s.charAt(i) != t.charAt(j)) {
                    return false;
                }
            } else {
                if (i >= 0 || j >= 0) {
                    return false;
                }
            }
            i--;
            j--;
        }
        return true;
    }
}

十、977.有序数组的平方

题目链接
思路:找到正数负数分界线,然后归并算法

class Solution {
    public int[] sortedSquares(int[] nums) {
        int n = nums.length;
        int negative = -1;
        for (int i = 0; i < n; ++i) {
            if (nums[i] < 0) {
                negative = i;
            } else {
                break;
            }
        }

        int[] ans = new int[n];
        int index = 0, i = negative, j = negative + 1;
        while (i >= 0 || j < n) {
            if (i < 0) {
                ans[index] = nums[j] * nums[j];
                ++j;
            } else if (j == n) {
                ans[index] = nums[i] * nums[i];
                --i;
            } else if (nums[i] * nums[i] < nums[j] * nums[j]) {
                ans[index] = nums[i] * nums[i];
                --i;
            } else {
                ans[index] = nums[j] * nums[j];
                ++j;
            }
            ++index;
        }

        return ans;
    }


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

当年拼却醉颜红

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值