【leetcode】LeetCode15三数之和+LeetCode3无重复字符的最长子串

最近写了两道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;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_38391210/article/details/108014267