两数之和
/*
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
*/
export function twoNumberAdd(nums: number[], target: number) {
// 思路:我们可以在遍历数组的过程中,增加一个Map结构来存储已经遍历过的数字及其对应的索引值。然后每遍历到一个新数字的时候,都回到Map里去查询targetNum与该数的
// 差值是否已经在前面出现过,若出现过则答案已经显现,我们就不在往下走了。
let diffs = {}
for (let i = 0; i < nums.length; i++) {
// 判断当前值与target的差值是否存在
if (diffs[target - nums[i]] !== undefined) {
return [diffs[target - nums[i]], i]
}
// 若没有对应差值,则记录当前值
diffs[nums[i]] = i
}
}
三数之和
/*
三数之和
给你一个包含那个整数的数组nums,判断nums中是否存在三个元素a,b,c使得a+b+c=0,请你找出所有满足条件且重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组nums = [-1, 0, 1, 2, -1, -4],
满足条件的三元组集合为
[
[-1, 0, 1],
[-1, -1, 2]
]
思路:
跟两数之和一样,我们把求和的问题变成求差的问题:固定其中一个数,在剩下的数中寻找是否有两个数的和
和这个固定的数相加和是0
这里才用 双指针法 来解决问题,相比三层循环,效率会大大提升。
*/
/*
双指针法的适用范围比较广,一般像求和,比大小都可用它来解决,但是有一个前提:数组必须有序。
*/
/*
因此我们的第一步是给数组进行排序,升序排列
nuns = nums.sort((a, b) => {
return a - b
})
然后对数组进行遍历,每遍历到哪个数字,就固定当前数字。同时左指针指向该数字后面的紧邻的那个数字,
右指针指向数组末尾。然后左右指针分别向中间靠拢
每次指针移动一次位置,就计算一下两个指针指向数字之和加上固定的那个数之后,是否等于0。如果是,
那我们就得到了一个目标组合;否则,分两种情况来看:
1.相加之和大于0,说明右侧的数偏大,右指针左移
2.相加之和小于 0,说明左侧的数偏小了,左指针右移
*/
threeSum(nums: number[]) {
// 用于存放结果的数组
let res: any = []
// 给nums排序
nums = nums.sort((a, b) => {
return a - b
})
// 缓存数组的长度
const len = nums.length
for (let i = 0; i < len - 2; i++) {
// 左指针j
let j = i + 1
// 右指针k
let k = len - 1
// 如果遇到重复的数字 则跳过
if (i > 0 && nums[i] === nums[i - 1]) {
continue
}
while (j < k) {
// 三数之和小于0,左指针前进
if (nums[i] + nums[j] + nums[k] < 0) {
j++
// 处理左指针元素重复的情况
while (j < k && nums[j] === nums[j - 1]) {
j++
}
} else if (nums[i] + nums[j] + nums[k] > 0) {
// 三数之和大于0,右指针后退
k--
// 处理右指针元素重复的情况
while (j < k && nums[k] === nums[k + 1]) {
k--
}
} else {
res.push([nums[i], nums[j], nums[k]])
// 左右指针一起前进
j++
k--
// 若左指针元素重复,跳过
while (j < k && nums[j] === nums[j - 1]) {
j++
}
// 若右指针元素重复,跳过
while (j < k && nums[k] === nums[k + 1]) {
k--
}
}
}
}
// 返回结果数组
return res
}
盛最多水的容器
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
maxArea(heightArr) {
let max = 0
let i = 0
let j = heightArr.length - 1
while (i < j) {
let minHeight = Math.min(heightArr[i], heightArr[j])
let area = (j - i) * minHeight
max = Math.max(max, area)
// 如果左侧小于右侧,则i++,否则j--(这一步其实就是取所有高度中比较高的,我们知道面积等于长*宽)
if (heightArr[i] < heightArr[j]) {
i++
} else {
j--
}
}
}