# 数组串相关算法
# 剑指 offer 专题
# 剑指 Offer 42. 连续子数组的最大和
输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
/**
* @param {number[]} nums
* @return {number}
*/
// 方法一: 优化前缀和
var maxSubArray = function(nums) {
let max = nums[0],
min = 0,
sum = 0;
for (let i = 0, len = nums.length; i < len; i++) {
sum += nums[i];
max = Math.max(sum - min, max);
min = Math.min(sum, min);
}
return max;
}
// 方法二: 动态规划
var maxSubArray = function(nums) {
let max = nums[0];
for (let i = 1, length = nums.length; i < length; i++) {
// 取非负数
nums[i] += Math.max(0, nums[i - 1]);
// 更新max
max = Math.max(nums[i], max);
}
return max;
};
# 剑指 Offer 40. 最小的k个数
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3, 2, 1], k = 2 输出:[1, 2] 或者 [2, 1] 示例 2:
输入:arr = [0, 1, 2, 1], k = 1 输出:[0]
/**
* @param {number[]} arr
* @param {number} k
* @return {number[]}
*/
// 方法一:借助数组原生的sort方法排序,然后截取前面k个数字
// var getLeastNumbers = function(arr, k) {
// return arr.sort((a, b) => a - b).slice(0, k);
// };
// 方法二: 快排
var getLeastNumbers = function(arr, k) {
function quickSort(arr = []) {
const len = arr.length;
if (len < 2) return arr;
const midIndex = len >> 1;
// 设置中间值为基准值,用来遍历每个元素作为比较值
// 注意:基准值需要从数组中去掉
const midValue = arr.splice(midIndex, 1)[0];
const left = [],
right = [];
for (let i = 0, _len = arr.length; i < _len; i++) {
const num = arr[i];
// 小于基准值的元素放左边
if (num < midValue) {
left.push(num);
} else {
// 大于基准值的元素放右边
right.push(num);
}
}
return [...getLeastNumbers(left), midValue, ...getLeastNumbers(right)];
}
arr = quickSort(arr);
return arr.slice(0, k);
}
# 剑指 Offer 10- I. 斐波那契数列
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2 输出:1 示例 2:
输入:n = 5 输出:5
/**
* @param {number} n
* @return {number}
*/
// 方法一: 暴力递归(可能会超出时间限制)
// var fib = function (n) {
// if (n <= 1) return n;
// return (fib(n - 1) + fib(n - 2)) % 1000000007;
// }
// 方法二:循环
// 根据数学定义:f(n) = f(n - 1) + f(n - 2)。最初始情况是f(0) = 0和f(1) = 1。
// 因此直接循环更新即可。时间复杂度 O(N),空间复杂度 O(1)。
// var fib = function (n) {
// if (n <= 1) return n;
// // prevTwo: 第n-2个数,prevOne: 第n-1个数
// let prevTwo = 0, prevOne = 1;
// for(let i = 1; i < n; i++) {
// const curr = prevTwo + prevOne;
// // 下一次的第一个数就是从上一次的第二个数开始
// prevTwo = prevOne;
// // 取模
// prevOne = curr % 1000000007;
// }
// return prevOne;
// }
// 方法三:暴力递归加个缓存
var fib = function(n) {
const cacheMap = new Map([
[0, 0],
[1, 1]
]);
if (n <= 1) return n;
function fibonacci(n) {
if (cacheMap.has(n)) return cacheMap.get(n);
const data = (fibonacci(n - 2) + fibonacci(n - 1)) % 1000000007;
cacheMap.set(n, data);
return data;
}
return fibonacci(n);
}
# 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
示例:
输入:nums = [1, 2, 3, 4] 输出:[1, 3, 2, 4] 注:[3, 1, 2, 4] 也是正确的答案之一。
/**
* @param {number[]} nums
* @return {number[]}
*/
// 方法一:借助奇数数组和偶数数组
// var exchange = function(nums) {
// if(nums.length < 2) return nums;
// // 左数组用来存放,右数组用来存放偶数
// const left = [], right = [];
// for(let i = 0, len = nums.length; i < len; i++) {
// const num = nums[i];
// // 按位与:奇数返回1,偶数返回0
// if(num & 1 === 1) left.push(num); // 奇数
// else right.push(num); // 偶数
// }
// return [...left, ...right];
// };
// 方法二:双指针法,确保奇数在偶数前面
var exchange = function(nums) {
const length = nums.length;
if (length === 0) return [];
let i = 0,
j = length - 1;
while (i < j) {
// 确保是奇数,直到找到是偶数的就停止循环
while (i < length && nums[i] % 2 === 1) i++;
// 确保是偶数,直到找到是奇数的就停止循环
while (j >= 0 && nums[j] % 2 === 0) j--;
// 找到了就交换元素位置
if (i < j) {
[nums[i], nums[j]] = [nums[j], nums[i]];
// 交换完毕,指针前进,继续循环
i++;
j--;
}
}
return nums;
}
# 剑指 Offer 04. 二维数组中的查找
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
/**
* @param {number[][]} matrix
* @param {number} target
* @return {boolean}
*/
var findNumberIn2DArray = function(matrix, target) {
if (matrix.length === 0) return false;
let flag = false;
for (let i = 0, len = matrix.length; i < len; i++) {
// 每一行的最后一个数(也是每一行中最大的)都比target小,那这一行就不用比较了,直接跳到下一行
if (matrix[i][matrix[i].length - 1] < target) continue;
for (let j = 0, _len = matrix[i].length; j < _len; j++) {
if (matrix[i][j] === target) {
flag = true;
break;
}
}
}
return flag;
};
# 剑指 Offer 66. 构建乘积数组
给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B 中的元素 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。
示例:
输入: [1,2,3,4,5] 输出: [120,60,40,30,24]
/**
* @param {number[]} a
* @return {number[]}
*/
var constructArr = function(a) {
const length = a.length;
if (length === 0) return [];
const result = [];
const left = new Array(length).fill(1),
right = new Array(length).fill(1);
// 构建左边乘积结果数组
for (let i = 1; i < a.length; i++) {
left[i] = a[i - 1] * left[i - 1];
}
// 构建右边乘积结果数组
for (let j = length - 2; j >= 0; j--) {
right[j] = a[j + 1] * right[j + 1];
}
console.log(left);
console.log(right);
for (let k = 0; k < length; k++) {
result[k] = left[k] * right[k];
}
return result;
};
# 把字符串转换成整数
TODO
# 最后
文中若有不准确或错误的地方,欢迎指出,有兴趣可以的关注下Github,一起学习呀~~