day1|leetcode 704、35、34、69、367、27

非科班,之前只是学过数据结构课,基础较差,写给自己的碎碎念

day1: 34题2分法的方法没做出来,69、367有int,long的坑,27题没做出来快慢指针的做法。

704:力扣题目链接

首先是二分查找法的使用前提条件:

1.数组为有序数组

2.数组中无重复元素

确定可以使用后,有两种写法

1.左闭右闭:这是我之前一直用的写法,其中需要注意的是int mid = start + (end - start)/2或者是int mid = start + (end - start)>>1。这样相比于常见的(start = end)/2,可以防止溢出。其实这个也很好理解,当成向量理解就觉得更合理了。

class Solution {
    public int search(int[] nums, int target) {
        int start = 0;
        int end = nums.length-1;
        while(start <= end){
            int mid = start + ((end - start) / 2) ;
            if(nums[mid] < target){
                //target在右边
                start = mid + 1;
            }else if(nums[mid] > target){
                end = mid - 1;
            }else if(nums[mid] == target){
                return mid;
            }
        }
        return -1;
    }
}

2.左闭右开:注意左闭右开的话,[start,end),要想让他是一个合法的区间,那么start是不可能等于end的,比如[3,3)是错的。所以while里的条件应该是start < end。同时注意,在比较时,右边的那个数始终是不参与比较的,所以end = mid就可以,如果是mid - 1的话,就漏掉了一个数。左边因为是开区间所以不变。故完整代码是:

class Solution {
    public int search(int[] nums, int target) {
        int start = 0;
        int end = nums.length;
        while(start < end){
            int mid =  start + ((end - start) / 2) ;
            if(nums[mid] < target){
                //target在右边
                start = mid + 1;
            }else if(nums[mid] > target){
                end = mid;
            }else if(nums[mid] == target){
                return mid;
            }
        }
        return -1;
    }
}

35.力扣题目链接

我个人不考虑二分法的做法是:

因为这是一个排序数组,那么只需要从头开始遍历,得到的第一个大于或者等于这个target的数的索引就是该target输入的位置。

class Solution {
    public int searchInsert(int[] nums, int target) {
        for(int i = 0; i < nums.length; i++){
            if(target <= nums[i]){
                return i;
            }
        }
        return nums.length;

        
    }
}

如果要用二分查找法的方式做,那么:

class Solution {
    public int searchInsert(int[] nums, int target) {
        // for(int i = 0; i < nums.length; i++){
        //     if(target <= nums[i]){
        //         return i;
        //     }
        // }
        // return nums.length;
        int start = 0;
        int end = nums.length - 1;
        while(start <= end){
            int mid = start + (end - start)/2;
            if(nums[mid] < target){
                start = mid + 1;
            }
            else if(nums[mid] > target){
                end = mid - 1;
            }
            else{
                return mid;
            }
        }
        return start;
    }
}

这个题的中心思想和704差不多,当target不存在的数时,始终返回的是start的索引(也可以认为是end+1,因为跳出循环的时候始终是start = end - 1)。

尝试用第二种方法做:

class Solution {
    public int searchInsert(int[] nums, int target) {
        // for(int i = 0; i < nums.length; i++){
        //     if(target <= nums[i]){
        //         return i;
        //     }
        // }
        // return nums.length;
        int start = 0;
        int end = nums.length;
        while(start < end){
            int mid = start + (end - start)/2;
            if(nums[mid] < target){
                start = mid + 1;
            }
            else if(nums[mid] > target){
                end = mid;
            }
            else{
                return mid;
            }
        }
        return start;
    }
}

这里也可以返回end,因为此时跳出循环的end = start

34.力扣链接

这道题我一开始想用基于数组的暴力解题法,结果自己逻辑水平太有限实在是弄不出来,多举几个例子就错了,最后我采用了集合arraylist的方法,如下:

class Solution {
    public int[] searchRange(int[] nums, int target) {
       ArrayList<Integer> list = new ArrayList();
       int[] arr = new int[2];
       for(int i = 0; i< nums.length; i++){
           if(nums[i] == target){
               list.add(i);
           }
       }
       if(list.size() == 0){
           arr[0] = arr[1] = -1;
       }else {
           arr[0] = list.get(0);
           arr[1] = list.get(list.size()-1);
       }
       return arr;
    }
}

如果要用二分法的话,重点是要找到左边界和右边界,随想录提供的第一种方法我还需要消化一下,这里用第二种方法,觉得更好解释:

首先用二分法确定是否存在该target,若不存在则直接输出{-1,1};

若存在,则在数组范围内(0,nums.length -1)逐步查找left和right的范围。

class Solution {
	public int[] searchRange(int[] nums, int target) {
		int num = binarySearch(nums, target);
        if(num == -1){
            return new int[] {-1,-1};
        }else{
            int left = num;
            int right = num;
            while(left >= 0 && nums[left] == target){
                left --;
            }
            while(right <= nums.length - 1 && nums[right] == target){
                right ++;
            }
            return new int[] {left+1,right-1};
        }
	}
    public int binarySearch(int[] nums, int target){
        int start = 0;
        int end = nums.length - 1;
        while(start <= end){
            int mid = start + (end - start)/2;
            if(nums[mid] < target){
                start = mid + 1;
            }else if(nums[mid] > target){
                end = mid - 1;
            }else{
                return mid;
            }
        }
        return -1;
    }
}

69.力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

中心思想是求左边界,以为很快就做完了,结果有一个int和long的坑,卡了很久才反应过来.注意当x为整数类型时,x/2的平方是非常有可能溢出的。

class Solution {
    public int mySqrt(int x) {
        int start = 0;
        int end = x;
        int bound = -1;
        while(start <= end){
            int mid = start + (end - start)/2;
            long result = (long)mid*mid;
            if(result <= x){
                bound = mid;
                start = mid + 1;
            }else{
                end = mid - 1;
            }
        }
        return bound;
    }
}

367. 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

同理。求左边界

class Solution {
    public boolean isPerfectSquare(int num) {
        int start = 0;
        int end = num;
        while(start <= end){
            int mid = start + (end - start)/2;
            long result = (long)mid*mid;
            if(result == num){
                return true;
            }else if(result < num){
                start = mid + 1;
            }else{
                end = mid - 1;
            }
        }
        return false;
    }
}

27 .力扣题目链接

这个题要求原地移除元素并返回移除后的长度,其中移除的含义是指通过返回的数组长度遍历数组,得到剩下的数组。这里我一开始是想到了先把要移除的元素变成-1,之后遍历得到数组中非负数的长度,最后逆冒泡算法,使负数都排到数组后面,得到结果。

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

这种方法执行时间长。

用快慢指针法,则

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

也就是说快指针起到遍历的作用一直往前走,边走便判断,慢指针则主要起到了确定新数组下标的作用,当不是val时它也跟着遍历,当是val时,它这一轮就停住了,等下一轮去覆盖它。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值