【算法】代码随想录训练营Day1打卡,LeetCode 704二分查找 LeetCode27 移除元素

【算法】代码随想录训练营Day1打卡,数组与二分查找

  • 数组
    • 认识数组
      • C中的数组
      • JS中的数组
    • 二分查找
      • 二分法
      • C语言解法
      • JS解法
    • 移除元素
      • C语言解法
      • JS解法
    • 今日心得

数组

代码随想录算法训练营Day1任务。

  1. 认识数组
  2. 力扣NO.704 二分查找
  3. 力扣No.27 移除元素

认识数组

数组是一种我们最常用也是最常见的数据结构。
学过数据结构的同学们都知道,数组是一种线性表,数组是一串连续的内存空间中相同类型的数据聚合
接下来我会根据自己的理解写出在C语言中的数组与在JS中的数组

C中的数组

C语言中的数组就是我们在数据结构中所描述的最经典的数组,它有着如下的一些特点

  1. 数组的下标起始位置都是从0开始
  2. 数组是一串连续的地址(内存空间中)
  3. 数组的每一片空间都是同一种数据类型,且数据类型和数组长度在定义时就确定了
  4. 数组无法增加或删除(即改变数组的长度)
  5. 数组只允许覆盖

JS中的数组

数组在JS这一门语言中与C和C++就大有不同了,这是因为JS的数组的底层设计原因。

  1. JS的数组下标起始位置是从0开始(相同)
  2. JS的数组可以存放不同类型的数据(不同)
  3. JS的数组在相同数据类型下是一串连续的地址(相同)
  4. JS的数组在内部存放不同数据类型的情况下,地址是不连续的(不同)
  5. JS的数组允许增加或删除,即可以随意的改变数组的长度(不同)

二分查找

力扣链接:https://leetcode.cn/problems/binary-search/description/
二分查找这道题其实并不难理解,只要理解了二分法就可以了,其中最重要的就是要明白里面的一些坑,到底判断的是left< right 还是 left<=right right的初值是nums.length 还是 nums.lenght-1;在缩小范围的时候到底是加1 还是 不加1

二分法

二分法最重要的是要在一个有序数组中,如果数组无序,则二分法无法判断。
在有序的这个条件下,通过一个左右边界来找出中间值,通过传入的数与中间值的比较来丢弃掉一半的数,进而缩小范围,来达到快速搜索的理念。

在这里我们有两种方法 这两种方法就可以理解上面的一系列坑

  1. 左闭右闭区间
    左闭右闭区间的意思就是,这个二分的范围的左边界和右边界都会纳入这一次的检查范围
    【算法】代码随想录训练营Day1打卡,LeetCode 704二分查找 LeetCode27 移除元素_第1张图片
    根据上图我们就能充分明白左闭右闭区间中的各个判断条件
    即 nums[mid] < target 时 left = mid +1
    nums[mid] > target 时 right = mid -1
    nums[mid] == target 时 return
    而循环条件则是 left <= right 因为如图最后一次查询, 如果是left < right 则没有最后一次判断 直接 结束循环了

  2. 左闭右开区间
    左闭右开即右边界所指向的数不计入当此的检索范围
    ![在这里插入图片描【算法】代码随想录训练营Day1打卡,LeetCode 704二分查找 LeetCode27 移除元素_第2张图片

根据上图我们就能充分明白左闭右开区间中的各个判断条件
即 nums[mid] < target 时 left = mid +1
nums[mid] > target 时 right = mid
nums[mid] == target 时 return
而循环条件则是 left < right 因为right右边界是不计入当次检索范围的 所以若是let <= right的话则是不必要的

C语言解法

左闭右闭区间

int search(int* nums, int numsSize, int target){
 int left = 0;
 int right = numsSize-1;
 int mid = 0;
 while(left <= right){
     mid = (right + left) /2 ;
     if(nums[mid] < target){
         left = mid+1;
     }
     else if(nums[mid] > target){
         right = mid-1;
     }
     else if(nums[mid] == target){
         return mid;
     }
 }
 return -1;
}

左闭右开区间

int search(int* nums, int numsSize, int target){
 int left = 0;
 int right = numsSize;
 int mid = 0;
 while(left < right){
     mid = (right + left) /2 ;
     if(nums[mid] < target){
         left = mid+1;
     }
     else if(nums[mid] > target){
         right = mid;
     }
     else if(nums[mid] == target){
         return mid;
     }
 }
 return -1;
}

JS解法

左闭右闭区间

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    let left = 0;
    let right = nums.length -1 ; //左闭右开区间  所以right = nums.length 时 不会检查right 
    while(left<=right){
        let mid = left + ((right - left)>>1);

        if(nums[mid] < target){
            left = mid+1;
        }else if(nums[mid] > target){
            //左闭右开
            right = mid-1;
        }else{
            return mid;
        }

    }
    return -1;
};

左闭右开区间

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    let left = 0;
    let right = nums.length; //左闭右开区间  所以right = nums.length 时 不会检查right 
    while(left< right){
        let mid = left + ((right - left)>>1);

        if(nums[mid] < target){
            left = mid+1;
        }else if(nums[mid] > target){
            //左闭右开
            right = mid;
        }else{
            return mid;
        }

    }
    return -1;
};

移除元素

https://leetcode.cn/problems/remove-element/description/

本题一共我能够想到3种解法

  1. 暴力解
    即用一层for循环遍历每一位,当遍历到的位与nums相同 则用第二层for循环 将后续的每一位覆盖前一位,之后 i-- 继续判断后续的数值,因为所有数都前移了一位 所以i需要减一位 重新判断当前位置的值
  2. 双指针(左右指针)
    该方法是用两个指针,右侧指针指向能够存放数据的空位,先把right移动到不为val的位置,然后判断nums[left] 是否等于val。若是等于 则把nums[left]的值赋值为nums[right],然后再把right–之后 再把right移动到部位val的位置,如此循环到最后返回left值就为新数组的大小
    注意:在每一次循环过后都要再将右指针移动到不为 val的位置,否则会有些事项通不过,因为–了之后可能这个值就为val,再这个地方卡了挺久了,错了很多次。
    3.双指针(快慢指针)
    该方法时用两个指针,当遇到nums[slot] == val时,该指针不动, fast指针继续往前走,并将nums[slot]的值赋值为nums[fast]。循环结束后 slot就是新数组的长度

C语言解法

快慢指针

int removeElement(int* nums, int numsSize, int val){
    int slot =0;
    int fast;
    for(fast =0;fast < numsSize;fast++){
        if(nums[fast] != val ){
            nums[slot++] = nums[fast];
        }
    }
    return slot;
}

JS解法

暴力

/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
    let size = nums.length;
    for (let i=0;i<size;i++){
        if(val == nums[i]){
            for(let j=i+1;j<size;j++){
                nums[j -1] = nums[j]
            }
            i--;
            size--;
        }
    }
    return size;
};

左右指针

/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
   let left = 0;
   let right = nums.length -1 ;
   while(nums[right] == val && right >=0)right--; //将右侧指针移动到 右侧不为val的值
   while(left <= right){
       if(nums[left] == val){
           nums[left] = nums[right];
           right--;
       }
       left++;
        while(nums[right] == val && right >=0)right--;
   }
   return left
};

快慢指针

/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
   let slot = 0;
   let fast = 0;
   for(fast;fast<nums.length;fast++){
       if(nums[fast]!= val){
           nums[slot++] = nums[fast]
       }
   }
   return slot
};

今日心得

今日完成算法+完成文章的总共时间共2小时,今日的这几道题其实我也不是第一次刷了,在进入训练营之前也刷过一两遍代码随想录,但是没有特别的认真,都是比较粗略的一些想法,然后看一看代码随想录的思路,就稀里胡录的把代码写出来了,也没有进行一些复盘之类的,导致一些踩过的坑再刷仍然会踩,今天用心的理了思路,画了图,对题的记忆和解法更深刻了,对这些题也有一些自己的想法了,不像之前基本看着题没什么思路

你可能感兴趣的:(算法打卡记录,javascript,c语言,leetcode)