代码随想录算法训练营Day1任务。
数组是一种我们最常用也是最常见的数据结构。
学过数据结构的同学们都知道,数组是一种线性表,数组是一串连续的内存空间中相同类型的数据聚合
接下来我会根据自己的理解写出在C语言中的数组与在JS中的数组
C语言中的数组就是我们在数据结构中所描述的最经典的数组,它有着如下的一些特点
数组在JS这一门语言中与C和C++就大有不同了,这是因为JS的数组的底层设计原因。
力扣链接:https://leetcode.cn/problems/binary-search/description/
二分查找这道题其实并不难理解,只要理解了二分法就可以了,其中最重要的就是要明白里面的一些坑,到底判断的是left< right 还是 left<=right right的初值是nums.length 还是 nums.lenght-1;在缩小范围的时候到底是加1 还是 不加1
二分法最重要的是要在一个有序数组中,如果数组无序,则二分法无法判断。
在有序的这个条件下,通过一个左右边界来找出中间值,通过传入的数与中间值的比较来丢弃掉一半的数,进而缩小范围,来达到快速搜索的理念。
在这里我们有两种方法 这两种方法就可以理解上面的一系列坑
左闭右闭区间
左闭右闭区间的意思就是,这个二分的范围的左边界和右边界都会纳入这一次的检查范围
根据上图我们就能充分明白左闭右闭区间中的各个判断条件
即 nums[mid] < target 时 left = mid +1
nums[mid] > target 时 right = mid -1
nums[mid] == target 时 return
而循环条件则是 left <= right 因为如图最后一次查询, 如果是left < right 则没有最后一次判断 直接 结束循环了
根据上图我们就能充分明白左闭右开区间中的各个判断条件
即 nums[mid] < target 时 left = mid +1
nums[mid] > target 时 right = mid
nums[mid] == target 时 return
而循环条件则是 left < right 因为right右边界是不计入当次检索范围的 所以若是let <= right的话则是不必要的
左闭右闭区间
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;
}
左闭右闭区间
/**
* @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种解法
快慢指针
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;
}
暴力
/**
* @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小时,今日的这几道题其实我也不是第一次刷了,在进入训练营之前也刷过一两遍代码随想录,但是没有特别的认真,都是比较粗略的一些想法,然后看一看代码随想录的思路,就稀里胡录的把代码写出来了,也没有进行一些复盘之类的,导致一些踩过的坑再刷仍然会踩,今天用心的理了思路,画了图,对题的记忆和解法更深刻了,对这些题也有一些自己的想法了,不像之前基本看着题没什么思路