哈希表
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。
链接
题解
该题目的关键在于遍历循环数组,在遍历的过程中,记录目前值与target的差值,且使用map记录差值情况,若存在差值,则直接返回差值
function twoSum(nums: Array<number>, target: number) {const len = nums.length;const hashMap = new Map();for(let i = 0; i < len; i++) {// 计算当前值与target的差值const targetNew = target - nums[i];if (hashMap.has(targetNew)) {// 如果存在该差值,则直接返回 [该差值的下标, 与当前值的下标]return [hashMap.get(targetNew), i];} else {// 暂时不存在差值,存入当前值的下标hashMap.set(nums[i], i);}}
};// const arr = twoSum([3,2,4], 6);
// console.log({ arr });
2. 字母异位词分组
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
链接
题解
该题目在于将每一项数据根据Unicode编码排序,异位词经过排序后的字符串会相等,后使用map记录数据即可。
function groupAnagrams(strs: string[]): string[][] {const len = strs.length;// 讲异位词归类成一个数组 {'ab': ['ab', 'ba']}const hashMap = new Map<string, string[]>();// 遍历字符串数组for(let i = 0; i < len; i++) {const temp = strs[i];// 字符串转化为数组 ['b', 'a']const newStr = (Array.from(temp) as string[])// 按Unicode编码排序 ['a', 'b'].sort((a, b) => a.charCodeAt(0) - b.charCodeAt(0))// 拼接成字符串 ['ab'].reduce((a, b) => `${a}${b}`, '');if (hashMap.has(newStr)) {// 如果存在异位词,则推进数组(hashMap.get(newStr) || []).push(temp);} else {// 不存在异位词,则set初始化数组hashMap.set(newStr, [temp]);}}const res: string[][] = [];// 输出结果hashMap.forEach((value) => {res.push(value);});return res;
};// const arr = groupAnagrams(['abc', 'cab', 'de', 'ed']);
// // { arr: [ [ 'abc', 'cab' ], [ 'de', 'ed' ] ] }
// console.log({ arr });
3.最长连续序列
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
链接
题解:
function longestConsecutive(nums: number[]): number {// 去重 [100, 4, 4, 200, 1, 3, 2] => [100, 4, 200, 1, 3, 2]let num_set: Set<number> = new Set([...nums]);// 记录当前最长连续序列长度let longestStreak = 0;for (const num of num_set) {// 遍历if (!num_set.has(num - 1)) {// 如果不存在比当前值小1的值,则当前值作为起点// 如100, 1可以作为起点let currentNum = num;// 记录当前最长连续序列长度let currentStreak = 1;while (num_set.has(currentNum + 1)) {// 遍历,找比当前值大1的数currentNum += 1;currentStreak += 1;}// 更新最大长度longestStreak = Math.max(longestStreak, currentStreak);}}return longestStreak;
};// const num = longestConsecutive([100, 4, 4, 200, 1, 3, 2]);
// // { num: 4 }
// console.log({ num });
指针
4.移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
链接
题解
// 快排思想
function moveZeroes(nums: Array<number>) {if (nums.length === 1) {return nums;}let left = 0;for (let right = 0; right < nums.length; right++) {if (nums[right] !== 0) {// 右边不等于0if (nums[left] === 0) {// 左边等于0[nums[right], nums[left]] = [nums[left], nums[right]];}// 找到了右边不等于0的目标元素,移动左指针寻找等于0的元素left++;}}return nums;
};// const arr = moveZeroes([0, 1, 0, 3, 12]);
// // { num: 4 }
// console.log({ arr });
5.盛水最多的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
说明:你不能倾斜容器。
链接
题解
左右指针法,每次移动短的指针能才有机会使容纳的水变多,因为左右指针收窄时,形成的容器的底是变小的,而能存多少水,容器的高也是一个决定性因素,根据木桶原理,短的木板决定水桶能装多少水,在底变小的情况下,移动短的指针有机会遇到更长的木板,使得容积变大。移动过程中,更新最大值即可。
function maxArea(height: Array<number>): number {let left = 0, right = height.length - 1;let res = 0;while(left < right) {// 底const bottom = right - left;// 高const h = Math.min(height[left], height[right]);// 更新最大值res = Math.max(res, bottom * h);if (height[left] > height[right]) {// 右边小,移动小的right--;} else {// 左边小,移动小的left++;}}return res;
};// const num = maxArea([1, 8, 6, 2, 5, 4, 8, 3, 7]);
// // { num: 49 }
// console.log({ num });