代码随想录算法一刷Day01|数组理论基础 704二分查找 27移除元素

1.基础知识

1.1数组是存放在连续内存空间上的相同类型数据的集合。

  • 数组下标都是从0开始的。
  • 数组内存空间的地址是连续的。
  • 数组的元素是不能删的,只能覆盖。
  • 二维数组在内存的空间地址在C++中是连续分布的,在java中是不连续的。(Java是没有指针的,同时也不对程序员暴露其元素的地址,寻址操作完全交给虚拟机,所以看不到每个元素的地址空间情况,可以找出经过处理后的数值。)
    java中二维数组的排列方式

2.相关知识

3.力扣题目

3.1 704 二分查找

704问题

3.1.1 自己做法

//第一反应和二分查找没有一毛钱关系的,还在想这题咋这么简单(微笑)
class Solution {
    public int search(int[] nums, int target) {
        for(int i = 0; i < nums.length; i++){
            if(target == nums[i]){
                return i;
            }
        }
        return -1;
    }
}

//二分查找
class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        
        while(left <= right){
            int mid = left + (right - left)/2;
            if(target == nums[mid]){
                return mid;
            }else if(target > nums[mid]){
                left = mid + 1;
            }else if(target < nums[mid]){
                right = mid - 1;
            }
        }
        return -1;
    }
}
出现的问题(快反思)
  1. 求数组的长度用的是:nums.length 你用的是:nums.size()
  2. 第一反应写的和二分查找没有一毛钱关系
  3. 判断用的是==而不是=
  4. 二分查找结束条件:left>right 而不是==
  5. .int mid = left+(right - left)/2; -----防止整数溢出(怕right + left结果超过int范围)(而且这个语句要放在循环里,因为每次mid值都要改)
  6. 更新left和right的值:
    left = mid + 1;
    right = mid - 1;
    不能直接left/right = mid;
    (这样设置的话万一target不在数组中(比如比数组中的最大值还大),/法两个相邻的值求一直等于较小的值,就死循环了。比如在[1,2,3]里找4)
    left=0-1-1-1-1
    right=2-2-2-2-2
    (就一直1、2循环下去了,left不会大于right)
    正确的
    left=0-2-3
    right=2-2-2
    (此时就不满足条件退出循环)
    (别纠结:反正target != mid了,缩小后肯定也不要它了)

3.1.2 参考做法

  1. 写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)
  2. 两种判断while里条件是<=还是<:可以想象left=right,此时若right还代表最后一个数,此时就是右闭了。所以右闭是<=,右开是<。([1,1]就代表1,就是两边闭可以相等。[1,1) 这明显就是错误的式子,既包括1又不包括1,所以一开一闭不能相等。 )
  3. 判断right是mid还是mid-1:右闭是包含right的,而此时mid已经不是了,就要把mid从下轮要找的区间里排除,所以右闭就是mid-1,右开是mid。
  4. left因为两种都是闭,所以都是mid+1.
  5. right的初始值,右闭的话包含right所以取数组的最大下标就行,右开的话因为不包含right,所以right的取值就要比数组实际大1,才能把数组整个表示到。
左闭右闭即[left, right]

//自己写的那个应该就属于这个
right = nums.length - 1
while(left <= right)
right = mid - 1

class Solution {
    public int search(int[] nums, int target) {
        // 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
        if (target < nums[0] || target > nums[nums.length - 1]) {
            return -1;
        }
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + ((right - left) >> 1);
            if (nums[mid] == target) {
                return mid;
            }
            else if (nums[mid] < target) {
                left = mid + 1;
            }
            else { // nums[mid] > target
                right = mid - 1;
            }
        }
        // 未找到目标值
        return -1;
    }
}
左闭右开即[left, right)

right = nums.length
while(left < right)
right = mid

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length;
        while (left < right) {
            int mid = left + ((right - left) >> 1);
            if (nums[mid] == target) {
                return mid;
            }
            else if (nums[mid] < target) {
                left = mid + 1;
            }
            else { // nums[mid] > target
                right = mid;
            }
        }
        // 未找到目标值
        return -1;
    }
}

3.2 27 移除元素

在这里插入图片描述
在这里插入图片描述

3.2.1 自己做法

class Solution {
    public int removeElement(int[] nums, int val) {
        int count = nums.length;
        for(int i = 0; i <= count-1; i++){
            if(nums[i] == val){
                for(int j = i; j < count - 1; j++){
                    nums[j] = nums[j+1];
                }
                i--;
                count--;  //这里没有想到可以直接总数-1.
            }
        }
        return count;
    }
}
出现的问题(快反思)
  1. 这属于暴力解法。

3.2.2 参考做法

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置
fast指向的若不等于val的:fast值赋给slow的,即遇到相等的就走,遇到不相等的就给slow传回去。(一开始俩一起走的时候也是赋值了,只是俩指向同一个,所以相当于没赋值。)
slow遇到不相等的则+1,遇到相等的就不变,等着fast遇到不相等的给他传回来。
(把需要的数组想象成新建了一个新数组:slow相当于一个新数组,只存!=val的值,fast相当于在与数组中找!=val的值)
(所以slow只要遇到=val的值就停下,等着fast给他找到!=val的值把这个一替换)
(slow最后的值就是新数组中的大小)
在这里插入图片描述

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

4.总结

数据结构差不多忘完了,第一次做算法题,做的真shi啊(暴风哭泣)

二分法查找:有序、无重复元素
1. mid值的计算,left+(right - left)/2防止溢出。
2. while循环满足的条件。
3. left和right的移动。

  • 24
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值