本周的3道题目,记录下,就当成一个练习的方式,出现题目简单与中等难度,还是比较适合的,其实题目就相当于我们的解决方式,学习更多就会写的更加多,提供的方法,学习的方法都可以,做题前可以看自己大脑如歌看,能在大脑中可以判断,解决问题,这个时候就是让大脑的思路变成逻辑,最总变成程序,有时候我们大脑能看题目能够解决问题,但是让你写代码的时候,不知道如何解决,慢慢练习就学会了。
第十四题:最长公共前缀
解题思路:这个题目出来后就发现,直接从0位置开始来比拼,一样就加到str中,知道不等。当第一个为都不等的情况,str不赋 值时间复杂度O(mn) m平均长度数,n为个数。
横向想法,第一个与第二个找到公共字符串,以此向后面找,知道遍历到最后一个。找到公共的部分向下找,时间复杂度O(mn) m平均长度数,n为个数。
string longestCommonPrefix(vector<string>& strs)
{
if (!strs.size())
{
return "";
}
int length = strs[0].size(); //获取第一个长度
int numOfstrs = strs.size(); //获取vector 的存储个数
for (int i = 0; i<length; i++)
{
char one = strs[0][i]; //获取第一字符串中第i个字符
for (int j =1; j<numOfstrs; j++)
{
if (i == strs[j].size() || strs[j][i] !=one)
{
return strs[0].substr(0, i);
}
}
}
//当把第一个数都遍历完了,表示第一个数就是最小公共前缀
return strs[0];
}
void testlongestCommonPrefix()
{
vector<string> strs = { "flower","flow","flight" };
string str = longestCommonPrefix(strs);
cout << "the public string is " << str << endl;
}
输出结果:
结果:
the public string is fl
第十五题:三数之和
解题思路:第一题目中是两个数相加,这个是3个数相加,第一题中,我提出是多个数对应的目标数,该如何处理呢。
依旧可以采用hashmap的方式来解决,当然要对数组进行排序,采用双指针来确定。
vector<vector<int> > threeSum(vector<int>& nums)
{
vector<vector<int>> result;
sort(nums.begin(), nums.end());
// 找出a + b + c = 0
// a = nums[i], b = nums[j], c = -(a + b)
for (int i = 0; i < nums.size(); i++) {
// 排序之后如果第一个元素已经大于零,那么不可能凑成三元组
if (nums[i] > 0) {
continue;
}
if (i > 0 && nums[i] == nums[i - 1]) { //三元组元素a去重
continue;
}
unordered_set<int> set;
for (int j = i + 1; j < nums.size(); j++) {
if (j > i + 2
&& nums[j] == nums[j - 1]
&& nums[j - 1] == nums[j - 2]) { // 三元组元素b去重
continue;
}
int c = 0 - (nums[i] + nums[j]);
if (set.find(c) != set.end()) {
result.push_back({ nums[i], nums[j], c });
set.erase(c);// 三元组元素c去重
}
else {
set.insert(nums[j]);
}
}
}
return result;
}
本题还可以直接使用双指针,来解决问题,使得重复部分给省略,我把大佬的代码也给上吧:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
// 找出a + b + c = 0
// a = nums[i], b = nums[left], c = nums[right]
for (int i = 0; i < nums.size(); i++) {
// 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
if (nums[i] > 0) {
return result;
}
// 错误去重方法,将会漏掉-1,-1,2 这种情况
/*
if (nums[i] == nums[i + 1]) {
continue;
}
*/
// 正确去重方法
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.size() - 1;
while (right > left) {
// 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组
/*
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
*/
if (nums[i] + nums[left] + nums[right] > 0) {
right--;
} else if (nums[i] + nums[left] + nums[right] < 0) {
left++;
} else {
result.push_back(vector<int>{nums[i], nums[left], nums[right]});
// 去重逻辑应该放在找到一个三元组之后
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
// 找到答案时,双指针同时收缩
right--;
left++;
}
}
}
return result;
}
第十六题:最接近的三数之和
解题思路:这个题目其实就是上个题目:3个数相加的变形,采用的方法依旧是双指针法。记录最小值的对应的数,去除重复的。
时间复杂度O(n).
int threeSumClosest(vector<int>& nums, int target)
{
sort(nums.begin(),nums.end()); //排序,
int n = nums.size();
int best = 1e7;
// 根据差值的绝对值来更新答案 lambda函数
auto updata = [&](int cur)
{
if (abs(cur - target) < abs(best-target))
{
best = cur;
}
};
for (int i =0; i<n; i++)
{
// 保证和上一次枚举的元素不相等
if (i >0 && nums[i] ==nums[i-1])
{
continue;
}
// 使用双指针枚举 b 和 c
int j = i + 1, k = n - 1;
while (j < k)
{
int sum = nums[i] + nums[j] + nums[k];
if (sum == target)
{
return target;
}
updata(sum);
//当和大于目标值的时候。
if (sum >target)
{
//如果和大于target,移动c 对应指针
int k0 = k - 1;
while (j <k0 && nums[k0]==nums[k])
{
--k0;
}
k = k0;
}
else
{
int j0 = j + 1;
//移动到下一个不相等的元素
while (j0 <k &&nums[j0] ==nums[j])
{
++j0;
}
j = j0;
}
}
}
return best;
}