LeetCode刷题总结:(2)查找表相关问题

1. 两数之和

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。

你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
// 思路: 利用查找表,一次遍历,寻找当前遍历的索引对应的target-nums[i],如果找到就返回,找不到就将当前的数据推入哈希表
class Solution {
public:
	vector<int> twoSum(vector<int>& nums, int target) {

		unordered_map<int, int> record;
		for (int i = 0; i < nums.size(); i++) {
			int element = target - nums[i];
			if (record.find(element) != record.end()) {
				int res[2] = { record[element],i };
				return vector<int>(res, res + 2);
			}

			record[nums[i]] = i;
		}

		throw invalid_argument("the input hao no solution");
	}
};

// 相似的题目: 15. 3sum 三数之和
//给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
//
//注意:答案中不可以包含重复的三元组。
//
//例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
//
//满足要求的三元组集合为:
//[
//	[-1, 0, 1],
//	[-1, -1, 2]
//]

// 思路: 将三数相加简单地分解为1+2
// 利用查找表,在索引之前的数据中寻找当前遍历的索引对应的target-nums[i]的两个索引的和
class Solution2 {
public:
	vector<vector<int>> threeSum(vector<int>& nums) {

		vector<vector<int>> result;
		unordered_map<int, int> record;
		for (int i = 0; i < nums.size(); i++) {
			int twoSumTarget = 0 - nums[i];
			unordered_map<int, int> recordTwoSum;
			vector<int> numsTwo;
			for (int j = 0; j < i; j++) {
				numsTwo.push_back(nums[j]);
			}

			for (int j = 0; j < numsTwo.size(); j++) {
				int element = twoSumTarget - nums[j];
				if (recordTwoSum.find(element) != recordTwoSum.end()) {
					int res[3] = { element,nums[j],nums[i] };
					result.push_back(vector<int>(res, res + 3));
				}
				else {
					recordTwoSum[nums[j]] = j;
				}
			}
		}

		return result;
	}
};



class Solution3 {
public:
	vector<vector<int>> fourSum(vector<int>& nums, int target) {

		if (nums.size() < 4)
			return vector<vector<int>>();

		vector<vector<int>> res;
		sort(nums.begin(), nums.end());
		int l = 0;
		int r = nums.size() - 1;
		while (r - l >= 3) {
			int i = l + 1;
			int j = r - 1;
			if (nums[l] + nums[l + 1] + nums[l + 2] + nums[r] > target)
				r--;
			else if (nums[l] + nums[r - 2] + nums[r - 1] + nums[r] < target)
				l++;
			else {
				int sumTarget = target - nums[l] - nums[r];
				while (i < j) {
					if (nums[i] + nums[j] == sumTarget) {
						int res_[4] = { nums[l],nums[i],nums[j],nums[r] };
						res.push_back(vector<int>(res_, res_ + 4));
					}
					else if (nums[i] + nums[j] < sumTarget)
						i++;
					else {
						j--;
					}
				}
			}
		}

		return res;
	}
};

 

149. 直线上最多的点数

给定一个二维平面,平面上有 个点,求最多有多少个点在同一条直线上。

示例 1:

输入: [[1,1],[2,2],[3,3]]
输出: 3
解释:
^
|
|        o
|     o
|  o  
+------------->
0  1  2  3  4

示例 2:

输入: [[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
// Definition for a point.
 struct Point {
     int x;
     int y;
     Point() : x(0), y(0) {}
     Point(int a, int b) : x(a), y(b) {}
 };

 // 思路: 选取一个基准点,然后计算剩余所有点与基准点的斜率,构建哈希表<斜率,数量>,遍历完所有基准点找出哈希表中的最大值即可,时间复杂度n平方
class Solution {
public:
	int maxPoints(vector<Point>& points) {

		if (points.size() == 0)
			return 0;
		int res = 0;
		// 遍历所有关键点
		for (int i = 0; i < points.size(); i++) {

			unordered_map<long double, int> record;
			int numSlopeMax = 0;
			int samePoint = 0;
			int res_tmp = 0;
			// 遍历当前关键点的其余边
			for (int j = 0; j < points.size(); j++) {
				if (j != i) {
					// 两点是同一位置的情况
					if (points[i].x == points[j].x && points[i].y == points[j].y)
						samePoint++;
					// 两点不同位置下,记录斜率不存在的情况
					else if (points[i].x == points[j].x) {
						numSlopeMax++;
						// 维护相同斜率点数的最大值
						if (numSlopeMax > res_tmp)
							res_tmp = numSlopeMax;
					}
					else {
						long double slope = calSlope(points[i], points[j]);
						// 相同斜率推进哈希表
						record[slope]++;
						// 维护相同斜率点数的最大值
						if (record[slope] > res_tmp)
							res_tmp = record[slope];
					}
				}
			}
			res_tmp += samePoint;
			if (res < res_tmp)
				res = res_tmp;
		}


		return res + 1;		// 加上自身的点
	}

private:
	static long double calSlope(const Point &p1, const Point &p2) {
		return (p1.y - p2.y) / (long double)(p1.x - p2.x);
	}
};

 

219. 存在重复元素 II

给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的绝对值最大为 k

示例 1:

输入: nums = [1,2,3,1], k = 3
输出: true

示例 2:

输入: nums = [1,0,1,1], k = 1
输出: true

示例 3:

输入: nums = [1,2,3,1,2,3], k = 2
输出: false
// 维护好一个长度为k的滑窗,查询当前遍历到的索引对应的值是否在滑窗中即可
class Solution {
public:
	bool containsNearbyDuplicate(vector<int>& nums, int k) {

		unordered_set<int> record;
		for (int i = 0; i < nums.size(); i++) {
			 
			// 查询一下是否存在
			if (record.find(nums[i]) != record.end())
				return true;
			// 维护好k长度的滑窗
			record.insert(nums[i]);
			if (record.size() == k + 1)
				record.erase(nums[i - k]);
		}

		return false;
	}
};

 

217. 存在重复元素contains - duplicate

给定一个整数数组,判断是否存在重复元素。

如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。

示例 1:

输入: [1,2,3,1]
输出: true

示例 2:

输入: [1,2,3,4]
输出: false

示例 3:

输入: [1,1,1,3,3,4,3,2,4,2]
输出: true
class Solution2 {
public:
	bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {

		set<long long> record;
		for (int i = 0; i < nums.size(); i++) {

			// 查询一下是否有在[v-t,v+t]之间的元素
			if (record.lower_bound((long long)nums[i] - t) != record.end())		// record.lower_bound(nums[i] - t),找到>=nums[i] - t的最小元素是否存在
				if (*record.lower_bound((long long)nums[i] - t) <= (long long)nums[i] + t)	// 得到>=nums[i] - t的最小元素的值
					return true;
			// 维护好k长度的滑窗
			record.insert(nums[i]);
			if (record.size() == k + 1)
				record.erase(nums[i - k]);
		}

		return false;
	}
};

 

447. 回旋镖的数量

给定平面上 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]]
// 为中间的枢纽点创建边长的哈希表<dis,fre>,以中间点为枢纽寻找等边的组合
class Solution {
public:
	int numberOfBoomerangs(vector<pair<int, int>>& points) {

		int res = 0;
		for (int i = 0; i < points.size(); i++) {
			unordered_map<int, int> record;
			// 创建此点的边长哈希表
			for (int j = 0; j < points.size(); j++) {
				if (j != i) {
					record[dis(points[i], points[j])]++;
				}
			}

			// 遍历哈希表,计算存在两边长相等的组合
			for (auto iter = record.begin(); iter != record.end(); iter++) {
				res += iter->second*(iter->second - 1);
			}
		}

		return res;
	}

private:
	int dis(const pair<int, int> &pa, const pair<int, int> &pb) {
		return (pa.first - pb.first)*(pa.first - pb.first) + (pa.second - pb.second)*(pa.second - pb.second);
	}
};

 

454. 四数相加 II

给定四个包含整数的数组列表 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
// 思路: 将向量C和D组合成哈希表,key为sum和,value为相应的组合数
class Solution {
public:
	int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {

		int res = 0;
		// 完成哈希查找表
		unordered_map<int, int> record;
		for (int i = 0; i < C.size(); i++) {
			for (int j = 0; j < D.size(); j++) {
				record[C[i] + D[j]]++;
			}
		}
		// 双层遍历查找组合数
		for (int i = 0; i < A.size(); i++) {
			for (int j = 0; j < B.size(); j++) {
				if (record.find(0 - A[i] - B[j]) != record.end()) {
					res += record[0 - A[i] - B[j]];
				}
			}
		}

		return res;
	}
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值