数组基础知识
数组是存放在连续内存空间上的相同类型数据的集合。
特点:
- 数组下标都是从0开始的。
- 数组内存空间的地址是连续的
- 易读取
- 难增删
简单
二分查找
二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
方法:二分查找(闭区间)
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
let left = 0, right = nums.length-1
while(left <= right){
let mid = left + Math.floor((right - left)/2)
if(nums[mid] > target){
right = mid - 1
}else if(nums[mid] < target){
left = mid +1
}else{
return mid
}
}
return -1
};
移除元素
移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
方法一:暴力
两层循环
var removeElement = function (nums, val) {
let len = nums.length;
// 遍历数组元素,查找val
for (let i = 0; i < len; i++) {
// 找到val
if (nums[i] == val) {
// 将val后面的数组元素整体前移1位
for (let j = i + 1; j < len; j++) {
nums[j - 1] = nums[j];
}
// 下标i之后的数值都前移1位,所以i也向前移1位
i--;
// 数组长度-1
len--;
}
}
return len;
};
方法二:双指针
var removeElement = function (nums, val) {
let fast = 0,
slow = 0,
len = nums.length;
while (fast < len) {
if (nums[fast] != val) {
nums[slow] = nums[fast];
slow++;
}
fast++;
}
return slow;
};
有序数组的平方
有序数组的平方
给你一个按 非递减顺序 排序的整数数组 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) {
let len = nums.length;
let res = [];
let left = 0,
k = len - 1;
right = len - 1;
while (left <= right) {
let leftNum = nums[left] * nums[left];
let rightNum = nums[right] * nums[right];
if (leftNum < rightNum) {
res[k--] = rightNum;
right--;
} else {
res[k--] = leftNum;
left++;
}
}
return res;
};
中等
长度最小的子数组
长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
方法:滑动窗口
var minSubArrayLen = function (target, nums) {
let len = nums.length;
// 窗口开始指针
let i = 0;
// 窗口末尾指针
let j = 0;
// 窗口里值的和
let sum = 0;
let res = Infinity;
// 遍历,增大窗口
for (; j < len; j++) {
// 更新窗口值和
sum += nums[j];
// 当窗口值和大于等于目标值
while (sum >= target) {
// 计算窗口现在长度
let nowLen = j - i + 1;
// 比较更新最小窗口长度
res = Math.min(res, nowLen);
// 缩小窗口:窗口开始指针右移,更新窗口值和
sum -= nums[i++];
}
}
return res == Infinity ? 0 : res;
};
类似题目
最小覆盖子串
输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”
var minWindow = function(s, t) {
let maxLength = 100000, maxStartIndex = -1;
let needWhich = {}; // 这里存 t 子串中各字符的数量,即需要满足的个数
let windowAll = {}; // 这里存滑动窗口遍历过程中,处于滑动窗口内部的 t 中的字符
// 初始化 needWhich,总共需要哪些字符
for(let val of t) {
needWhich[val] = (needWhich[val] || 0) + 1;
}
let left = 0, right = 0;
let len = s.length, nowSatisfy = 0; // 要多少个键值对满足 needWhich 中的才算覆盖
while(right < len) {
const key = s[right]; // 右指针当前遍历到的字符
right++;
// 如果是 t 字符串中字符
if(needWhich[key]) {
windowAll[key] = (windowAll[key] || 0) + 1; // 当前滑动窗口的该键,值 + 1
// 如果读取到这个字符后,该字符总数 === 覆盖的子串中的该字符总数了,那就总数 + 1
if(windowAll[key] === needWhich[key]) {
nowSatisfy++;
}
}
// 当验证数量与需要的字符个数一致时,就应该收缩窗口了
while(nowSatisfy === Object.keys(needWhich).length) {
// 更新最小覆盖子串
if (right - left < maxLength) {
maxStartIndex = left;
maxLength = right - left;
}
//即将移出窗口的字符
const outKey = s[left];
// 窗口左边界右移
left++;
// 如果是 t 字符串中字符
if(needWhich[outKey]) {
// 对于要移出窗口的这个字符的个数,如果 窗口内部 和 t 中的相同,即没有多余,那么 nowSatisfy--,开始找下一滑动窗口了,否则还得继续移除该字符
if (windowAll[outKey] === needWhich[outKey]) {
nowSatisfy--;
}
windowAll[outKey]--;
}
}
}
return maxStartIndex === -1 ? "" : s.slice(maxStartIndex, maxStartIndex + maxLength);
};
螺旋矩阵
螺旋矩阵
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
var spiralOrder = function(matrix) {
let len1=matrix.length,len2=matrix[0].length
let res=[]
let left=0,right=len2-1,top=0,bottom=len1-1
while(left<=right&&top<=bottom){
// 从左到右
for(len2=left;len2<=right;len2++){
res.push(matrix[top][len2])
}
// 从上到下
for(len1=top+1;len1<=bottom;len1++){
res.push(matrix[len1][right])
}
if(left<right&&top<bottom){
// 从左到右
for(let len2=right-1;len2>left;len2--){
res.push(matrix[bottom][len2])
}
// 从下到上
for(let len1=bottom;len1>top;len1--){
res.push(matrix[len1][left])
}
}
[left,right,top,bottom]=[left+1,right-1,top+1,bottom-1]
}
return res
};
console.log(spiralOrder([[1,2,3,4],[5,6,7,8],[9,10,11,12]]))
题目来源力扣