最近写了两道LeetCode题目,都是Medium题目,不难,但是我觉得两个题目的解题思路都差不多,而且我平时很少使用这种解题方法,所以放在一起。
LeetCode15三数之和
1 题目描述
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[[-1, 0, 1], [-1, -1, 2]]
2 解题思路及代码
这道题目如果暴力求解时间复杂度是o(
n
3
n^3
n3),会超时,不能通过所有的样例。这里用的是两个指针,时间复杂度为o(
n
2
n^2
n2),可以通过所有样例。
解题思路是固定一个数字的位置i,设定两个指针j和k,j初始化为i+1,k初始化为size-1(其中size为vector的大小)。两个指针一起向中间移动。刚开始需要把nums进行排序成从小到大。每次判断nums[i]+nums[j]+nums[k]是大于0,小于0,还是等于0.如果大于0,说明还需要减小nums[i]+nums[j]+nums[k]也就是三数之和,就只能增大j,因为k已经在最右边是最大值了不能再增大了。如果小于0,说明还需要增大nums[i]+nums[j]+nums[k]也就是三数之和,就只能减小k,因为j已经在最左边是最小值了不能再减小了。这样一直比较直到j和k相遇,就终止退出本次循环,此时没必要继续增大j或者减小k了,因为继续改变就相当于是在重复之前的情况。如果等于0,说明找到了一种排列,存储的同时,还需要判断j右边的值是否等于j位置的值,k左边的值是否等于k位置的值,如果有相等的情况需要相应的j+1以及k-1,这是为了去重,因为题目中明确说答案中不可以包含重复的三元组。
在外面的循环也需要判断当前位置i的元素是否等于前面i-1位置的元素,也是为了去重,因为既然前面已经考虑过这个值了,后面就没必要再做了。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int j,k;
vector<vector<int>>ans;
vector<int>mid;
if(nums.size()<3)
return ans;
sort(nums.begin(),nums.end());
for(int i=0;i<(nums.size()-2);i++)//固定第一个数字的位置
{
if(i!=0)
{
if(nums[i]==nums[i-1])//去重
continue;
}
j=i+1;
k=nums.size()-1;
while(j<k)
{
if((nums[i]+nums[j]+nums[k])<0)
{
j++;
continue;
}
if((nums[i]+nums[j]+nums[k])>0)
{
k--;
continue;
}
if((nums[i]+nums[j]+nums[k])==0)
{
mid.clear();
mid.push_back(nums[i]);
mid.push_back(nums[j]);
mid.push_back(nums[k]);
ans.push_back(mid);
while(nums[j]==nums[j+1])//去重
{
j++;
if(j>=k)
break;
}
while(nums[k]==nums[k-1])//去重
{
k--;
if(j>=k)
break;
}
j++;
k--;
}
}
}
return ans;
}
};
LeetCode3无重复字符的最长子串
1 题目描述
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
2 解题思路及代码
我觉得这个题目的解题思路跟上面是差不多的。也是用到了两个指针k和j,使得复杂度控制为o(
n
2
n^2
n2)。如果不使用两个指针,直接做复杂度也是o(
n
3
n^3
n3),会超时。
思路也是固定字符串的位置i,i是当前不重复字符串的最后一个字符所在的位置,相当于也是考虑到了所有的情况。寻找当前不重复字符串的第一个字符所在的位置j,是通过k指针,判断k位置的字符是否等于i位置的字符,如果等于,就将第一个字符所在的位置j赋值为k+1.每次判断当前不重复字符串的长度是否大于之前的,存储最大的结果在ans中。这里我认为这种思路可以解决问题依靠的前提是每次循环的时候,当前位置i前面的j到i-1之间的所有字符都是不重复的,所以如果发现j到i-1之间某一个位置k的字符等于i位置的字符,直接将j赋值为k+1就可以保证当前的j到i之间的字符是不重复的,也就是得到当前以i为最后一个字符的不重复字符串。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int j=0,k;
int ans=0;
for(int i=0;i<s.size();i++)//每次循环,判断i在每一个位置的情况
{
for(int k=j;k<i;k++)
{
if(s[k]==s[i])
{
j=k+1;//找到本次循环对应的不重复字符串的第一个字符的位置
break;
}
}
if((i-j+1)>ans)//计算当前不重复字符串的长度,得到最大的长度存储于ans中
ans=i-j+1;
}
return ans;
}
};