49. 字母异位词分组
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
说明:
- 所有输入均为小写字母。
- 不考虑答案输出的顺序。
/**
* @param {string[]} strs
* @return {string[][]}
*/
var groupAnagrams = function(strs) {
// 字符长度为0直接返回
if(strs.length === 0)
return [];
// 用map记录每个code所对应的字符串数组,code表示每个字符串每个字母的编码值,是一个长度为26位的数组,每一位表示该字母出现的次数
const map = new Map();
// 遍历输入的字符串数组
for(const str of strs) {
// 初始化code数组为全0
const characters = Array(26).fill(0);
// 遍历每一个字符串的所有字母
for(let i = 0; i < str.length; i++) {
// 找到该字母对应的位置,将ascii值转换为从0-25的一个数,97为a的ASCII值
const ascii = str.charCodeAt(i) - 97;
// 该字母出现次数加一
characters[ascii]++;
}
// 将code数组转为字符串,作为map的键
const key = characters.join(".");
// 如果map有对应的code,将字符串加入此code对应的数组中
if(map.has(key)) {
map.set(key, [...map.get(key), str]);
}else{
// 否则该字符组合未出现过,作为一个新的键值对加入map中
map.set(key, [str]);
}
}
const result = [];
// 采用for of遍历map,迭代器每次为一个数组arr, 其中arr[0]为key, arr[1]为value
for(const arr of map) {
result.push(arr[1])
}
return result;
};
53. 最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [0]
输出:0
示例 4:
输入:nums = [-1]
输出:-1
示例 5:
输入:nums = [-100000]
输出:-100000
提示:
- 1 <= nums.length <= 3 * 104
- -105 <= nums[i] <= 105
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function (nums) {
// 记录每一个位置对应的最大子序和
const memo = [];
// 初始时只有一个元素
memo[0] = nums[0];
// max记录所有最大子序和的最大值,作为整个数组的最大子序和
let max = nums[0];
// 循环遍历数组的每一个元素
for (let i = 1; i < nums.length; i++) {
// 动态规划,计算当前的最大子序和: Max(从第一个元素到当前数字的序列和, 从当前数字起的序列和)
memo[i] = Math.max(nums[i] + memo[i - 1], nums[i]);
// 更新max
max = Math.max(max, memo[i]);
}
return max;
};
54. 螺旋矩阵
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
/**
* @param {number[][]} matrix
* @return {number[]}
*/
var spiralOrder = function (matrix) {
// 矩阵为空则返回空数组
if (matrix.length === 0) {
return [];
}
// 定义上下左右边界值
let top = 0;
let bottom = matrix.length - 1;
let left = 0;
let right = matrix[0].length - 1;
// 定义当前方向,方向的变化顺序为right->down->left->up->right->...
let direction = "right";
let result = [];
// 循环遍历矩阵,当右边界大于等于左边界,下边界大于等于上边界时执行循环
while (left <= right && top <= bottom) {
if (direction === "right") {
for (let i = left; i <= right; i++) {
result.push(matrix[top][i]);
}
top++;
direction = "down";
} else if (direction === "down") {
for (let i = top; i <= bottom; i++) {
result.push(matrix[i][right]);
}
right--;
direction = "left";
} else if (direction === "left") {
for (let i = right; i >= left; i--) {
result.push(matrix[bottom][i]);
}
bottom--;
direction = "top";
} else if (direction === "top") {
for (let i = bottom; i >= top; i--) {
result.push(matrix[i][left]);
}
left++;
direction = "right";
}
}
return result;
};
55. 跳跃游戏
给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
示例 1:
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:
输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
/**
* @param {number[]} nums
* @return {boolean}
*/
var canJump = function(nums) {
// 记录到达当前位置最少需要的步数
let maxJump = nums.length - 1;
// 贪心法,自底向上。从后往前遍历数组
for(let i = nums.length - 2; i >=0; i--) {
// 如果当前位置(maxJump)的前一个元素能跳到当前位置,则更新maxJump
if(i + nums[i] >= maxJump) {
maxJump = i;
}
}
// 如果能遍历完数组,则说明问题有解
return maxJump === 0;
};
56. 合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
提示:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
/**
* @param {number[][]} intervals
* @return {number[][]}
*/
var merge = function(intervals) {
// 数组为空或长度为一时直接返回
if(intervals.length < 2) {
return intervals;
}
// 将元素按照区间左端点排序
intervals.sort((a, b) => a[0] - b[0]);
// 用于记录当前合并的最大的数组
let curr = intervals[0];
let result = [];
// 循环遍历区间数组
for(let interval of intervals) {
// 如果后一个区间的左端点小于等于当前区间的右端点,则合并这两个区间
if(curr[1] >= interval[0]) {
curr[1] = Math.max(curr[1], interval[1]);
} else {
// 否则将当前最大的区间加入结果集中,并更新位置
result.push(curr);
curr = interval;
}
}
// 注意最后一个区间不存在下一个区间来比较,直接加入结果集
result.push(curr);
return result;
};