四数相加
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过 231 - 1
示例:
输入:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
输出:
2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
- 解题思路
- 暴力解法,时间复杂度 O(n^4)
- D 中的元素放入查找表,时间复杂度 O(n^3)
- 将 A + B 的每一种可能放入查找表,然后 两重循环对在查找表中寻找是否存在 -(C[i] + D[i]),时间复杂度为 O(n^2)。两数相加的和作为键值
//执行用时 :144 ms, 在所有 javascript 提交中击败了81.95%的用户
//内存消耗 :51.3 MB, 在所有 javascript 提交中击败了69.23%的用户
var fourSumCount = function (A, B, C, D) {
let sumMap = new Map();
let count = 0;
for (let a of A) {
for (let b of B) {
sumMap.set(a + b, sumMap.get(a + b) ? sumMap.get(a + b) + 1 : 1);
}
}
for (let c of C) {
for (let d of D) {
let target = 0 - c - d;
if (sumMap.has(target)) {
count += sumMap.get(target);
}
}
}
return count;
};
字母异位词分组
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。说明:所有输入均为小写字母且不考虑答案输出的顺序。
示例:
输入: ["eat", "tea", "tan", "ate", "nat", "bat"],
输出:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
- 排序后的字符串作为key
//执行用时 :156 ms, 在所有 javascript 提交中击败了62.75%的用户
//内存消耗 :45.7 MB, 在所有 javascript 提交中击败了55.43%的用户
var groupAnagrams = function (strs) {
var tag = {};
var res = [];
strs.forEach((item) => {
let oderStr = item.split('').sort().join('');
if (tag.hasOwnProperty(oderStr)) {
tag[oderStr].push(item);
} else {
tag[oderStr] = [item];
}
})
for (var key in tag) {
res.push(tag[key]);
}
return res;
};
- map
//执行用时 :144 ms, 在所有 javascript 提交中击败了83.75%的用户
//内存消耗 :47.1 MB, 在所有 javascript 提交中击败了29.34%的用户
const groupAnagrams = function (strs) {
let sMap = new Map();
for (let ss of strs) {
let curr = ss.split('').sort(function (a, b) {
return a.charCodeAt(0) - b.charCodeAt(0);
}).join('');
let tmp = (sMap.get(curr) || []);
tmp.push(ss);
sMap.set(curr, tmp);
}
return Array.from(sMap.values()); //return [... sMap.values()];
};
回旋镖的数量
给定平面上 n 对不同的点,“回旋镖” 是由点表示的元组 (i, j, k) ,其中 i 和 j 之间的距离和 i 和 k 之间的距离相等(需要考虑元组的顺序)。找到所有回旋镖的数量。你可以假设 n 最大为 500,所有点的座标在闭区间 [-10000, 10000] 中。
示例:
输入:
[[0,0],[1,0],[2,0]]
输出:
2
解释:
两个回旋镖为 [[1,0],[0,0],[2,0]] 和 [[1,0],[2,0],[0,0]]
- 解题思路
- 暴力解法:三重循环枚举所有的可能性。 时间复杂度为:O(n^3)
- 使用查找表:观察到 i 是一个 “枢纽”,对于每个点i,遍历其余点到 i 的距离对于每个枢纽i,计算它到其它点j的距离,并将距离作为键存入字典 dict 中,value为距离的个数。时间复杂度为:O(n^2)。 距离作为键值
//执行用时 :180 ms, 在所有 javascript 提交中击败了89.47%的用户
//内存消耗 :41.7 MB, 在所有 javascript 提交中击败了59.38%的用户
var numberOfBoomerangs = function (points) {
var len = points.length;
var count = 0;
for (let i = 0; i < len; i++) {
let sumMap = new Map();
for (let j = 0; j < len; j++) {
if (i === j) continue;
let sum = getDis(points[i], points[j]); //节省内存可以直接计算d = dx * dx + dy * dy
if (sumMap.has(sum)) {
let num = sumMap.get(sum);
count += num;
sumMap.set(sum, num + 1);
} else {
sumMap.set(sum, 1);
}
//上述map条件判断可以简写为 let count = ~~map.get(dis);
}
}
return count * 2;
};
function getDis(point1, point2) {
return (point1[0] - point2[0]) * (point1[0] - point2[0]) + (point1[1] - point2[1]) * (point1[1] - point2[1]);
}
直线上最多的点数
给定一个二维平面,平面上有 n 个点,求最多有多少个点在同一条直线上。
示例:
输入: [[1,1],[2,2],[3,3]]
输出: 3
解释:
^
|
| o
| o
| o
+------------->
0 1 2 3 4
输入: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
输出: 4
解释:
^
|
| o
| o o
| o
| o o
+------------------->
0 1 2 3 4 5 6
- 两点可以确定一条直线,那么选择固定一个点,求其他点与固定点的斜率,如果斜率相同,那么斜率相同的点在同一条直线上。同时要考虑,斜率可能为无穷大,也有可能两个点为同一个点。键值应该为:斜率
//执行用时 :88 ms, 在所有 javascript 提交中击败了78.05%的用户
//内存消耗 :38 MB, 在所有 javascript 提交中击败了60.00%的用户
var maxPoints = function (points) {
//求最大公约数
function gcd(x, y) {
if (y === 0) {
return x;
}
return gcd(y, x % y);
}
if (points.length <= 2) {
return points.length;
}
let result = Number.MIN_SAFE_INTEGER;
for (let i = 0; i < points.length - 1; ++i) {
let max = 0;
let repeat = 0;
let slope = new Map();
for (let j = i + 1; j < points.length; ++j) {
let dx = points[i][0] - points[j][0];
let dy = points[i][1] - points[j][1];
if (dy === 0 && dx === 0) {
++repeat;
continue;
}
const g = gcd(dy, dx);
if (g !== 0) {
dx /= g;
dy /= g;
}
const key = `${dx}/${dy}`;
let count = (slope.get(key) || 0) + 1;
slope.set(key, count);
max = Math.max(max, count);
}
result = Math.max(result, repeat + max + 1);
}
return result;
};
//执行用时 :112 ms, 在所有 javascript 提交中击败了48.78%的用户
//内存消耗 :38.5 MB, 在所有 javascript 提交中击败了60.00%的用户
var maxPoints = function (points) {
if (points.length == 0)
return 0;
var result = 0,
pointsMap = new Map();
for (var i = 0; i < points.length; i++) {
if (pointsMap.has(points[i].toString())) {
pointsMap.set(points[i].toString(), pointsMap.get(points[i].toString()) + 1); //统计相同座标数
} else {
pointsMap.set(points[i].toString(), 1);
}
}
var pointsArr = [...pointsMap]; //解构赋值,包含key和value的二维数组
console.log(pointsArr);
if (pointsArr.length == 1)
return pointsArr[0][1];
for (var i = 0; i < pointsArr.length; i++) {
var map = new Map();
for (var ii = i + 1; ii < pointsArr.length; ii++) {
var res = 0;
if (pointsArr[i][0].split(",")[0] - pointsArr[ii][0].split(",")[0] === 0) //x轴座标相同
res = "y";
if (pointsArr[i][0].split(",")[1] - pointsArr[ii][0].split(",")[1] === 0) //y轴座标相同
res = "x";
res = res == 0 ? (pointsArr[i][0].split(",")[0] - pointsArr[ii][0].split(",")[0]) / (pointsArr[i][0].split(",")[1] - pointsArr[ii][0].split(",")[1]) : res; //
if (map.has(res)) {
map.set(res, map.get(res) + pointsArr[ii][1]); //相同斜率下,相同y座标的数量
} else {
map.set(res, pointsArr[ii][1] + pointsArr[i][1]); //重复座标数
}
}
map.forEach((value, key) => {
result = result > value ? result : value;
});
}
return result;
};
来源:力扣(LeetCode)https://leetcode-cn.com