来哟~做题吧
两数求和
题目描述:
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例: 给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1]
第一时间思路:
【两层循环】:
第一层循环遍历的值记为 a,第二层循环时遍历的值记为 b;若 a+b = 目标值,那么 a 和 b 对应的数组下标就是我们想要的答案
反思:
两层循环 O(n^2)->性能问题->空间换时间->优化为一层循环?
优化做法:
记住一个结论:几乎所有的求和问题,都可以转化为求差问题
步骤:
① Map方法:遍历 —— {当前值:索引值}
② target - 当前值 = ? , 这个差值要和前面遍历过的数字找,如果前面出现过,那么我们找到答案了\
以 nums = [2, 7, 11, 15] 这个数组为例
① 第一个数
② 第二个数:差值发现是之前出现过的值
const twoSum = function (nums, target) {
const diffs = {}
// 缓存数组长度
const len = nums.length
// 遍历数组
for (let i = 0; i < len; i++) {
// 判断当前值对应的 target 差值是否存在(是否已遍历过)
if (diffs[target - nums[i]] !== undefined) {
// 若有对应差值,那么答案get!
return [diffs[target - nums[i]], i]
}
// 若没有对应差值,则记录当前值
diffs[nums[i]] = i
}
};
console.log(twoSum([1,2,7,3,6],9)) // [1,2]
合并两个有序数组
题目描述:有序整数数组:nums1,nums2,将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
说明: 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
思路一:合并后排序
时间复杂度:O(n+m)*log(n+m)
空间复杂度:O(1)
思路二:双指针法\从后往前
推荐这个方法
时间复杂度:O(n+m)
空间复杂度:O(1)
const merge = function (nums1, m, nums2, n) {
// 初始化两个指针的指针,初始化 nums1 尾部索引k
let i = m - 1,
j = n - 1,
k = m + n - 1
// 当两个数组都没遍历完时,指针同步移动
while (i >= 0 && j >= 0) {
// 取较大的值,从末尾往前填补
if (nums1[i] >= nums2[j]) {
nums1[k] = nums1[i]
i--
k--
} else {
nums1[k] = nums2[j]
j--
k--
}
}
// nums2 留下的情况,特殊处理一下
while (j >= 0) {
nums1[k] = nums2[j]
k--
j--
}
return nums1
};
nums1 = [1, 2, 3, 0, 0, 0], m = 3
nums2 = [2, 5, 6], n = 3
console.log(merge(nums1, m, nums2, n)) // [ 1, 2, 2, 3, 5, 6 ]
三数求和
真题描述:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?
请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例: 给定数组 nums = [-1, 0, 1, 2, -1, -4]
满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]
暴力解题:三重循环
时间复杂度:O(N^3)
空间复杂度:O(1)
吸取第一题思路:把求和问题变成求差问题
双指针法-空间换时间,不过大前提是:数组必须有序!!
所以,首先排序
nums = nums.sort((a,b)=>{
return a-b
})
然后:对数组进行遍历,每次遍历到哪个数字,就固定哪个数字。然后把左指针指向该数字后面一个坑里的数字,把右指针指向数组末尾,让左右指针从起点开始,向中间前进
- 相加之和大于0,说明右侧的数偏大了,右指针左移
- 相加之和小于0,说明左侧的数偏小了,左指针右移
const threeSum = function (nums) {
// 用于存放结果数组
let res = []
// 给 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
};
const nums = [-1, 0, 1, 2, -1, -4]
console.log(threeSum(nums))
“对撞指针”
当出现两个关键词时:“有序”和“数组”,大脑马上出现“对撞指针”,即左右指针一起从两边向中间靠近。