LeetCode: 15 sum

Longest Substring Without Repeating Characters

"""
"""
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char,int> map;
        int i=0, j=0, ans=0, n=s.size();
        while(i<n && j<n){
            if(map.find(s[j])==map.end()){
                map.insert({s[j], j});
            }
            else{
                i = max(i,map[s[j]]+1);
                map[s[j]] = j;
            }

            ans = max(ans,j-i+1);
            j++;
        }

        return ans;
    }
};

ZigZag Conversion

class Solution {
public:
    string convert(string s, int numRows) {
        if (numRows <= 1) return s;
        string res = "";
        int size = 2 * numRows - 2;
        for (int i = 0; i < numRows; ++i){
            for(int j = i; j < s.size(); j += size){
                res += s[j];
                int tmp = j + size- 2 * i;  
                if(i != 0 && i != numRows-1 && tmp< s.size()) res += s[tmp];
            }
        }
        return res;
    }
};

String to Integer (atoi)

class Solution {
public:
    bool valid(char c){
        return (c>='0' && c<='9') || c=='+' || c=='-';
    }
    int myAtoi(string str) {
        if(str.empty())
            return 0;
        int i = 0;

        while(i<str.size()){
            if(str[i]==' ')
                i++;
            else
                break;
        }
        if(!valid(str[i]))
            return 0;

        while(i<str.size()){
            if(valid(str[i]))
                break;
            else
                i++;
        }
        if(i == str.size())
            return 0;

        int tmp = 0, start = i;
        bool out_of_bound = false;
        if(str[i] == '-' || str[i] == '+')
            start = i+1;

        for(int j=start;j<str.size();j++){
            if(str[j]>='0' && str[j]<='9'){
                if(tmp>INT_MAX/10 || (tmp==INT_MAX/10 && str[j]-'0'>=8)){
                    out_of_bound = true;
                    break;
                }
                tmp *= 10;
                tmp += (str[j]-'0');
            }
            else
                break;
        }

        if(str[i] == '-')
            return out_of_bound?INT_MIN:-tmp;
        else 
            return out_of_bound?INT_MAX:tmp;    
    }
};

Container With Most Water

class Solution {
public:
    int maxArea(vector<int>& height) {
        int res = 0, i=0, j=height.size()-1;
        while(i<j){
            int h = min(height[i], height[j]);
            res = max(res, h*(j-i));
            while(i<j && height[i]==h) i++;
            while(i<j && height[j]==h) j--;
        }
        return res;
    }
};

3Sum

"""
一个比较好的总结:
https://blog.csdn.net/haolexiao/article/details/70768526

2Sum有O(n)解,这个3Sum目测只能O(n^2),而且情况更为复杂一些,2Sum那个假设有且仅有一组解。
这里我们利用set(基于hashmap)的去重特性,解决输出结果不能重复和一个数字不能多次使用这两个问题,详见注释。

尴尬,超时(参见下面4Sum的做法,先sort就可以避免很多去重操作,不然这里用set去重的地方太多了)
"""
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        set<vector<int>> res;
        unordered_map<int,int> m;
        for(int n:nums)
            m[n]++;

        set<set<int>> help; //考虑结果不能重复,顺序颠倒也算重复

        set<int> nums_set(nums.begin(), nums.end()); //减少重复的循环

        for(int n:nums_set){
            int used = 1; //考虑同一个位置处的同一个数字不能重复使用
            int target = -n;
            for(int k:nums_set){
                if(n==k) 
                    used=2;
                else
                    used=1;
                if(m[k]>=used)
                    if(m.find(target-k)!=m.end()){
                        if(target-k==n||target-k==k) used++;
                        if(m[target-k]>=used)
                            if(help.find({n,k,target-k}) == help.end()){
                                help.insert({n,k,target-k});
                                res.insert({n,k,target-k});
                            }
                    }
            }
        }

        return vector<vector<int>> (res.begin(), res.end());
    }
};

3Sum

"""这次我们使用2Sum的排序解法。总的复杂度仍然是n^2。
这个方法更轻量一些,通过排序和while循环直接避免了很多重复计算。
"""
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        set<vector<int>> res;
        sort(nums.begin(), nums.end());

        for(int k=0;k<nums.size();k++){
            int target = -nums[k];
            int i=k+1, j=nums.size()-1;
            while(i<j){
                int sums = nums[i]+nums[j];
                if(sums == target){
                    res.insert({nums[k], nums[i], nums[j]});
                    while (i < j && nums[i] == nums[i + 1]) ++i;
                    while (i < j && nums[j] == nums[j - 1]) --j;
                    ++i; 
                    --j;
                }
                else if(sums>target)
                    j--;
                else
                    i++;
            }
        }
        return vector<vector<int>> (res.begin(), res.end());
    }
};

3Sum Closest

"""n^2
和刚才有点不一样,尤其是之前有这四行:
while (i < j && nums[i] == nums[i + 1]) ++i;//这两行之前是考虑去重,问题是有可能i一直往右移动,把最后一个本来应该给j的值也给取了。这个问题在之前不会体现出来,因为这些操作都是在相等的条件下做的
while (i < j && nums[j] == nums[j - 1]) --j;
++i; //这两行是因为之前只改变一个是不可能再次相等的,现在显然不能要了
--j;
"""
class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int re=0;
        sort(nums.begin(), nums.end());

        int d = INT_MAX;

        for(int k=0;k<nums.size()-2;k++){
            int i=k+1, j=nums.size()-1;
            while(i<j){
                int sums = nums[i]+nums[j]+nums[k];
                if(abs(sums - target)<d){
                    d = abs(sums - target);
                    re = sums;
                    //while (i < j && nums[i] == nums[i + 1]) ++i;
                    //while (i < j && nums[j] == nums[j - 1]) --j;
                }
                if(sums>target)
                    j--;
                else
                    i++;
            }
        }
        return re;
    }
};

4Sum II

"""这题不需要去重,且只需要返回结果的个数,其实更容易一些。
空间换时间:O(n^2)
"""
class Solution {
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        unordered_map<int, int> m;
        int res = 0;
        for(int i:A){
            for(int j:B){
                m[i+j] ++;
            }
        }

        for(int i:C){
            for(int j:D){
                if(m.find(-i-j)!=m.end())
                    res += m[-i-j];
            }
        }

        return res;
    }
};

4Sum

"""转化为3Sum来做,O(n^3),代码与之前3Sum基本一致,比较容易写。
时空均O(n^2)的做法:空间换时间。需要返回所有结果,且不能重复。下面的代码设计非常精妙,逻辑环环相扣(关键在于排序和循环的次序,巧妙避免重复)
"""
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end()); // aaaaabbbbcccccccddddddddddddd

        //(i,j):(1st a, 2nd a); (1st a, 1st b); ...; (1st a, 1st d); (1st b, 2nd b) 
        unordered_map<int, vector<pair<int, int>>> m;  //因为sort了,所以不会有2,3和3,2这种重复pair
        for(int i=0;i<nums.size();i++){
            if(i>0 && nums[i]==nums[i-1])  //利用sort
                continue;
            for(int j=i+1;j<nums.size();j++){
                if(j-i>1 && nums[j]==nums[j-1]) //利用sort
                    continue;
                m[nums[i]+nums[j]].push_back({i,j}); //存放的是位置,用于后面避免重复
            }
        }

        //循环顺序反过来
        vector<vector<int>> res; 
        for(int i=nums.size()-1;i>0;i--){
            if(i<nums.size()-1 && nums[i]==nums[i+1])  //利用sort
                continue;
            for(int j=i-1;j>=0;j--){
                if(i-j>1 && nums[j]==nums[j+1]) //利用sort
                    continue;
                if(m.find(target-nums[i]-nums[j])!=m.end()){
                    for(auto p:m[target-nums[i]-nums[j]]){
                        if(p.second<j) //去重
                            res.push_back({nums[i], nums[j], nums[p.first], nums[p.second]});
                    }
                }
            }
        }

        return res;
    }
};

4Sum

"""构建hashmap这地方还能优化。
https://leetcode.com/problems/4sum/discuss/128024/Time-complexity-O(N2)-space-complexity-O(N2)-use-visited-elements-in-the-array-to-build-hashmap
"""
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值