力扣刷题day01|704二分查找、27移除元素

力扣刷题day01-704二分查找|27移除元素

文章目录

  • 力扣刷题day01-704二分查找|27移除元素
    • 704. 二分查找
      • 难点
      • 思路
    • 27. 移除元素
      • 思路
        • 双指针法
        • 双向指针法

704. 二分查找

力扣题目链接(opens new window)

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

难点

  1. 二分时的条件到底是 while(left < right) 还是 while(left <= right)

  2. 二分完后根据target的位置不同,指针到底应该指向哪,是right = middle,还是要right = middle - 1

思路

  • target 是在一个在左闭右闭的区间里,即[left, right]

此时left == right是有意义的,if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1

public class BinarySearch {
    public int search1 (int[] nums, int target){
        // whlie循环中为左闭右闭区间
        // 定义左右指针及中间位置
        int left = 0;
        int right = nums.length - 1;
        while (left <= right){
            int mid = left + ((right - left) >> 1);
            if (target < nums[mid]){
                right = mid - 1;
            }else if (target > nums[mid]){
                left = mid + 1;
            }else if (target == nums[mid]){
                return mid;
            }
        }
        return -1;
    }
}
  • target 是在一个在左闭右开的区间里,即[left, right)

因为left == right在区间[left, right)是没有意义的,if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,right即使更新为middle也是在开区间上,不会参与比较

public int search2 (int[] nums, int target){
        // whlie循环中为左闭右开区间
        // 定义左右指针及中间位置
        int left = 0;
        int right = nums.length; // 左闭右开时右指针要指出数组右边界后一位,开区间取不到
        while (left < right){
            int mid = left + ((right - left) >> 1);
            if (target < nums[mid]){
                right = mid;
            }else if (target > nums[mid]){
                left = mid + 1;
            }else if (target == nums[mid]){
                return mid;
            }
        }
        return -1;
    }

时间复杂度:O(logn)


27. 移除元素

力扣题目链接

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。

思路

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

双指针法

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

定义快慢指针

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

当快指针指向的值不等于目标值,那么快指针此时指向的值便可以赋值给慢指针所指向的新数组

public class RemoveElement {
    public int removeElement(int[] nums, int val){
        int slowIndex = 0; // 寻找新数组的元素 ,新数组就是不含有目标元素的数组
        int fastIndex = 0; // 新新数组下标
        for (fastIndex = 0; fastIndex < nums.length; fastIndex++){
            if (nums[fastIndex] != val){
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }
        }
        return slowIndex;
    }
}
  • 时间复杂度:O(n)

双向指针法

核心就是把不等于val的全部放在数组左边,等于val的全部放在数组右边

  • 左指针:寻找等于val的元素把它扔到右边
  • 慢指针:寻找不等于val的元素,与左边等于val的位置进行交换

难点是关于while中<<=的使用

while (leftIndex <= rightIndex && nums[leftIndex] != val){
                leftIndex++;
}

当leftIndex=rightIndex两个指针重合,说明左边已经没有val要移动到右边,左指针指向两指针重合的下一位,当leftIndex>rightIndex循环停止

while (leftIndex <= rightIndex && nums[rightIndex] == val) {
                rightIndex--;
}

此时leftIndex已经大于rightIndex,循环停止。

 if (leftIndex < rightIndex)

leftIndex=rightIndex时当二指针重合时不需要交换

完整代码:

public int removeElement(int[] nums, int val){
    // 双向指针的方法
    int leftIndex = 0; // 左指针
    int rightIndex = nums.length - 1; // 右指针
    while(leftIndex <= rightIndex){
        // 找到左边等于val的元素
        while (leftIndex <= rightIndex && nums[leftIndex] != val){
            leftIndex++;
        }
        //找到右边不等于val的元素
        while (leftIndex <= rightIndex && nums[rightIndex] == val){
            rightIndex--;
        }
        //找到左边等于val的就与右边不等于val的元素交换
        if(leftIndex < rightIndex){
            nums[leftIndex++] = nums[rightIndex--];
        }
    }
    return leftIndex;
}

你可能感兴趣的:(leetcode,leetcode,算法,数据结构)