算法题-数组

1.数组理论基础

数组是存放在连续内存空间上的相同类型数据的集合
数组元素为相同类型的元素(同一类型元素所需要的存储空间大小一致,所以方便利用元素的索引来计算元素所在的位置)

数组可以通过下标索引的方式获取到下标对应的数据。
字符数组
注意:

  • 数组的下标是从0 开始的
  • 数组内存空间的地址是连续的

因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。

数组的元素是不能删的,只能覆盖。

二维数组在内存的空间地址是否连续:
在C++中二维数组在地址空间上是连续的;
但其他语言中二维数组在地址空间上不一定连续。

JavaScript中的数组:
同一个JavaScript数组的元素的数据类型可以不同,每个元素所需要的存储空间的大小不能确定,则数组没有办法通过元素的索引来计算某个元素对应的存储地址。
JavaScript的数组可以任意更改大小。

2.二分查找

LeetCode

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

实例:

输入: nums = [-1,0,3,5,9,12], target = 9     
输出: 4       
解释: 9 出现在 nums 中并且下标为 4     

前提条件:数组是有序数组,且数组中无重复元素(二分法的前提条件)

使用二分法时需要注意区间的定义,区间的定义为不变量。
区间的定义:左闭右闭 [left,right] 或左闭右开 [left,right)

二分法一
目标值target在左闭右闭的区间 [left, right]
注意:
while(left<=right) left==right时有意义
if(nums[middle]>target) right=middle-1; 目标值位于左区间

var search = function(nums, target) {
    let l = 0, r = nums.length - 1;
    // 区间 [l, r]
    while(l <= r) {
        let mid = (l + r) >> 1;
        if(nums[mid] === target) return mid;
        let isSmall = nums[mid] < target;
        l = isSmall ? mid + 1 : l;
        r = isSmall ? r : mid - 1;
    }
    return -1;
};

二分法二
目标值target在左闭右开的区间内 [left,right)
注意:
while (left<right) left==right时无意义
if(nums[middle]>target) right=middle; 目标值位于左区间

var search = function(nums, target) {
    let left=0,right=nums.length;
    while(left<right){
    let mid=(left+right)>>1;
    if(nums[mid]==target)
    return mid;
    left=nums[mid]<target ? mid+1 :left;
    right=nums[mid]<target ? right : mid;
    }
    return -1;
};

3.移出元素

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

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

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

示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。

暴力解法:
两层for循环,一个for循环遍历数组,查看是否有元素等于指定值,第二个for循环用于更新数组

var removeElement = function(nums, val) {
    var len=nums.length;
    for(var i=0;i<len;i++){
        if(nums[i]==val){
            for(var j=i+1;j<len-i;j++){
                nums[j-1]=nums[j];
            }
            i--;
            len--;
        }
        return len;
    }
};

双指针法:
(快慢指针法)通过快慢指针在一个for循环下完成两个for循环的工作。
慢指针寻找与给定值相同的元素,通过快指针更新数组的值。

function remove(nums,val){
    var slowIndex=0;
    for(var fastIndex=0;fastIndex<nums.length;fastIndex++){ //快指针用于遍历数组
        if(nums[fastIndex]!=val){ //若快指针对应的元素值等于给定值
            nums[slowIndex++]=nums[fastIndex]; //则快指针的值等于快指针的值(通过slowIndex++来移动安慢指针)
        } //若快指针的值与给定值相等,则慢指针处于原位置不动,当快指针移动到与给定值不相等的位置时,再将其赋值给慢指针,替换掉原相等的值,即移除该元素
        
    }
    console.log(slowIndex); //慢指针指向的是移除相等元素后数组的元素
};
remove([3,2,2,3,5,3,9,6],3);

4.有序数组的平方

LeetCode

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]

暴力排序
将数组中的元素直接平方再进行排序

//暴力排序
var sortedSquares=function(nums){
    for(var i=0;i<nums.length;i++){
        var a=nums[i]*nums[i];
    }
    nums.sort();
    console.log(nums);
}
sortedSquares([4,7,2,8,1]);

双指针法
因为数组是按从大到小的顺序来排序的,最大值和最小值都排列在数组的两端,最小值可能为负数,因此平方后的值两边的一定大于中间的。
定义双指针i和j, 定义一个和原数组大小相同的空数组,比较位于原数组两端元素的大小,将大的从尾部开始放入空数组中。

//双指针法
var sortedSquares=function(nums){
    var i=0,j=nums.length-1;
    var result=[];
    var k=nums.length-1;
    while(i<=j){
        if(nums[i]*nums[i]>=nums[j]*nums[j]){
        // if(Math.abs(nums[i])>=Math.abs(nums[j])){
            result[k]=nums[i]*nums[i];
            k--;
            i++;
        }else{
            result[k]=nums[j]*nums[j];
            k--;
            j--;
        }
    } 
    console.log(result);
}
sortedSquares([-4,-1,3,6,9]);

5.长度最小的子数组

LeetCode
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:
输入:s = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

暴力解法

滑动窗口
不断调节子序列的起始位置和末位置,找到符合条件的最短距离。
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,窗口的起始位置设置为数组的起始位置就可以了。

var minArray=function(nums,s){
    var i=0,j=0,sum=0,result=nums.length+1; //子数组的长度不可能超过原数组的长度
    while(i<nums.length){
        sum+=nums[i]; //滑动窗口的末位置
        while(sum>=s){ //当子数组长度大于等于给定值时
            result=(i-j+1)<result?(i-j+1):result; //最终子数组的长度(最小长度)
            sum-=nums[j];  //滑动窗口起始位置向右滑动
            j++;   
        }
        i++; 
    }
    console.log(result>nums.lenght ? 0 : result); //若子数组的长度仍然大于原数组长度,则证明未改变,没有符合结果,返回0
}
minArray([1,5,2,1,3,9],9);

6.螺旋矩阵II

leetcode
给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]

var generateMatrix = function(n) {
    // new Array(n).fill(new Array(n))
    // 使用fill --> 填充的是同一个数组地址
    const res = Array.from({length: n}).map(() => new Array(n));
    let loop = n >> 1, i = 0, //循环次数
        count = 1,
        startX = startY = 0; // 起始位置 
    while(++i <= loop) {
        // 定义行列
        let row = startX, column = startY;
        // [ startY, n - i)
        while(column < n - i) {
            res[row][column++] = count++;
        }
        // [ startX, n - i)
        while(row < n - i) {
            res[row++][column] = count++;
        }
        // [n - i ,  startY)
        while(column > startY) {
            res[row][column--] = count++; 
        }
        // [n - i ,  startX)
        while(row > startX) {
            res[row--][column] = count++;
        }
        startX = ++startY;
    }
    if(n & 1) {
        res[startX][startY] = count;
    }
    return res;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值