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
"""