以下题目都选自LeetCode中的算法问题:https://leetcode.com/problemset/algorithms/
1.Two Sum Easy难度
题目描述如下:
语言选择的是C++,下面是自动给出的解题类和函数声明:
题目强调了两点,1.返回值是indices也就是多个下标index,在这里是两个数字的下标,原本可以直接使用简单的int数组来存储结果,但是由于函数的返回值为vector,所以我们还是要使用相当于动态数组的vector来存储结果;
2.因为每个输入只有一个结果,且一个元素只能使用一次,所以我选择使用两个嵌套的循环来一一验证是否满足条件,在确保不重复的同时一旦有数字对满足条件即输出他们的下标结束程序。我们可以直接使用vector的函数调用:.size得出容器中实际数字的个数,来作为循环的终止。
代码如下:
下面是LeetCode上面的用int数组作为存储数据结构的solution,思路基本一致:
个人体会:
很按部就班的一道题,在思路上没有什么难度,实现方面,只要根据题目要求注意一些细节,掌握基础的vector用法就可以了。
2.进阶版:Three Sum medium难度
题目描述如下:
乍一看似乎和2Sum没有很大的差别,好像加多个循环就够了??
这道题难在选用何种方法找出符合条件的元组,涉及到了用合适的算法简化时间复杂度,如果单纯的加多一层循环则会导致超时问题。
题目细节暗示着你输出是从小到大排序的,如果意识到一开始就将vector排序(使用sort函数排序非常方便,时间复杂度为lgn),排除重复好像变得简单了,还可以避免不必要的匹配,比如第一个数如果大于0即可结束循环(因为不可能与之后的数相加等于0了)。然而单是排序并没有解决由算法导致的时间复杂度问题。
排序还有什么可以利用的优点?我们可以使用“控制变量法”,先固定第一个数,然后根据这个数控制另外两个数的大小(三个数和为0),这样一来排序的由小到大的优点就很清晰了,可以利用两个指针从vector两端同时开始遍历,然后根据这两个指针所对应数与“第一个数”之和的正负来调整指针大小!如果为正就减小“大指针”,为负就增大“小指针”,以此来找到和为0的平衡点。这样一来只要遍历一次就可以找出所有满足条件的元组了!
代码如下:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for(int i = 0; i < n - 2 && nums[i] <= 0; i++){
if(i != 0 && nums[i] == nums[i-1]){ //检查“第一个数”是否与之前数字重复
continue;
}
int s = i + 1, b = n - 1; //小数指针s,大数指针b
while(s < b){
int sum = nums[s] + nums[b] + nums[i];
if(sum > 0){
b--;
}
else if(sum < 0){
s++;
}
else{
vector<int> indices;
indices.push_back(nums[i]);
indices.push_back(nums[s]);
indices.push_back(nums[b]);
result.push_back(indices);
s++;
b--;
while(nums[s] == nums[s-1]){ //排除重复
s++;
}
while(nums[b] == nums[b+1]){
b--;
}
}
}
}
return result;
}
};
个人体会:
知道方法与不知道方法完全是两道题。