如果直接再原数组进行find。对i遍历的事件复杂度是n,每一个find又是n,所以这种的时间复杂度是n放(另外:map和set红黑树的时间复杂度是logn,哈希表直接取值是1)
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
//这里不能排序,因为就失去了原来的顺序了
for(int i = 0;i<nums.size();i++)
{
auto iter = find(nums.begin()+i+1,nums.end(),target-nums[i]);
if(iter==nums.end())continue;
else
{
int j = iter-nums.begin();
return {i,j};
}
}
return {0,0};
}
};
一开始想对数组进行排序,这样可以极大程度的进行剪枝,但是排序之后丢失了原有的下标,如果返回的是元素不是下标的话这样就是可行的,但是下标不能用这种方法
哈希表的方法:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,vector<int>> mp;
for(int i = 0;i<nums.size();i++)mp[nums[i]].push_back(i);
for(int i = 0 ;i<nums.size();i++)
{
if( mp.find(target-nums[i])!=mp.end() )
{
if(i!=mp[target-nums[i]][0])return {i,mp[target-nums[i]][0]};
else if(mp[target-nums[i]].size()==2)return {i,mp[target-nums[i]][1]};
}
}
return {0,0};
}
};
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> m;
for(int i=0;i<nums.size();i++)
m[nums[i]] = i; //向map中添加元素
for(int i=0;i<nums.size();i++)
{
if(m.find(target-nums[i]) != m.end() && m[target-nums[i]] != i) //如果m中存在对应的键值,并且不为i,后面这个条件很重要,因为会有重复的元素
return {i , m[target-nums[i]]};
}
return {};
}
};
作者:zrita
链接:https://leetcode-cn.com/problems/two-sum/solution/c-san-chong-fang-fa-jian-dan-yi-dong-ji-bai-100-z-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
auto head = new ListNode(0);
auto temp = head;
int b = 0;
while(l1 && l2)
{
int x = b + l1->val + l2->val;
b = (x>=10)?1:0;
auto t = new ListNode(x%10);
temp->next = t;
temp = t;
l1 = l1->next; l2 = l2->next;
}
while(l1)
{
int x = b + l1->val;
b = (x>=10)?1:0;
auto t = new ListNode(x%10);
temp->next = t;
temp = t; l1 = l1->next;
}
while(l2)
{
int x = b + l2->val;
b = (x>=10)?1:0;
auto t = new ListNode(x%10);
temp->next = t;
temp = t; l2 = l2->next;
}
if(b)
{
auto t = new ListNode(1);
temp->next = t;
t->next = NULL;
return head->next;
}
else
{
temp->next = NULL;
return head->next;
}
}
};
对于字符串的题,最容易出现的就是超时,而这是更好的办法往往是哈希表法
class Solution
{
public:
int lengthOfLongestSubstring(string s)
{
//s[start,end) 前面包含 后面不包含
int start(0), end(0), length(0), result(0);
int sSize = int(s.size());
unordered_map<char, int> hash;
while (end < sSize)
{
char tmpChar = s[end];
//仅当s[start,end) 中存在s[end]时更新start
if (hash.find(tmpChar) != hash.end() && hash[tmpChar] >= start)
{
start = hash[tmpChar] + 1;
length = end - start;
}
hash[tmpChar] = end;
end++;
length++;
result = max(result, length);
}
return result;
}
};
作者:pinku-2
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-cshi-xian-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
推荐滑动窗口
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int res = 0;
//不能使用map或者set
vector<char> vt;
for(int i =0 ;i<s.size();i++)
{
if(find(vt.begin(),vt.end(),s[i])==vt.end())
{
vt.push_back(s[i]);
res = max(res, (int)vt.size());
}
else
{
auto iter = find(vt.begin(),vt.end(),s[i]);
vt.assign(iter+1,vt.end());
vt.push_back(s[i]);
}
}
return res;
}
};
class Solution {
public:
int findKthElm(vector<int>& nums1,vector<int>& nums2,int k){
assert(1<=k&&k<=nums1.size()+nums2.size());
int le=max(0,int(k-nums2.size())),ri=min(k,int(nums1.size()));
while(le<ri){
int m=le+(ri-le)/2;
if(nums2[k-m-1]>nums1[m]) le=m+1;
else ri=m;
}//循环结束时的位置le即为所求位置,第k小即为max(nums1[le-1]),nums2[k-le-1]),但是由于le可以为0、k,所以
//le-1或者k-le-1可能不存在所以下面单独判断下
int nums1LeftMax=le==0?INT_MIN:nums1[le-1];
int nums2LeftMax=le==k?INT_MIN:nums2[k-le-1];
return max(nums1LeftMax,nums2LeftMax);
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int n=nums1.size()+nums2.size();
if(n&1){//两个数组长度和为奇数
return findKthElm(nums1,nums2,(n>>1)+1);
}
else{//为偶数
return (findKthElm(nums1,nums2,n>>1)+findKthElm(nums1,nums2,(n>>1)+1))/2.0;
}
}
};
作者:nojoker
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/jiang-qi-zhuan-wei-zhao-liang-ge-you-xu-shu-zu-de-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
错误的做法
“aacdefcaa”
下面的方法找出的是这个字符串中最长的存在与它回文子串的子串,但其实它的回文子串不一定还是自己,这种情况下长度就比自身的长了
class Solution {
public:
string longestPalindrome(string s) {
string s1 = s;
int len = s.size();
reverse(s1.begin(),s1.end());
vector<vector<int>> dp(len+1,vector<int>(len+1,0));
int res = 0;
int pos = 0;
for(int i = 1;i<=len;i++)
{
for(int j =1;j<=len;j++)
{
if(s[i-1]==s1[j-1])
{
dp[i][j]=dp[i-1][j-1]+1;
if(dp[i][j]>res)
{
res = dp[i][j];
pos = i;
}
}
}
}
return s.substr(pos-res,res);
}
};
推荐动态规划法
class Solution {
public:
string longestPalindrome(string &s) {
int n=s.length(), begin=0, end=0;
vector<vector<bool> > dp(n,vector<bool> (n,false));
for(int j=0; j<n; ++j){
for(int i=0; i<=j; ++i){
if((j-i<=1 || dp[i+1][j-1]) && s[i]==s[j])
dp[i][j]=true;
if(dp[i][j] && j-i>end-begin)
begin=i, end=j;
}
}
return s.substr(begin,end-begin+1);
}
};
作者:joy-teng
链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/dong-tai-gui-hua-zhong-xin-kuo-zhan-ma-la-che-suan/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
string convert(string s, int numRows) {
if(numRows==1)return s;
string res;
int len = s.size();
vector<vector<int>> dp(numRows);
int b = 0, j=0;
for(int i = 0;i<len;i++)
{
if(b==0)
{
if(j<numRows-1){dp[j].push_back(s[i]);j++;}
else if(j==numRows-1){dp[j].push_back(s[i]);j--;b=1;}
}
else
{
if(j>0){dp[j].push_back(s[i]);j--;}
else if(j==0){dp[j].push_back(s[i]);j++;b=0;}
}
}
for(int i =0;i<numRows;i++)
{
for(auto j:dp[i])
{
res+=j;
}
}
return res;
}
};
class Solution {
public:
int reverse(int x) {
int p = 10;
int n;
long result = 0;
if(x == INT_MIN)
{
return 0;
}
if (x >= 0)
{
while(x > 0)
{
n = x % p;
x = x / p;
result = result*10 + n;
}
if(result > INT_MAX)
{
return 0;
}
return result;
}
else
{
int y = -x;
while(y > 0)
{
n = y % p;
y = y / p;
result = result*10 + n;
}
if(result > INT_MAX)
{
return 0;
}
return -result;
}
}
};
string转int、double、long long都有函数
如果使用atoi也可以转,但是要配合c_str()使用
class Solution {
public:
int reverse(int x) {
if(x< -2147483647 || x>= 2147483647)return 0;
string s = to_string(x);
int b = 0;
if(s[0]=='-')
{
s = s.substr(1,s.size()-1); b=1;
}
::reverse(s.begin(),s.end());
while(s.size()>0 && s[0]=='0')
{
s = s.substr(1,s.size()-1);
}
if(s.empty())return 0;
long long MIN = -pow(2,31);
long long MAX = pow(2,31)-1;
if(b==1)
{
s = '-'+s;
if(stoll(s)<INT_MIN || stoll(s)>INT_MAX)return 0;
return stoll(s);
}
else
{
if(stoll(s)<INT_MIN || stoll(s)>INT_MAX)return 0;
return stoll(s);
}
}
};
要考虑的情况太多了
class Solution {
public:
int b = 0;
int sign = 0;
int myAtoi(string str) {
if(str.empty())return 0;
string s = str;
if(s[0]>='0'&&s[0]<='9')
{
if(sign==2)return 0;
long long res = 0,i =0;
while(i<s.size()&&s[i]=='0')i++;
if(b==0)
{
while(s[i]>='0'&& s[i]<='9')
{
res = res*10 + int(s[i++]-'0');
if(res>INT_MAX)return INT_MAX;
}
return res;
}
else
{
while(s[i]>='0'&& s[i]<='9')
{
res = res*10 + int(s[i++]-'0');
if(-res<INT_MIN)return INT_MIN;
}
return -res;
}
}
else if (s[0]=='+')
{
s = s.substr(1,s.size()-1);
if(!s.empty()&&s[0] ==' ')return 0;
sign++;
return myAtoi(s);
}
else if(s[0]=='-')
{
s = s.substr(1,s.size()-1);
if(!s.empty()&&s[0] ==' ')return 0;
b=1;
sign++;
return myAtoi(s);
}
else if(s[0]==' ')
{
int i =0;
while(i<s.size()&&s[i]==' ')i++;
s =s.substr(i,s.size()-i);
return myAtoi(s);
}
return 0;
}
};
这里使用了整数反转的思路,直接比对反转后是否相等就知道是否是回文数;
另外,为了防止超范围,result可以使用类型long;
另外,数字和字符串转换不如算法方式好;
class Solution {
public:
bool isPalindrome(int x) {
if(x < 0){return false;}
else
{
long result = 0;
int y = x;
int n = 0;
while(x > 0)
{
n = x % 10;
x = x / 10;
result = result*10 + n;
}
if (result == y){return true;}
else{return false;}
}
}
};
class Solution {
public:
bool isMatch(string s, string p) {
int lens = s.size();
int lenp = p.size();
vector<vector<int>> dp(lens+1,vector<int>(lenp+1,false));
dp[0][0]=true;
for(int i =1;i<=lenp;i++)
{
if(p[i-1]=='*')dp[0][i]=dp[0][i-2];
}
for(int i = 1;i<=lens;i++)
{
for(int j =1;j<=lenp;j++)
{
if(s[i-1]==p[j-1]||p[j-1]=='.')
{
dp[i][j]=dp[i-1][j-1];
}
else if(p[j-1]=='*')
{
dp[i][j]=dp[i][j-2] || (dp[i-1][j] && (p[j-2]=='.'||s[i-1]==p[j-2]));
}
}
}
return dp[lens][lenp];
}
};
class Solution {
public:
int maxArea(vector<int>& height) {
int i=0, j=height.size()-1;
int res = 0;
while(i<j)
{
int area = min(height[i],height[j])*(j-i);
res = max(res,area);
if(height[i]<=height[j])i++;
else j--;
}
return res;
}
};
class Solution {
public:
string intToRoman(int num) {
vector<pair<int,string>> vt;
vt.push_back(make_pair(1000,"M"));
vt.push_back(make_pair(900,"CM"));
vt.push_back(make_pair(500,"D"));
vt.push_back(make_pair(400,"CD"));
vt.push_back(make_pair(100,"C"));
vt.push_back(make_pair(90,"XC"));
vt.push_back(make_pair(50,"L"));
vt.push_back(make_pair(40,"XL"));
vt.push_back(make_pair(10,"X"));
vt.push_back(make_pair(9,"IX"));
vt.push_back(make_pair(5,"V"));
vt.push_back(make_pair(4,"IV"));
vt.push_back(make_pair(1,"I"));
string res;
int count = 0;
for(auto v:vt)
{
if(v.first<=num)
{
int x= num/v.first;
for(int i=0;i<x;i++)res = res + v.second;
num = num % v.first;
}
}
return res;
}
};
class Solution {
public:
int romanToInt(string s) {
int res = 0;
int i=0,len = s.size();
unordered_map<char,int> mp = {{'I',1},{'V',5},{'X',10},{'L',50},{'C',100},{'D',500},{'M',1000}};
while(i<len)
{
if(i+1<len && mp[s[i]]<mp[s[i+1]])
{
res += mp[s[i+1]]-mp[s[i]];
i+=2;
}
else
{
res += mp[s[i]];
i++;
}
}
return res;
}
};
优点:
有序性,这是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作
红黑树,内部实现一个红黑书使得map的很多操作在lgn的时间复杂度下就可以实现,因此效率非常的高
缺点: 空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点、孩子节点和红/黑性质,使得每一个节点都占用大量的空间
适用处:对于那些有顺序要求的问题,用map会更高效一些
unordered_map:
优点: 因为内部实现了哈希表,因此其查找速度非常的快
缺点: 哈希表的建立比较耗费时间
适用处:对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if(strs.empty())return "";
string res = strs[0];
for(int i =1;i<strs.size();i++)
{
int j =0;
for(j =0; j<res.size(); j++)
{
if(res[j]!=strs[i][j])break;
}
res = res.substr(0,j);
if(res.empty())return "";
}
return res;
}
};
之前有道盛水量的问题用双指针能最快的解决,但是这道题直接两边双指针不能智能收缩,但是进行遍历的话有会是n方的复杂度,比如下面这个,两边遍历收缩,中间使用二分法,这样就是nnlogn的复杂度,依然不行。这道题有一种能够智能收缩的方法,就是把一个当作固定的,这样就能后面范围收缩了
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
set<vector<int>> res;
sort(nums.begin(),nums.end());
//-4,-1,-1,0,1,2
//-2,-1,0,1,2
int len = nums.size();
for(int i = 0;i<len-2;i++)
{
for(int j = len-1;j>i+1;j--)
{
//if(nums[i]+nums[j-1]+nums[j]<0){i++;continue;}
//if(nums[i]+nums[i+1]+nums[j]>0){j--;continue;}
set<int> st(nums.begin()+i+1,nums.begin()+j);
vector<int> vt(st.begin(),st.end());
int left = 0, right = vt.size();
while(left<right)
{
int mid = left + (right-left)/2;
int temp = nums[i]+vt[mid]+nums[j];
if(temp==0){res.insert({nums[i],vt[mid],nums[j]}); break;}
else if(temp<0) {left = mid+1;}
else right = mid;
}
}
}
vector<vector<int>> r(res.begin(),res.end());
return r;
}
};
这里的去重太重要了,这里去重就不需要set和vector之间的转换了,就差这点时间复杂度
if(i>0&&nums[i]==nums[i-1])continue;//去重
while (l<r && nums[l] == nums[l+1]) l++; // 去重
while (l<r && nums[r] == nums[r-1]) r--; // 去重
作者:rt-huang
链接:https://leetcode-cn.com/problems/3sum/solution/shuang-zhi-zhen-fa-hashfa-c-by-rt-huang/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
#include
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
int len = nums.size();
//-4,-1,-1,0,1,2
//-2,-1,0,1,2,3
vector<vector<int>> res;
for(int i = 0;i<len-2;i++)
{
int j = i+1,k = len-1;
if(i>=1&&nums[i]==nums[i-1])continue;
if(nums[i]+nums[j]+nums[j+1]>0)break;
if(nums[i]+nums[k-1]+nums[k]<0)continue;
while(j<k)
{
int temp =nums[i]+nums[j]+nums[k];
if(temp==0){
res.push_back(
{nums[i],nums[j],nums[k]});
while(j<k&&nums[k-1]==nums[k])k--;
while(j<k&&nums[j+1]==nums[j])j++;
j++;k--;
}
else if(temp>0)k--;
else j++;
}
}
//vector> vt(res.begin(),res.end());
return res;
}
};
自己写的,勉强不超时,考虑可能是去重那里费了比较多功夫
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int len = nums.size();
int k=0, i=1,j = len-1;
sort(nums.begin(),nums.end());
vector<vector<int>> res;
while(k<=len-3)
{
if(nums[k]+nums[k+1]+nums[k+2]>0)break;
if(nums[k]+nums[k+1]+nums[k+2]==0)
{ vector<int> temp={nums[k],nums[k+1],nums[k+2]};
res.push_back(temp);break;};
//if(nums[k]+nums[i]+nums[j]>0){k++;i=k+1;j=len-1;continue;}
if(nums[k]+nums[j-1]+nums[j]<0){k++;i=k+1;j=len-1;continue;}
while(i<j)
{
if(nums[i]+nums[j]==-nums[k])
{
vector<int> temp={nums[k],nums[i],nums[j]};
res.push_back(temp);
i++;j--;
}
else if(nums[i]+nums[j]>-nums[k])
{
j--;
}
else
{
i++;
}
}
k++;
i=k+1;
j=len-1;
}
set<vector<int>> r(res.begin(),res.end());
res.assign(r.begin(),r.end());
return res;
}
};
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
int res = 5e6;
int len= nums.size();
sort(nums.begin(),nums.end());
for(int i = 0;i<len-2;i++)
{
int t1 = nums[i]+nums[i+1]+nums[i+2]; if(t1>target){if(abs(t1-target)<abs(res-target)){res = t1;}break;}
int t2 = nums[i]+nums[len-1]+nums[len-2];if(t2<target){if(abs(t2-target)<abs(res-target)){res=t2;}continue;}
if(i>1 && nums[i]==nums[i-1])continue;
int j =i+1,k=len-1;
while(j<k)
{
int temp = nums[i]+nums[j]+nums[k];
if(temp==target){return target;}
if(abs(temp-target)<abs(res-target)){res = temp;}
if(temp<target)j++;
else k--;
}
}
return res;
}
};
dfs:注意第一层不要循环,对里层进行循环
class Solution {
public:
vector<string> res;
string path;
void dfs(unordered_map<int,string> mp, string dig,int p,int q)
{
if(path.size()==dig.size())
{
res.push_back(path);
return;
}
for(int j = q;j<mp[dig[p]-'0'].size();j++)
{
path.push_back(mp[dig[p]-'0'][j]);
dfs(mp,dig,p+1,q);
path.pop_back();
}
}
vector<string> letterCombinations(string digits) {
if(digits.empty())return {};
unordered_map<int,string> mp = {{2,"abc"},{3,"def"},{4,"ghi"},{5,"jkl"},{6,"mno"},{7,"pqrs"},{8,"tuv"},{9,"wxyz"}};
dfs(mp,digits,0,0);
return res;
}
};
bfs更好理解,注意一点queue不能直接转换成vector
class Solution {
public:
vector<string> letterCombinations(string digits) {
if(digits.empty())return {};
unordered_map<int,string> mp = {{2,"abc"},{3,"def"},{4,"ghi"},{5,"jkl"},{6,"mno"},{7,"pqrs"},{8,"tuv"},{9,"wxyz"}};
int temp =digits[0]-'0';
queue<string> qt;
string s;
for(auto i:mp[temp])qt.push(s+i);
int len = digits.size() ,i =1;
while(i<len)
{
int l = qt.size();
for(int j = 0;j<l;j++)
{
auto t = qt.front();qt.pop();
for(auto s:mp[digits[i]-'0'])
{
qt.push(t+s);
}
}
i++;
}
vector<string> res;
while(!qt.empty())
{
res.push_back(qt.front());qt.pop();
}
return res;
}
};
要特别注意里面排除i相同和j相同的语句,出现一个相同就直接排除,不同非等到i和j同时满足;另外当出现了等于target的时候,p和q不仅要去重而且还要同时进行缩小,因为仅仅一个变化,另外一个因为去重不可能再匹配上了,就算匹配上也是重复的结果,所以这时要同时进行缩进。
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
int len = nums.size();
vector<vector<int>> res;
//-3,-2,-1,0,0,1,2,3
for(int i = 0;i<len-3;i++)
{
if(i>=1&&nums[i]==nums[i-1])continue;
int t1 = nums[i]+nums[i+1]+nums[i+2]+nums[i+3];if(t1>target)break;
int t2 = nums[i]+nums[len-3]+nums[len-2]+nums[len-1];if(t2<target)continue;
for(int j = i+1;j<len-2;j++)
{
int t3 = nums[i]+nums[j]+nums[j+1]+nums[j+2];if(t3>target)break;
int t4 = nums[i]+nums[j]+nums[len-2]+nums[len-1];if(t4<target)continue;
if(j>i+1&&nums[j-1]==nums[j])continue;
int p = j+1,q=len-1;
while(p<q)
{
int temp = nums[i]+nums[j]+nums[p]+nums[q];
if(temp==target)
{
res.push_back({nums[i],nums[j],nums[p],nums[q]});
while(p<q&&nums[p]==nums[p+1])p++;
while(p<q&&nums[q]==nums[q-1])q--;
p++;q--;
}
else if(temp>target)q--;
else p++;
}
}
}
return res;
}
};
添加这个头节点十分的重要!
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
c/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
auto head1 = new ListNode(0);
head1->next = head;
auto slow = head1;
auto fast = head1;
while(n--)
{
fast = fast->next;
}
while(fast->next)
{
slow = slow->next;
fast = fast->next;
}
slow->next = slow->next->next;
head=head1->next;
delete head1;
return head;
}
};
class Solution {
public:
bool isValid(string s) {
stack<char> st;
for(auto c:s)
{
if(c=='(' || c=='[' || c == '{')st.push(c);
else if(c==')')
{
if(st.empty() || st.top()!= '(')return false;
else {st.pop();}
}
else if(c==']')
{
if(st.empty() || st.top()!='[')return false;
else {st.pop();}
}
else if(c=='}')
{
if(st.empty() || st.top()!='{')return false;
else {st.pop();}
}
}
if(!st.empty())return false;
return true;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
auto head = new ListNode(0);
auto temp = head;
while(l1 && l2)
{
if(l1->val<=l2->val)
{
auto t = new ListNode(l1->val);
temp->next = t;
temp = t;
l1=l1->next;
}
else
{
auto t = new ListNode(l2->val);
temp->next = t;
temp = t;
l2=l2->next;
}
}
temp->next = (l1)?(l1):(l2);
return head->next;
}
};
class Solution {
public:
//DFS
void generateParenthesis_(int left,int right,vector<string>& rs,string str){
if (left == 0 && right == 0) {
rs.push_back(str);
return;
}
if (left > 0) generateParenthesis_(left - 1, right, rs, str + "(");
if (left < right) generateParenthesis_(left, right - 1, rs, str + ")");
}
vector<string> generateParenthesis(int n) {
vector<string> rs;
generateParenthesis_(n,n,rs,"");
return rs;
}
//BFS
vector<string> generateParenthesis2(int n) {
vector<string> rs;
queue<pair<string, pair<int, int>>>q; // pair<当前的括号, pair<左括号剩余, 右括号剩余>>
q.push({"",{n,n}});
while (!q.empty()) {
auto top = q.front();
q.pop();
string str = top.first;
int left = top.second.first;
int right = top.second.second;
if (left == 0 && right == 0) {
rs.push_back(str);
}
if (left > 0) {
q.push({str + '(',{left-1,right}});
}
if (right > 0 && right > left) {
q.push({str + ')',{left,right-1}});
}
}
return rs;
}
};
作者:chuang-bian-gu-shi
链接:https://leetcode-cn.com/problems/generate-parentheses/solution/c-dfs-by-chuang-bian-gu-shi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
bfs
class Solution {
public:
vector<string> generateParenthesis(int n) {
queue<pair<string,pair<int,int>>> qt;
//auto t = make_pair("(",make_pair(1,0));
//qt.push(t);
qt.push({ "(", {1,0} });
while(qt.front().first.size()<2*n)
{
int len = qt.size();
for(int i = 0;i<len;i++)
{
auto temp = qt.front(); qt.pop();
int left = temp.second.first;
int right = temp.second.second;
if(left>right && left<n)
{
auto t1 = temp;
t1.first += '(';
t1.second.first +=1;
qt.push(t1);
auto t2 = temp;
t2.first += ')';
t2.second.second +=1;
qt.push(t2);
}
else if(left>right && left==n)
{
auto t3 = temp;
t3.first += ')';
t3.second.second +=1;
qt.push(t3);
}
else if (left == right)
{
auto t1 = temp;
t1.first += '(';
t1.second.first +=1;
qt.push(t1);
auto t2 = temp;
t2.first += ')';
t2.second.second +=1;
qt.push(t2);
}
}
}
vector<string> res;
while(!qt.empty())
{
res.push_back(qt.front().first);qt.pop();
}
return res;
}
};
dfs
class Solution {
public:
vector<string> res;
string path;
void dfs(int n, int left, int right)
{
if(left>n || right>n || right>left)return;
if(left==n&&right==n)
{
res.push_back(path);
return;
}
path += ')';
dfs(n,left,right+1);
path.pop_back();
path += '(';
dfs(n,left+1,right);
path.pop_back();
}
vector<string> generateParenthesis(int n) {
dfs(n,0,0);
return res;
}
};
找到所有括号的组合方式看起来比较复杂。
所以我们可以尝试换个思路:如果“(”对应数字1,“)”对应数字-1呢?
通过观察我们可以发现这样一个规律:
凡是有效的括号组合,转化成数字,任意前n项和都不小于0!
比如:“()()()”
前1位:1>=0;前2位:1+(-1)=0>=0;前3位:1+(-1)+1=1>=0;
…以此类推,前n位数字和均大于等于0.
又比如:“((()))”
前3位:1+1+1=3>=0;前4位:1+1+1+(-1)=2>=0;前5位:1+1+1+(-1)+(-1)=1>=0;
…依然满足规律。
至此,我们就能想到这样一个思路:
1.目标为n时,可以转化为n个-1和n个1
2.求这串数字的所有排列
3.满足以上规律的就是有效的括号组合
4.最后一步再将数字组合转化成括号组合
整个过程需要一些小的工具:
1.求全排列的函数:next_permutation
2.数字转化成括号:容器map
class Solution {
public:
vector<string> generateParenthesis(int n)
{
vector<string> result;
if(n == 0){return result;}
vector<vector<int>> mid;
vector<int> temp;
for(int i = 0 ; i < n ; i ++)
{
temp.push_back(-1); //先放所有的-1
}
for(int i = 0 ; i < n ; i ++)
{
temp.push_back(1); //再放所有的+1(这样的原因是因为全排列需要从小到大的顺序)
}
while(next_permutation(temp.begin(),temp.end())) //求全排列
{
int target = 0;
int judg = 1;
for(auto i:temp)
{
target+=i;
if(target < 0)
{
judg = 0;break; //是否满足前n项之和不小于0
}
}
if(judg == 1){mid.push_back(temp);}//如果不用剪枝,则可以将数组放入mid
}
map<int,string> invert;
invert.insert(map<int,string>::value_type(1,"(")); //1对应左括号
invert.insert(map<int,string>::value_type(-1,")")); //-1对应右括号
for(auto i:mid)
{
string s;
for(auto j:i)
{
s += invert[j]; //数字组合转化成字符串
}
result.push_back(s);
}
return result;
}
};
作者:da-lian-mao-ai-chi-yu
链接:https://leetcode-cn.com/problems/generate-parentheses/solution/gua-hao-tai-fu-za-shu-zi-zhuan-hua-ta-by-da-lian-m/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
用这个函数一下子就省去了找所有可能的排列,在排列之后再转成括号就行了,由于只有一种括号,就用1和-1来代替并使用剪枝算法
while(next_permutation(temp.begin(),temp.end()))
{}
next_permutation(num,num+n)函数是对数组num中的前n个元素进行全排列,同时并改变num数组的值。
另外,需要强调的是,next_permutation()在使用前需要对欲排列数组按升序排序,否则只能找出该序列之后的全排列数。
1.vector
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
vector<int> v;
for(auto head:lists)
{
while(head)
{
v.push_back(head->val);
head=head->next;
}
}
sort(v.begin(),v.end());
ListNode* head = new ListNode(0);
ListNode* res = head;
//int i = v.size();
for(int i = 0 ; i<v.size(); i++)
{
ListNode* temp =new ListNode(v[i]);
res->next = temp;
res = temp;
}
return head->next;
}
};
2.使用优先队列
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<pair<int,ListNode*>,vector<pair<int,ListNode*>>,greater<pair<int,ListNode*>>> pt;
for(int i = 0; i< lists.size() ;i++)
{
while(lists[i])
{
pt.push(make_pair(lists[i]->val,lists[i]));
lists[i] = lists[i]->next;
}
}
auto head1 = new ListNode(0);
auto temp = head1;
while(!pt.empty())
{
temp->next = pt.top().second;
temp = pt.top().second;
pt.pop();
}
temp->next = NULL;
return head1->next;
}
};
class Solution {
public:
ListNode* mergeTwoLists(ListNode *a, ListNode *b) {
if ((!a) || (!b)) return a ? a : b;
ListNode head, *tail = &head, *aPtr = a, *bPtr = b;
while (aPtr && bPtr) {
if (aPtr->val < bPtr->val) {
tail->next = aPtr; aPtr = aPtr->next;
} else {
tail->next = bPtr; bPtr = bPtr->next;
}
tail = tail->next;
}
tail->next = (aPtr ? aPtr : bPtr);
return head.next;
}
ListNode* merge(vector <ListNode*> &lists, int l, int r) {
if (l == r) return lists[l];
if (l > r) return nullptr;
int mid = (l + r) >> 1;
return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
return merge(lists, 0, lists.size() - 1);
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists/solution/he-bing-kge-pai-xu-lian-biao-by-leetcode-solutio-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
auto head1 = new ListNode(0);
head1->next = head;
auto temp = head1;
while(temp && temp->next && temp->next->next)
{
auto pre = temp->next;
auto cur = temp->next->next;
pre->next = cur->next;
cur->next = pre;
temp->next = cur;
temp = pre;
}
return head1->next;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
auto dummy=new ListNode(-1);
dummy->next=head;
for(auto p=dummy;p->next&&p->next->next;){
auto a=p->next,b=a->next;
p->next=b;
a->next=b->next;
b->next=a;
p=a;
}
return dummy->next;
}
};
作者:TeFuirnever
链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs/solution/shou-hui-man-hua-tu-jie-leetcodezhi-liang-liang-ji/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(!head)return head;
auto head1 = new ListNode(0);
head1->next = head;
auto last = head1;
auto pre = head;
auto cur = head->next;
while(cur)
{
auto temp = cur->next;
last->next = cur;
cur->next = pre;
pre->next = temp;
last = pre;
pre = temp;
if(!temp)break;
else cur = temp->next;
}
auto res = head1->next;
delete head1;
return res;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<ListNode*> reverselist(ListNode* head, ListNode* furture)
{
auto head1 = new ListNode(0);
head1->next = head;
auto last = head;
auto pre = head1;
auto cur = head;
auto sign = cur;
while(cur!=furture)
{
auto temp = cur->next;
cur->next = pre;
pre = cur;
sign = cur;
cur = temp;
}
head->next = furture;
delete head1;
vector<ListNode*> res = {sign,head};
return res;
}
ListNode* reverseKGroup(ListNode* head, int k) {
auto head1 = new ListNode(0);
head1->next = head;
auto p = head1;
while(p)
{
int count = k;
auto temp = p->next;
auto q = temp;
while(temp && count)
{
count--;
temp = temp->next;
}
if(count==0)
{
auto x = reverselist(q,temp);
p->next = x[0];
p = x[1];
}
else break;
}
auto res = head1->next;
delete head1;
return res;
}
};
class Solution {
public:
// 翻转一个子链表,并且返回新的头与尾
pair<ListNode*, ListNode*> myReverse(ListNode* head, ListNode* tail) {
ListNode* prev = tail->next;
ListNode* p = head;
while (prev != tail) {
ListNode* nex = p->next;
p->next = prev;
prev = p;
p = nex;
}
return {tail, head};
}
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* hair = new ListNode(0);
hair->next = head;
ListNode* pre = hair;
while (head) {
ListNode* tail = pre;
// 查看剩余部分长度是否大于等于 k
for (int i = 0; i < k; ++i) {
tail = tail->next;
if (!tail) {
return hair->next;
}
}
ListNode* nex = tail->next;
// 这里是 C++17 的写法,也可以写成
// pair result = myReverse(head, tail);
// head = result.first;
// tail = result.second;
tie(head, tail) = myReverse(head, tail);
// 把子链表重新接回原链表
pre->next = head;
tail->next = nex;
pre = tail;
head = tail->next;
}
return hair->next;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/solution/k-ge-yi-zu-fan-zhuan-lian-biao-by-leetcode-solutio/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if (head == NULL) return NULL;
ListNode *a = head;
ListNode *b = head;
for (int i = 0; i < k; i++) {
if (b == NULL) return head;
b = b->next;
}
ListNode *newNode = reverseOperator(a,b);
a->next = reverseKGroup(b,k);
return newNode;
}
ListNode* reverseOperator(ListNode* n,ListNode *b) {
ListNode *pre, *cur, *nxt;
pre = NULL; cur = n; nxt = n;
while (cur != b) {
nxt = cur->next;
cur->next = pre;
pre = cur;
cur = nxt;
}
return pre;
}
};
作者:yu-fan-u
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/solution/c-di-gui-jian-dan-yi-dong-by-yu-fan-u/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if(nums.empty())return 0;
int i=0,j =0;
while(i<nums.size())
{
while(i<nums.size() && nums[i]==nums[j])
{
i++;
}
if (i == nums.size())break;
nums[++j]=nums[i++];
}
return j+1;
}
};
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int i =1;
int j = 0;
int len = nums.size();
if(len==0)return 0;
for(i=1; i<len;i++)
{
if(nums[i]==nums[j])continue;
else
{
nums[++j] = nums[i];
}
}
return j+1;
}
};
循环这里必须加等号
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int i = 0 ;
int j = nums.size()-1;
while(i<=j)
{
while(i<=j && nums[i]!=val) i++;
while(i<=j && nums[j]==val)j--;
if(i<=j) swap(nums[i],nums[j]);
}
return i;
}
};
超时了
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
if(s.empty() || words.empty())return {};
vector<int> res;
int lenw = words.size();
sort(words.begin(),words.end());
string s1;
for(auto w:words)s1 =s1+w;
if(s1.size()>s.size())return {};
for(int i =0 ; i<= s.size()-s1.size() ;i++)
{
if(s.substr(i,s1.size())==s1)res.push_back(i);
}
while(next_permutation(words.begin(),words.end()))
{
for(int i =0 ; i<= s.size()-s1.size() ;i++)
{
s1 = "";
for(auto w:words)s1 =s1+w;
if(s.substr(i,s1.size())==s1)res.push_back(i);
}
}
return res;
}
};
利用字符都是等长的这点可以使用哈希表做,不然会比较麻烦
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
if(s.empty() || words.empty())return {};
unordered_map<string,int> mp;
int sublen =words[0].size();
int count = sublen*words.size();
if(count>s.size())return {};
for(auto i:words){mp[i]++;}
vector<int> res;
for(int i =0;i<=s.size()-count;i++)
{
unordered_map<string,int> mp1;
auto temp = s.substr(i,count);
int j = 0;
while(j<s.size())
{
if(mp.find(temp.substr(j,sublen))==mp.end())break;
else {mp1[temp.substr(j,sublen)]++; j+=sublen;}
}
if(mp1==mp)res.push_back(i);
}
return res;
}
};
class Solution {
public:
void nextPermutation(vector<int>& nums) {
next_permutation(nums.begin(), nums.end());
}
};
作者:chronosphere
链接:https://leetcode-cn.com/problems/next-permutation/solution/c-4ms-5xing-by-chronosphere/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
#
```cpp
从后向前查找第一个相邻升序的元素对 (i,j),满足 A[i] < A[j]。此时 [j,end) 必然是降序
在 [j,end) 从后向前查找第一个满足 A[i] < A[k] 的 k。A[i]、A[k] 分别就是上文所说的「小数」、「大数」
将 A[i] 与 A[k] 交换
可以断定这时 [j,end) 必然是降序,逆置 [j,end),使其升序
如果在步骤 1 找不到符合的相邻元素对,说明当前 [begin,end) 为一个降序顺序,则直接跳到步骤 4
作者:imageslr
链接:https://leetcode-cn.com/problems/next-permutation/solution/xia-yi-ge-pai-lie-suan-fa-xiang-jie-si-lu-tui-dao-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
void nextPermutation(vector<int>& nums) {
bool b = false;
for(int i = nums.size()-2;i>=0;i--)
{
if(nums[i]<nums[i+1])
{
int m = 5e6,sign = 0;
for(int j = nums.size()-1;j>=i+1;j--)
{
if(nums[j]>nums[i] && abs(nums[j]-nums[i])<m)
{
sign = j;
m = nums[j]-nums[i];
}
}
if(sign)
{
swap(nums[sign],nums[i]);
reverse(nums.begin()+i+1,nums.end());
b = !b;
break;
}
}
}
if(b)return;
else
{
reverse(nums.begin(),nums.end());
return;
}
}
};
if s[i] == '(' :
dp[i] = 0
if s[i] == ')' :
if s[i - 1] == '(' :
dp[i] = dp[i - 2] + 2 #要保证i - 2 >= 0
if s[i - 1] == ')' and s[i - dp[i - 1] - 1] == '(' :
dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2 #要保证i - dp[i - 1] - 2 >= 0
采用的是遍历判断法,能够剪枝的地方非常有限,所以超时了
class Solution {
public:
bool is(string s1)
{
if(s1[0]==')')return false;
int len = s1.size();
if(len%2!=0)return false;
stack<char> st;
for(auto i:s1)
{
if(i=='(')
{
st.push(i);
}
else
{
if(!st.empty() && st.top()=='(')
{
st.pop();
}
else
{
return false;
}
}
}
return st.empty();
}
int longestValidParentheses(string s) {
//两种办法,第一种双指针窗口法,当遇到破坏结构时,从中间的地方开始起,但是可能会有一点复杂
//遍历判断法,专门呢写一个函数,第一种的复杂度肯定是最低的
if(s.empty())return 0;
int max = 0;
int len = s.size();
if(len==1)return 0;
for(int i = 0 ; i<len ;i++)
{
for(int j = i+1;j<len;j++)
{
string s1=s.substr(i,j-i+1);
if(is(s1) && j-i+1>max)max = j-i+1;
}
}
return max;
}
};
用的哈希表,超时了
class Solution {
public:
int longestValidParentheses(string s) {
int len = s.size();
unordered_map<char,int> mp1;
mp1['(']=1; mp1[')']=-1;
int res = 0;
for(int i = 0;i<len-1 ;i++)
{
int start = i;
while(s[start]==')')start++;
int count = 0;
for(int j = start; j<len ;j++)
{
count += mp1[s[j]];
if(count==0)res = max(res,j-start+1);
if(count<0)break;
}
}
return res;
}
};
class Solution {
public:
int search(vector<int>& nums, int target) {
int right = nums.size();
int left = 0;
while(left<right)
{
int mid = left + (right-left)/2;
if(nums[mid]==target){return mid;}
else if (nums[mid]>target)
{
if(target>=nums[0] || nums[mid]<nums[0]){right = mid;}
else{left=mid+1;}
}
else
{
if(nums[mid]>=nums[0] ||target<nums[0]){left=mid+1;}
else{right=mid;}
}
}
return -1;
}
};
class Solution {
public:
int search(vector<int>& nums, int target) {
int lo = 0, hi = nums.size() - 1;
while (lo < hi) {
int mid = (lo + hi) / 2;
if ((nums[0] > target) ^ (nums[0] > nums[mid]) ^ (target > nums[mid]))
lo = mid + 1;
else
hi = mid;
}
return lo == hi && nums[lo] == target ? lo : -1;
}
};
作者:LukeLee
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/ji-jian-solution-by-lukelee/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left = 0, right = nums.size();
while(left<right)
{
int mid = left + (right-left)/2;
if(nums[mid]==target)
{
int t1 =mid-1, t2 = mid+1;
while(t1>=0 && nums[t1]==target)t1--;
while(t2<(int)nums.size() && nums[t2]==target)t2++;
return {t1+1,t2-1};
}
else if(nums[mid]<target)
{
left = mid +1;
}
else{right = mid;}
}
return {-1,-1};
}
};
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
return lower_bound(nums.begin(),nums.end(),target)-nums.begin();
}
};
返回第一个大于等于target的数,和二分法模板中最后的结果left的作用时一样的,upper_bound为返回第一个大于target的数
用来求刚刚大于等于target的第一个值
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int len = nums.size();
int left=0,right = len;
while(left<right)
{
int mid = (left+right)/2;
if(nums[mid]==target)return mid;
else if(nums[mid]<target)
{
left = mid+1;
}
else
{
right = mid;
}
}
return left;
}
};
注意块表示法,i/3*3和i不是一样的结果
下面这个方法灵活运用了三个哈希表(二维数组实现)的,单次遍历,用目的区域(行、列、快)来表示行,用1-9来9个数字出现次数作为列,列为10因为直接对应,0不算,给9加一行
bool isValidSudoku(vector<vector<char>>& board) {
unordered_map<int,int> mp;
for(int i =1;i<=9;i++) mp[i]=0;
vector< unordered_map<int,int> > v1(9,mp);
vector< unordered_map<int,int> > v2(9,mp);
vector< unordered_map<int,int> > v3(9,mp);
for(int i = 0 ;i<9;i++)
{
for(int j = 0;j<9;j++)
{
if(board[i][j]=='.')continue;
int temp = board[i][j]-'0';
if(v1[i][temp]==0)v1[i][temp]++;
else return false;
if(v2[j][temp]==0)v2[j][temp]++;
else return false;
if(v3[(i/3)*3+j/3][temp]==0)v3[(i/3)*3+j/3][temp]++;
else return false;
}
}
return true;
//00-0 03-1 06-2 30-3 36-4 39-5 60-6 63-7 66-8
}
class Solution {
public:
string countAndSay(int n) {
string s = "1";
while(n-1)
{
int i = 0;
string res;
while(i<s.size())
{
auto val = s[i];
int start = i;
while(i<s.size() && s[i]==val)i++;
int len = i-start;
res= res + to_string(len) + val;
}
s = res;
n--;
}
return s;
}
};
要特别注意将i放入下次dfs的写法,目的就是为了下次不再查找之前的元素,值得学习
class Solution {
private:
vector<vector<int>> res;
vector<int> path;
int sum = 0;
public:
void dfs(vector<vector<int>>& res,vector<int>& candidates,vector<int>& path, int sum,int target ,int j)
{
if(sum == target)
{
res.push_back(path);return;
}
if(sum>target)return;
for(int i = j; i<(int)candidates.size() ;i++)
{
path.push_back(candidates[i]);
sum +=candidates[i];
dfs(res, candidates, path, sum, target,i);
path.pop_back();
sum -=candidates[i];
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
dfs(res,candidates,path,0,target,0);
return res;
}
};
回溯算法:当给定终点时,可以进行回退
再加上递归和剪枝算法
负递归算法:
// author:rmokerone
#include
#include
using namespace std;
class Solution {
private://成员变量
vector<int> candidates;
vector<vector<int>> res;
vector<int> path;
public:
void DFS(int start, int target) {
if (target == 0) { //递归终止条件
res.push_back(path);
return;
}
for (int i = start; i < candidates.size() && target - candidates[i] >= 0; i++) {
path.push_back(candidates[i]);
DFS(i, target - candidates[i]);
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int> &candidates, int target) {
std::sort(candidates.begin(), candidates.end());
this->candidates = candidates;
DFS(0, target);
return res;
}
};
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/combination-sum/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
正递归加剪枝算法:
要特别注意几点:
1.是用了剪枝是为了提速
2.除此之外,在深度优先搜索的时候可以设置从当前元素开始,因为之前的元素在之前的节点已经用过了,所以加了一个start变量用来记录在can容器中的位置
3.像sum这种的不用每次都计算,直接加个参数就行了,注意全局变量的定义位置,因为递归函数要用,所以定义在全局的地方,还可以在外面定义但是在函数中进行计算,比如siz这个变量,更严格点可以定义在private中
class Solution {
public:
vector<int> tmp;
vector<vector<int>> ans;
int siz;
void dfs(int now, int sum, int tar, vector<int>& num)
{
if(sum > tar) return;
if(sum == tar)
{
ans.push_back(tmp);
return;
}
for(int i = now; i < siz; i ++)
{
tmp.push_back(num[i]); //一层一层往下走
dfs(i, sum + num[i], tar, num); //当大于或者等于时都会返回
tmp.pop_back();//回到上一个分叉节点,从整个树的最左边一条开始试
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
siz = candidates.size();
dfs(0, 0, target, candidates);
return ans;
}
};
作者:iswJXkYVv3
链接:https://leetcode-cn.com/problems/combination-sum/solution/c-di-gui-shen-sou-by-iswjxkyvv3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
体会和上一题的区别
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
int sum = 0;
void dfs(vector<int>& candidates, int target, vector<int>& path, int sum,int p)
{
if(sum>target)return;
if(sum==target){res.push_back(path);return;}
for(int i =p ;i< candidates.size() ;i++)
{
sum = sum + candidates[i];
path.push_back(candidates[i]);
dfs(candidates,target,path,sum,i+1);
sum = sum - candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
dfs(candidates,target,path,0,0);
set<vector<int>> st(res.begin(),res.end());
vector<vector<int>> r(st.begin(),st.end());
return r;
}
};
class Solution {
public:
int firstMissingPositive(vector<int> nums) {
int n = nums.size();
bool b= false;
for(auto i:nums)
{
if(i==1)
{
b = true;
break;
}
}
if(!b)return 1;
for(int i = 0;i<n;i++)
{
if(nums[i]<1 ||nums[i]>n)nums[i]=1;
}
for(int i =0;i<n;i++)
{
if(nums[i]>0 && nums[nums[i]-1]>0)nums[nums[i]-1]=-nums[nums[i]-1];
if (nums[i] < 0 && nums[-nums[i]-1]>0)
nums[-nums[i]-1] = -nums[-nums[i]-1];
}
for(int i=0;i<n;i++)
{
if (nums[i] > 0) {
return i+1;
}
}
return n+1;
}
};
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
//return 0;
int n = nums.size();
bool flag = true;
for(int i=0; i<n; i++){
if(nums[i] == 1) flag = false;
}
if(flag) return 1;
for(int i=0; i<n; i++){
if(nums[i] <= 0 || nums[i] > n){
nums[i] = 1;
}
}
for(int i=0; i<n; i++){
int pos = nums[i] > 0 ? nums[i] : (-nums[i]);
nums[pos-1] = nums[pos-1] > 0 ? (-nums[pos-1]) : nums[pos-1];
}
//find the fist positive index
int ret = n+1;
for(int i=0; i<n; i++){
if(nums[i] > 0) return i+1;
}
return ret;
}
};
作者:edward_wang
链接:https://leetcode-cn.com/problems/first-missing-positive/solution/chang-shu-kong-jian-fu-za-du-jie-jue-lei-ha-xi-wen/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int trap(vector<int>& height) {
int res = 0;
auto m = max_element(height.begin(),height.end())-height.begin();
int i = 0,j=0;
while(i<m && height[i]==0)i++;
while(i<m)
{
j = i+1;
int sum = 0;
while(j<=m && height[j]<height[i])
{
sum += height[j++];
}
res += min(height[i],height[j])*(j-i-1)-sum;
i=j;
}
i = height.size()-1;
while(i>m)
{
j = i-1;
int sum = 0;
while(j>=m && height[j]<height[i])
{
sum += height[j--];
}
res += min(height[i],height[j])*(i-j-1)-sum;
i=j;
}
return res;
}
};
class Solution {
public:
int trap(vector<int>& height) {
int dp = 0;
int res = 0;
int m = 0;
auto iter = max_element(height.begin(),height.end());
m=iter-height.begin();
for(int i = 0;i<m;i++)
{
if(dp==0)dp = height[i];
else if(height[i]<dp)
{
res += dp-height[i];
}
else if(height[i]>dp)
{
dp = height[i];
}
}
dp = 0;
for(int i = height.size()-1; i>m;i--)
{
if(dp==0)dp = height[i];
else if(height[i]<dp)
{
res += dp-height[i];
}
else if(height[i]>dp)
{
dp = height[i];
}
}
return res;
}
};
这是一个建立在一维数组上的问题,理论上这类的所有问题都可以用双指针来解决,这道题的难点在于找到最大值之后的后半部分怎么处理,怎么去找到剩下的部分,这时候需要求最大值,使用max_element函数,但是注意返回的是一个迭代器,用法如下
#include
//返回迭代器
auto max = max_element(v.begin(), v.end());
//得到最大值对应下标
int kk = max-v.begin();
当开始使用这个函数的时候想把里面所有的索引换成迭代器指针,但是发现在执行起来十分有困难,就是因为迭代器之间不传递,比如i和j都是v的迭代器,i++被允许,但是j=i+1就不被允许,所以能不使用迭代器就不使用,当要使用那些返回迭代器的方法时,可以用他减去v.begin()自然就返回的是下标位置
堆栈的方法,不是很好理解
直观想法
我们可以不用像方法 2 那样存储最大高度,而是用栈来跟踪可能储水的最长的条形块。使用栈就可以在一次遍历内完成计算。
我们在遍历数组时维护一个栈。如果当前的条形块小于或等于栈顶的条形块,我们将条形块的索引入栈,意思是当前的条形块被栈中的前一个条形块界定。如果我们发现一个条形块长于栈顶,我们可以确定栈顶的条形块被当前条形块和栈的前一个条形块界定,因此我们可以弹出栈顶元素并且累加答案到
\text{ans}ans 。算法
使用栈来存储条形块的索引下标。 遍历数组: 当栈非空且
\text{height}[current]>\text{height}[st.top()]height[current]>height[st.top()]
意味着栈中元素可以被弹出。弹出栈顶元素 \text{top}top。 计算当前元素和栈顶元素的距离,准备进行填充操作
\text{distance} = \text{current} - \text{st.top}() -
1distance=current−st.top()−1 找出界定高度 \text{bounded_height} =
\min(\text{height[current]}, \text{height[st.top()]}) -
\text{height[top]}bounded_height=min(height[current],height[st.top()])−height[top]
往答案中累加积水量\text{ans} \mathrel{+}= \text{distance} \times
\text{bounded_height}ans+=distance×bounded_height 将当前索引下标入栈 将
\text{current}current 移动到下个位置
作者:LeetCode
链接:https://leetcode-cn.com/problems/trapping-rain-water/solution/jie-yu-shui-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
int trap(vector<int>& height)
{
int ans = 0, current = 0;
stack<int> st;
while (current < height.size()) {
while (!st.empty() && height[current] > height[st.top()]) {
int top = st.top();
st.pop();
if (st.empty())
break;
int distance = current - st.top() - 1;
int bounded_height = min(height[current], height[st.top()]) - height[top];
ans += distance * bounded_height;
}
st.push(current++);
}
return ans;
}
作者:LeetCode
链接:https://leetcode-cn.com/problems/trapping-rain-water/solution/jie-yu-shui-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
string multiply(string num1, string num2) {
int n1=num1.size();
int n2=num2.size();
string res(n1+n2,'0');
for(int i=n2-1;i>=0;i--){
for(int j=n1-1;j>=0;j--){
int temp=(res[i+j+1]-'0')+(num1[j]-'0')*(num2[i]-'0');
res[i+j+1]=temp%10+'0';//当前位
res[i+j]+=temp/10; //前一位加上进位,res[i+j]已经初始化为'0',加上int类型自动转化为char,所以此处不加'0'
}
}
//去除首位'0'
for(int i=0;i<n1+n2;i++){
if(res[i]!='0')
return res.substr(i);
}
return "0";
}
};
作者:carryzz
链接:https://leetcode-cn.com/problems/multiply-strings/solution/c-shu-shi-cheng-fa-dai-ma-jian-ji-you-ya-yi-dong-b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
bool isMatch(string s, string p) {
int lens = s.size();
int lenp = p.size();
vector<vector<bool>> vt(lens+1, vector<bool>(lenp+1,false));
vt[0][0]=true;
for(int i=1 ;i<=lenp ;i++)
{vt[0][i]=vt[0][i-1]&&p[i-1]=='*';}//*可以匹配任何0字符
for(int i = 1 ;i<=lens ;i++)
{
for(int j = 1 ;j<=lenp ;j++)
{
if(s[i-1]==p[j-1] || p[j-1]=='?')
{vt[i][j]=vt[i-1][j-1];}
else if(p[j-1]=='*')
{vt[i][j]=vt[i-1][j]||vt[i][j-1];}
}
}
return vt[lens][lenp];
}
};
class Solution {
public:
int jump(vector<int>& nums) {
int res = 0;
int i = 0, len = nums.size();
while(i<len)
{
int m = 0,point = 0;
if(i==len-1)return res;
if(i+nums[i]>=len-1)return res+1;
for(int j = i ; j<= min(i+nums[i],len-1);j++)
{
if(j+nums[j]>m){m=j+nums[j];point = j;}
}
i = point ;res++;
}
return res;
}
};
看了解答,发现这种思路整体是对的,就是追求每一次能走的最大,然而之前的错误在于,并不是比较start+nums[start]和max[start,start+len(start)]之间的最大值,应该比较的是和区间里每一个值和其值的和即i+len(i),这才是走的最远的方法,按照这种方法不断更新,就可以找到最后了
即使意思相近但是别人的表达也十分简介
int jump(vector<int> &nums)
{
int ans = 0;
int start = 0;
int end = 1;
while (end < nums.size())
{
int maxPos = 0;
for (int i = start; i < end; i++)
{
// 能跳到最远的距离
maxPos = max(maxPos, i + nums[i]); //在遍历的过程中不断更新这个最大值
}
start = end; // 下一次起跳点范围开始的格子
end = maxPos + 1; // 下一次起跳点范围结束的格子,加一是因为上面的遍历时左闭右开的
ans++; // 跳跃次数
}
return ans;
}
作者:ikaruga
链接:https://leetcode-cn.com/problems/jump-game-ii/solution/45-by-ikaruga/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
关于全排列next_permumation有几点需要说明
1.之气那要排序
2.只要开始全排列,第一个结果是已经改变之后的数组,而不是原来的
3。参数是首末迭代器
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int> > res;
sort(nums.begin(), nums.end());
res.push_back(nums);
while(next_permutation(nums.begin(),nums.end()))
{
res.push_back(nums);
}
return res;
}
};
这是使用队列层序遍历的方法写的
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int> > res;
if (nums.size()==0 || nums.size()==1)
{
res.push_back(nums);
return res;
}
sort(nums.begin(), nums.end());
queue<vector<int>> q;
for(auto i:nums)
{
vector<int> temp;
temp.push_back(i);
q.push(temp);
}
//int i=nums.size()-1;
while(q.front().size()!=nums.size())
{
for (auto i:nums)
{
vector<int> temp = q.front();
if(find(temp.begin(),temp.end(),i)==temp.end())
{
temp.push_back(i);
q.push(temp);
}
}
q.pop();
}
while(!q.empty())
{
res.push_back(q.front());
q.pop();
}
return res;
}
};
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
void dfs(vector<int>& nums)
{
if(path.size()==nums.size())
{
res.push_back(path);
return;
}
for(int i = 0 ; i <nums.size();i++)
{
if(find(path.begin(),path.end(),nums[i])==path.end())
{
path.push_back(nums[i]);
dfs(nums);
path.pop_back();
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
dfs(nums);
return res;
}
};
算法模板
递归{
递归出口;
for(int i = 1;i<=n;i++){
add(i);
进入递归;
remove(i);
}
}
作者:windliang
链接:https://leetcode-cn.com/problems/unique-binary-search-trees-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-2-7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
void backtrack(路径,选择列表)
{
if(终止条件)
{
传出路径结果
return;
}
for i in 选择列表
{
进入该选择
back(路径,选择列表)
退出该选择
}
}
这是根据该思想写的代码,代码结构简单,清晰,但是优化的不好
class Solution {
private:
vector<vector<int> > res;
int len;
vector<int> path;
public:
void backtrack(vector<int> &path, vector<int>& nums)
{
set<int> s(path.begin(),path.end());
if(path.size()==len)
{
if (s.size()==len)
{
res.push_back(path);
return;
}
else
{
return;
}
}
for(auto i : nums)
{
path.push_back(i);
backtrack(path,nums);
path.pop_back();
}
}
vector<vector<int>> permute(vector<int>& nums) {
len = nums.size();
if (nums.size()==0 || nums.size()==1)
{
res.push_back(nums);
return res;
}
sort(nums.begin(), nums.end());
backtrack(path,nums);
return res;
}
};
与重复相比不一样的地方:用一个set接收,而且数组一开开始必须排序
class Solution {
public:
set<vector<int> > res;
vector<int> path;
void dfs(vector<int> nums, int len, vector<bool>& judge)
{
if(path.size()==len){res.insert(path);return;}
for(int i = 0; i<len ;i++)
{
if(!judge[i])
{
judge[i]=true;
path.push_back(nums[i]);
dfs(nums,len,judge);
path.pop_back();
judge[i]=false;
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
int len = nums.size();
sort(nums.begin(),nums.end());
vector<bool> judge(len,false);
dfs(nums,len,judge);
vector<vector<int>> r(res.begin(),res.end());
return r;
}
};
将图片沿正对角线和竖轴翻转一下就可以了
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
int m = matrix[0].size();
// 对于正对角线对称翻转
for (int i = 0; i < n; i++) {
for (int j = i; j < m; j++) {
swap(matrix[i][j], matrix[j][i]);
}
}
// 竖轴镜像操作
for (int i = 0; i < n; i++) {
reverse(matrix[i].begin(), matrix[i].end());
}
}
};
作者:happy_yuxuan
链接:https://leetcode-cn.com/problems/rotate-image/solution/leetcode48-fan-zhuan-gui-lu-by-happy_yuxuan/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>> res;
vector<pair<multiset<char>,vector<string>>> st;
for(auto str:strs)
{
multiset<char> temp(str.begin(),str.end());
bool b = false;
for(int i = 0 ;i<(int)st.size() ;i++)
{
if(st[i].first==temp)
{
st[i].second.push_back(str);
b = true;
break;
}
}
if(!b)
{
st.push_back(pair<multiset<char>,vector<string>>(temp,{str}));
}
}
for(auto i:st)
{
vector<string> temp;
for(auto j:i.second)
{
temp.push_back(j);
}
res.push_back(temp);
}
return res;
}
};
更好的办法:哈希表和数组联系,只要引入一个hash表,索引是排序后的单词,值为结果vector的下标,循环一遍就好了
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>> res;
int sub=0; //结果vector的下标值
string tmp; //临时string
unordered_map<string,int> work; //判断排序后单词是否存在,即字母组成是否一致
for(auto str:strs)
{
tmp=str;
sort(tmp.begin(),tmp.end());
if(work.count(tmp))
{
res[work[tmp]].push_back(str);
}
else
{
vector<string> vec(1,str);
res.push_back(vec);
work[tmp]=sub++;
}
}
return res;
}
};
作者:rjs
链接:https://leetcode-cn.com/problems/group-anagrams/solution/c-yin-ru-hashbiao-shi-jian-32ms-ji-bai-9948-nei-cu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
double dfs(double x, long long n)
{
if(n==1)return x;
if(n%2==0)
{
double temp = dfs(x,n/2);//这里可以减少计算次数,提前计算好
return temp*temp;
}
else
{
return x*dfs(x,n-1);
}
}
double myPow(double x, int n) {
if(n==0)return 1;
if(x==0)return 0;
bool k = (n>0)?true:false;
n = abs(n);
double res = dfs(x,n);
return k?res:(1/res);
}
};
不知道哪里有问题
思路非常清晰,典型的n皇后的问题,稍微麻烦的问题是判断是否额能够满足条件,而且注意不用在最后才检查条件。应该在中间进行判断,只要能够满足条件才继续下去,这样到最后也就满足条件了,放一个满足一个,最后就一定满足,这里一行一行建立的会稍微简单一点
class Solution {
vector<vector<string>> res;//存结果
vector<string> tmp;//存棋盘
public:
vector<vector<string>> solveNQueens(int n) {
string line(n,'.');//既然一行一行试,那就一行一行存
solveNQueens(line, 0, n);//从第0行开始
return res;
}
private:
//试某一行
void solveNQueens(string& line, int row, int n)
{
if(tmp.size() == n)//棋盘绘制够n行存进结果,不用继续试了
{
res.push_back(tmp);
return;
}
for(int i = 0; i < n; ++i)//一格一格,每格都要试
{
if(checkAll(row, i, n)) //符合条件了
{
line[i] = 'Q'; //就把当前试的这一格放皇后
tmp.push_back(line); //然后把这一行绘制进棋盘
line[i] = '.'; //棋盘的下一行应该是没有皇后的
solveNQueens(line, row + 1, n);//去试下一行
tmp.pop_back(); //接下来要去试下一格,刚才绘制进去的那一行删掉
}
}
}
//暴力检查条件
bool checkAll(int row, int col, int n)
{
for(int i = row - 1, j = col - 1; i >= 0 && j >= 0; --i,--j)//左上方
{
if(tmp[i][j] == 'Q')
return false;
}
for(int i = row - 1; i >= 0; --i)//正上方
{
if(tmp[i][col] == 'Q')
return false;
}
for(int i = row -1, j = col + 1; i >= 0 && j < n; --i, ++j)//右上方
{
if(tmp[i][j] == 'Q')
return false;
}
return true;
}
};
作者:zynflicker
链接:https://leetcode-cn.com/problems/n-queens/solution/4ms89mhui-su-fa-jian-dan-yi-dong-by-zynflicker/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
很典型的使用贪心算法的例题
class Solution
{
public:
int maxSubArray(vector<int> &nums)
{
//类似寻找最大最小值的题目,初始值一定要定义成理论上的最小最大值
int result = INT_MIN;
int numsSize = int(nums.size());
int sum = 0;
for (int i = 0; i < numsSize; i++)
{
sum += nums[i];
result = max(result, sum);
//如果sum < 0,重新开始找子序串
if (sum < 0)
{
sum = 0;
}
}
return result;
}
};
作者:pinku-2
链接:https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-cshi-xian-si-chong-jie-fa-bao-li-f/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
if(matrix.empty())return {};
int m = matrix.size(),n=matrix[0].size();
vector<vector<bool>> board(m,vector<bool>(n,false));
board[0][0]=true;
vector<int> res={matrix[0][0]};
string s = "right";
int i = 0,j=0;
while(res.size()<m*n)
{
if(s=="right")
{
if(j<n-1 && board[i][j+1]==false)
{
res.push_back(matrix[i][++j]);board[i][j]=true;
}
else{s="down";}
}
else if(s=="down")
{
if(i<m-1 && board[i+1][j]==false)
{
res.push_back(matrix[++i][j]);board[i][j]=true;
}
else{s="left";}
}
else if(s=="left")
{
if(j>0 && board[i][j-1]==false)
{
res.push_back(matrix[i][--j]);board[i][j]=true;
}
else{s="up";}
}
else if(s=="up")
{
if(i>0 && board[i-1][j]==false)
{
res.push_back(matrix[--i][j]);board[i][j]=true;
}
else{s="right";}
}
}
return res;
}
};
每次跟新一次位置,当最远达到的地方是0,说明false,代码用vs会出现莫名其妙的问题,但是做法应该是对的
另外由于可能出现的请情况太多了,在边界的设置上出错的地方太多了
class Solution {
public:
bool canJump(vector<int>& nums) {
int left = 0;
int len = nums.size();
while(1)
{
if(left>=len-1 || left+nums[left]>=len-1)return true;
int max = 0;
int temp = 0;
for(int i = left ; i<=len-1 &&i<=left+nums[left] ;i++)
{
if(i+nums[i]>max){max = i+nums[i];temp=i;}
}
if(max<len-1&& nums[max]==0)return false;
left = temp;
}
return false;
}
};
同样意思但更简洁的代码
解题思路:
1.如果某一个作为 起跳点 的格子可以跳跃的距离是 3,那么表示后面 3 个格子都可以作为 起跳点。
2.可以对每一个能作为 起跳点 的格子都尝试跳一次,把 能跳到最远的距离 不断更新。
3.如果可以一直跳到最后,就成功了。
作者:ikaruga
链接:https://leetcode-cn.com/problems/jump-game/solution/55-by-ikaruga/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
bool canJump(vector<int>& nums)
{
int k = 0;
for (int i = 0; i < nums.size(); i++)
{
if (i > k) return false;//k表示到i的时候,之前所有位置能到达的最大距离,每一个都走一下,但是不用考虑怎么走的,当走到一个位置不能再更新了,就会小于下一个i
k = max(k, i + nums[i]);
}
return true;
}
作者:ikaruga
链接:https://leetcode-cn.com/problems/jump-game/solution/55-by-ikaruga/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
同样的格式,但是改成max了,而且维护的不是一个树,而是先放到二维向量中的末尾
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> res;
if(intervals.empty())return res;
sort(intervals.begin(),intervals.end());
res.push_back(intervals[0]);
for(int i = 1 ;i< (int)intervals.size() ;i++)
{
if(intervals[i][0]<= res.back()[1])
{
res.back()[1] = max(res.back()[1],intervals[i][1]);
}
else
{
res.push_back(intervals[i]);
}
}
return res;
}
};
使用长度为1的滑动窗口在滑动,但是没想到题目还是会出现后面区间包含前面的情况,这样就要重新设计了
看到答案说sort函数排序可以默认按照第一个第二个这样排序,可以排序之后在做,排序之后后面的值肯定是大于等于前面的,但是还要考虑后面包含前面的情况
考点:排序+数组
思路:先对二维数组表示的所有区间的左端点进行升序排序,然后从第二个区间(下标为1)开始遍历判断是否可以做合并操作:只要前一个区间的右端点大于等于当前区间的左端点,那说明这两个区间可以合并,合并后的区间左端点是前一个区间的左端点,只需要更新右端点为两个区间右端点的最大值即可。
否则,说明两个区间没有重叠,直接更新表示不重复区间的pos值
作者:xing2fan
链接:https://leetcode-cn.com/problems/merge-intervals/solution/qu-jian-he-bing-de-pai-xu-fa-by-xing2fan/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
if (!intervals.size()) return {};
//先把区间集合按照左端点从小到大进行排序
sort(intervals.begin(), intervals.end(), less<vector<int>>());
int pos = 0;//pos的值是每个不重叠的区间
//直接在原区间上做就可以
//从第二个区间开始去比较
for (int i = 1; i < intervals.size(); ++i)
{
//两个区间若能合并,则第一个区间的右端点一定大于等于第二个区间的左端点
//比如[1,3] [2,6]
if (intervals[pos][1] >= intervals[i][0])
{
//第一个区间的尾部需要更新为:两个区间的最大值即[1,6]
intervals[pos][1] = max(intervals[pos][1], intervals[i][1]);
}
else//没有重叠时
{
//[1,6] [2,8]====>区间1就是目前的这个区间
intervals[++pos] = intervals[i];
}
}
intervals.resize(pos + 1);//把最后的不用的弹出
return intervals;
}
};
作者:xing2fan
链接:https://leetcode-cn.com/problems/merge-intervals/solution/qu-jian-he-bing-de-pai-xu-fa-by-xing2fan/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
if (intervals.empty()) {
return intervals;
}
sort(intervals.begin(), intervals.end());
vector<vector<int>> result{ intervals.front() };
for (auto&& interval : intervals) {
if (interval.front() > result.back().back()) {
result.emplace_back(move(interval));
} else {
result.back().back() = max(interval.back(), result.back().back());
}
}
return result;
}
};
作者:klaxxi
链接:https://leetcode-cn.com/problems/merge-intervals/solution/c-pai-xu-tan-xin-by-klaxxi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
和上题一样,先插入再做
class Solution {
public:
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
vector<vector<int>> res;
if(newInterval.empty())return intervals;
intervals.push_back(newInterval);
sort(intervals.begin(),intervals.end());
res.push_back(intervals[0]);
for(int i =1; i< (int)intervals.size() ;i++)
{
if(intervals[i][0]<= res.back()[1])
{
res.back()[1] = max(res.back()[1], intervals[i][1]);
}
else
{
res.push_back(intervals[i]);
}
}
return res;
}
};
class Solution {
public:
int lengthOfLastWord(string s) {
int len = s.size();
if(len==0)return 0;
int count = 0;
int i = len-1;
while(i>=0 && s[i]==' '){i--;}
while(i>=0 && s[i]!=' '){i--;count++;}
return count;
}
};
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n,vector<int>(n,0));
vector<vector<bool>> judge(n,vector<bool>(n,false));
int i = 0,j=0,count=1;
res[0][0]=count; judge[0][0]=true;
string s = "right";
while(count<n*n)
{
if( s=="right" )
{
if(j<n-1 && judge[i][j+1]==false)
{res[i][++j]=++count;judge[i][j]=true;}
else
{s="down";}
}
else if(s=="down")
{
if(i<n-1 && judge[i+1][j]==false)
{res[++i][j]=++count;judge[i][j]=true;}
else
{s="left";}
}
else if(s=="left")
{
if(j>0 && judge[i][j-1]==false)
{res[i][--j]=++count;judge[i][j]=true;}
else
{s="up";}
}
else if(s=="up")
{
if(i>0 && judge[i-1][j]==false)
{res[--i][j]=++count;judge[i][j]=true;}
else
{s="right";}
}
}
return res;
}
};
class Solution {
public:
string getPermutation(int n, int k) {
string s = "123456789";
string s1 = s.substr(0,n);
while(k-1 && next_permutation(s1.begin(),s1.end()))k--;
return s1;
}
};
class Solution {
public:
string next(string s,int n)
{
for(int i =n-1;i>=0;i--)
{
if(s[i]<s[i+1])
{
int m = INT_MAX,point = 0;
for(int j = i+1;j<=n;j++)
{
if(s[j]>s[i] && s[j]-s[i]<m)
{
m = s[j]-s[i];
point = j;
}
}
swap(s[i],s[point]);
reverse(s.begin()+i+1,s.end());
return s;
}
}
return {};
}
string getPermutation(int n, int k) {
string s;
for(int i =1;i<=n;i++)s += to_string(i);
while(k>1){k--;s = next(s,n);}
return s;
}
};
先变成一个环,再进行截断
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if(!head || !head->next)return head;
int count = 1;
auto temp = head;
while(temp->next){temp = temp->next;count++;}
auto tail = head;
k = k%count;
while((count-k)>1){k++;tail=tail->next;}
temp->next = head;
auto res = tail->next;
tail->next = NULL;
return res;
}
};
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> board(m,vector<int>(n,1));
for(int i =1 ;i<m;i++)
{
for(int j =1;j<n;j++)
{
board[i][j]=board[i-1][j]+board[i][j-1];
}
}
return board[m-1][n-1];
}
};
超时的dfs,而且剪枝的地方不多
class Solution {
public:
vector<vector<int>> board;
int res = 0;
vector<pair<int,int>> path;
void dfs(int m,int n)
{
int i = path.back().first;
int j = path.back().second;
if(i>= m || j>= n)return;
if(i==m-1 && j== n-1){res++;return;}
i++;
auto temp1 = make_pair(i,j);
path.push_back(temp1);
dfs(m,n);
path.pop_back();
i--;
j++;
auto temp2 = make_pair(i,j);
path.push_back(temp2);
dfs(m,n);
path.pop_back();
j--;
}
int uniquePaths(int m, int n) {
board = vector<vector<int>>(m,vector<int>(n,0));
path.push_back(make_pair(0,0));
dfs(m,n);
return res;
}
};
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
if(obstacleGrid.empty())return 0;
int len1 = obstacleGrid.size();
int len2 = obstacleGrid[0].size();
vector<vector<int>> dp(len1,vector<int>(len2,1));
bool k = true;
for(int i = 0; i<len1 ;i++)
{
if(k==false || obstacleGrid[i][0]==1){dp[i][0]=0;k=false;}
}
k = true;
for(int i = 0;i<len2;i++)
{
if(k==false || obstacleGrid[0][i]==1){dp[0][i]=0;k=false;}
}
for(int i = 1 ;i<len1 ;i++)
{
for(int j =1 ;j<len2 ;j++)
{
if(obstacleGrid[i][j]==1)dp[i][j]=0;
else
{
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
}
return dp[len1-1][len2-1];
}
};
很典型的动态规划题目,和上题一样
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if(grid.empty())return 0;
int m = grid.size();
int n = grid[0].size();
vector<vector<int>> board(m,vector<int>(n,0));
board[0][0]=grid[0][0];
for(int i = 1 ; i< n ;i++)
{
board[0][i] = grid[0][i]+board[0][i-1];
}
for(int i = 1 ; i< m ; i++)
{
board[i][0] = grid[i][0]+board[i-1][0];
}
for(int i = 1 ; i < m ;i++)
{
for(int j = 1 ; j< n; j++)
{
board[i][j] = grid[i][j] + min( board[i-1][j],board[i][j-1]);
}
}
return board[m-1][n-1];
}
};
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
int len = digits.size();
int b = 0;
for(int i = len-1 ; i>=0;i--)
{
int temp = b + digits[i];
if(i==len-1)temp++;
if(temp>=10){b = 1;}
else{b = 0;}
digits[i]=temp%10;
}
if(b)digits.insert(digits.begin(),1);
return digits;
}
};
class Solution {
public:
string addBinary(string a, string b) {
int lena = a.size();
int lenb = b.size();
int bb = 0;
string res;
int i =lena-1,j=lenb-1 ;
while( i>=0&&j>=0)
{
int temp = (a[i--]-'0')+(b[j--]-'0');
res = to_string((temp+bb)%2) + res;
if(temp+bb==2 || temp+bb==3){bb=1;}
else bb=0;
}
while(i>=0)
{
int temp = a[i--]-'0';
res = to_string((temp+bb)%2) + res;
if(temp+bb==2)bb=1;
else bb=0;
}
while(j>=0)
{
int temp = b[j--]-'0';
res = to_string((temp+bb)%2) + res;
if(temp+bb==2)bb=1;
else bb=0;
}
if(bb)res = "1"+res;
return res;
}
};
e
class Solution {
public:
int mySqrt(int x) {
if(x==1)return 1;
int left = 1,right = x/2+1;
while(left<right)
{
int mid = left + (right-left)/2;
if((double)x/mid == mid)return mid;
else if((double)x/mid > mid)left = mid + 1;
else right = mid;
}
return left-1;
}
};
动态规划
class Solution {
public:
int climbStairs(int n) {
if(n==0)return 0;
if(n==1)return 1;
if(n==2) return 2;
vector<int> dp(n+1,0);
dp[0]=0;
dp[1]=1;
dp[2]=2;
for(int i = 3 ; i<n+1; i++)
{
dp[i] = dp[i-1]+ dp[i-2];
}
return dp[n];
}
};
class Solution {
public:
string simplifyPath(string path) {
vector<string> vt;
int point = 0;
int i = 0,j=0;
int len = path.size();
while (i < len)
{
while (i < len && path[i] == '/')i++;
j = i;
while (i < len && path[i] != '/')i++;
if (i > j) {
string temp = path.substr(j, i - j);
if (temp == "..")
{
if (!vt.empty())
{
vt.pop_back();
point--;
}
}
else if (temp == ".")
{
if (point < vt.size() - 1)
{
point++;
}
}
else
{
vt.push_back(temp);
point++;
}
}
}
string res = "/";
for(auto i:vt)
{
res = res + i + '/';
}
if(res!="/")res.pop_back();
return res;
}
};
class Solution {
public:
int minDistance(string word1, string word2) {
int len1 = word1.size();
int len2 = word2.size();
vector<vector<int>> dp(len1+1, vector<int>(len2+1,0));
for(int i = 0 ;i<=len1; i++)
{
dp[i][0] = i;
}
for(int j = 0 ; j<=len2 ;j++)
{
dp[0][j] = j;
}
for(int i=1 ;i<=len1 ;i++)
{
for(int j=1; j<=len2 ;j++)
{
if(word1[i-1]==word2[j-1])
{
dp[i][j] = dp[i-1][j-1] ;
}
else
{
dp[i][j] = min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1;
}
}
}
return dp[len1][len2];
}
};
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
if(matrix.size()==0)return;
vector<int> row;
vector<int> col;
int len1 = matrix.size();
int len2 = matrix[0].size();
for(int i= 0 ;i<len1 ; i++)
{
for(int j = 0 ; j <len2 ;j++)
{
if(matrix[i][j]==0)
{
row.push_back(i);
col.push_back(j);
}
}
}
for(auto i :row)
{
for(int j = 0 ; j<len2 ;j++)
{
matrix[i][j]=0;
}
}
for(auto j:col)
{
for(int i = 0 ; i<len1 ; i++)
{
matrix[i][j] = 0;
}
}
return;
}
};
只有三个数的时候排序可以如此简单
class Solution {
public:
void sortColors(vector<int>& nums) {
int left = 0 , right = nums.size()-1;
for(int i = left ;i<=right ;i++)
{
if(nums[i]==0)swap(nums[left++],nums[i]);
if(nums[i]==2)swap(nums[right--],nums[i--]);
}
return;
}
};
巩固一下快速排序,要特注意的是先循环j再循环i
class Solution {
public:
void quicksort(int left,int right, vector<int>& nums)
{
if(left>=right)return;
int i = left;
int j = right;
while(i<j)
{
while(i<j && nums[j]>=nums[left])j--;
while(i<j && nums[i]<=nums[left])i++;
if(i<j)
{
swap(nums[i],nums[j]);
}
}
swap(nums[left],nums[i]);
quicksort(left,i-1,nums);
quicksort(i+1,right,nums);
}
void sortColors(vector<int>& nums) {
int len = nums.size();
if(len==0 || len==1)return;
quicksort(0,len-1,nums);
return;
}
};
采用了两个二分法模板做的,注意衔接的时候,要考虑小于第一个个值的情况
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if(matrix.empty())return false;
if(matrix[0].empty())return false;
int len = matrix.size();
int left = 0,right = len;
while(left<right)
{
int mid = (left+right)/2;
if(matrix[mid][0]==target)return true;
else if(matrix[mid][0]<target)
{
left = mid+1;
}
else
{
right = mid;
}
}
int temp = left-1;
if(temp<0)return false;
len = matrix[0].size();
left = 0;right=len;
while(left<right)
{
int mid = (left+right)/2;
if(matrix[temp][mid]==target) return true;
else if(matrix[temp][mid]<target)
{
left=mid+1;
}
else
{
right=mid;
}
}
return false;
}
};
维护哈希表并滑动窗口,超时了
class Solution {
public:
bool judge(unordered_map<char, int> mp, unordered_map<char, int> mt)
{
for (auto m:mt)
{
if (mp[m.first] < mt[m.first])return false;
}
return true;
}
string minWindow(string s, string t) {
unordered_map<char,int> mt;
for(auto t1:t)mt[t1]++;
int lens = s.size();
int lent = t.size();
if(lens<lent)return "";
int start = 0, len = INT_MAX;
int i =0 ,j =0;
unordered_map<char,int> mp;
//A
while(i<lens)
{
if (mt.find(s[i]) != mt.end())
{ mp[s[i]]++; }
while (judge(mp,mt))
{
if (mt.find(s[j]) == mt.end())j++;
else
{
if (i - j + 1 < len) { len = i - j + 1; start = j; }
mp[s[j]]--;
if (mp[s[j]] == 0)mp.erase(s[j]);
j++;
}
}
i++;
}
return len==INT_MAX?"":s.substr(start,len);
}
};
由于这个pos代表的是初始位置,当进行过一次遍历后,这个值也要加1才行
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
void dfs(int p,int n,int k)
{
if(path.size()==k)
{
res.push_back(path);return;
}
for(int i = p ;i<=n;i++)
{
path.push_back(i);
dfs(i+1,n,k);
path.pop_back();
}
}
vector<vector<int>> combine(int n, int k) {
dfs(1,n,k);
return res;
}
};
其他解答,道理是一样的
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> list;
vector<int> result;
dfs(list,result,n,k,0,-1);
return list;
}
void dfs(vector<vector<int>>& list, vector<int>& result, int n, int k, int pos,int pre){
if(pos == k){
list.push_back(result);
return;
}
if((pos + (n-pre)) <= k)return;//剪枝,添加之后用时节省了2/3
//在当前对不合理的取值进行判断,结束下一层的递归操作。
//如果当前剩余可操作数字的个数即(n-pre)< k-pos+1(即组合中有待赋值的位置个数),(+1是因为当前pos还没有进行操作),则可以判断该条路径不可能得到正确的解,不再向下探寻。
for(int i=pre+1; i<n ; i++){
result.push_back(i+1);
pre = i;
dfs(list,result,n,k,pos+1,pre);
result.pop_back();//回溯
}
return;
}
};
作者:rouzi
链接:https://leetcode-cn.com/problems/combinations/solution/dfsjian-zhi-by-rouzi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
注意return的位置
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
void dfs(vector<int>& nums,int p)
{
res.push_back(path);
if(p==nums.size())return;
for(int i= p;i<nums.size();i++)
{
path.push_back(nums[i]);
dfs(nums,i+1);
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
dfs(nums,0);
return res;
}
};
这道题要么注释的在前,要么就想下面这样换个条件放后面。如果按照正常理解的话应该是注释这句,但是注意它的位置,因为判断false这一句会直接导致无法到达这句。上面那道题也是,要注意顺序,如果先return了就无法放到res中了。所以dfs的return既不一定在最前,而且true和false之间也是有讲究的,一般来说true应该放在false的前面
class Solution {
public:
bool dfs(int i ,int j, int m, int n, vector<vector<char>>& board, string word,int p )
{
//if(p==word.size())return true;
if(i<0 || i==m || j<0 || j==n || board[i][j]!=word[p])return false;
if(p==word.size()-1 && board[i][j]==word[p])return true;
auto temp = board[i][j];
board[i][j]='0';
bool b = dfs(i+1,j,m,n,board,word,p+1) || dfs(i,j+1,m,n,board,word,p+1) || dfs(i-1,j,m,n,board,word,p+1) || dfs(i,j-1,m,n,board,word,p+1);
board[i][j]=temp;
return b;
}
bool exist(vector<vector<char>>& board, string word) {
int m = board.size(),n = board[0].size();
for(int i = 0;i<m;i++)
{
for(int j = 0;j<n;j++)
{
if(dfs(i,j,m,n,board,word,0))return true;
}
}
return false;
}
};
int removeDuplicates(vector<int>& nums) {
int i = 0 , j = 0 , len = nums.size();
while(i<len-1)
{
auto temp = nums[i];
if(nums[i]==temp && nums[i+1]==temp)
{
while(i<len && nums[i]==temp)i++;
nums[j++]=temp;
nums[j++]=temp;
}
else
{
nums[j++]=nums[i++];
}
}
if(i==len-1)nums[j++]=nums[i];
return j;
}
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int len = nums.size();
int i = 0, j = 0;
while(i<len)
{
int temp = i;
while(i<len && nums[i]==nums[temp])i++;
if(i-temp==1){nums[j++]=nums[temp];}
else if(i-temp>=2){nums[j++]=nums[temp];nums[j++]=nums[temp];}
}
return j;
}
};
先去重
class Solution {
public:
bool search(vector<int>& nums, int target) {
if(nums.empty())return false;
int j = 0;
for(int i =1 ;i<(int)nums.size() ;i++)
{if(nums[i]!=nums[j])nums[++j]=nums[i];}
vector<int> num;
num.assign(nums.begin(),nums.begin()+j+1);
if((int)num.size()>1 && num[j]==num[0]){num.pop_back();}
int right = num.size();
int left = 0;
while(left<right)
{
int mid = left + (right-left)/2;
if(num[mid]==target){return true;}
else if (num[mid]>target)
{
if(target>=num[0] || num[mid]<num[0]){right = mid;}
else{left=mid+1;}
}
else
{
if(num[mid]>=num[0] ||target<num[0]){left=mid+1;}
else{right=mid;}
}
}
return false;
}
};
要注意将末尾指针指空,不然会指向其他的地方
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head )return head;
auto head1 = new ListNode(0);
head1->next = head;
auto slow = head1;
auto fast = head;
while(fast)
{
if(fast->next && fast->next->val==fast->val)
{
auto temp = fast->val;
while(fast && fast->val==temp )
{
fast = fast->next;
}
}
else
{
slow->next =fast;
slow = fast;
fast = fast->next;
}
}
slow->next =NULL;
return head1->next;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head || !head->next)return head;
auto head1 = new ListNode(INT_MAX);
head1->next = head;
auto slow = head1;
auto fast = head;
while(fast && fast->next)
{
if(fast->val==fast->next->val)
{
while(fast->next && fast->val == fast->next->val)
{
fast = fast->next;
}
fast = fast->next;
}
else
{
slow->next = fast;
slow = fast;
fast = fast->next;
}
}
slow->next = fast;
return head1->next;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head || !head->next)return head;
auto slow = head;
auto fast = head->next;
while(fast)
{
if(fast->val==slow->val)
{
fast = fast->next;
}
else
{
slow->next = fast;
slow = fast;
}
}
slow->next = NULL;
return head;
}
};
//维护一个单调非递减的栈。
//核心思想还是选取中心元素尽量向两侧延申。
//当heights[i]小于栈顶元素时,以栈顶元素为高的矩形已不能继续向右延申(达到右边界)。
//矩形左边界就是栈内元素的前一个元素。
class Solution {
public:
int largestRectangleArea(vector<int> heights) {
//单调栈存放id
stack<int> st;
st.push(0);
heights.insert(heights.begin(),0);
heights.push_back(0);
int res = 0;
for(int i =1;i<heights.size();i++)
{
while (!st.empty() &&heights[st.top()] > heights[i])
{
auto temp = st.top(); st.pop();
res = max(res,heights[temp]*(i-st.top()-1));
}
st.push(i);
}
return res;
}
};
class Solution {
public:
int func(vector<int> nums)
{
int res = 0;
nums.insert(nums.begin(),0);
nums.push_back(0);
stack<int> st;
st.push(0);
for(int i = 1; i<nums.size();i++)
{
while(!st.empty() && nums[st.top()]>nums[i])
{
auto temp = st.top(); st.pop();
res = max(res,(nums[temp])*(i-st.top()-1));
}
st.push(i);
}
return res;
}
int maximalRectangle(vector<vector<char>>& matrix) {
if(matrix.empty())return 0;
int m = matrix.size();
int n = matrix[0].size();
vector<int> dp(n,0);
int res = 0;
for(int i = 0;i<m;i++)
{
for(int j = 0;j<n;j++)
{
dp[j] = matrix[i][j]=='1'?dp[j]+1:0;
}
res = max(res, func(dp));
}
return res;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
auto head1 = new ListNode(0);
auto temp1 = head1;
auto head2 = new ListNode(0);
auto temp2 = head2;
int count=0;
while(head)
{
if(head->val<x)
{
temp1->next = head;
temp1 = head;
}
else
{
temp2->next = head;
temp2=head;
}
head=head->next;
}
temp1->next = head2->next;
temp2->next = NULL;
return head1->next;
}
};
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
for(int i = 0;i<n;i++)
{
auto temp = lower_bound(nums1.begin(),nums1.begin()+m+i,nums2[i]);
nums1.insert(temp,nums2[i]);
}
while(n--)nums1.pop_back();
return ;
}
};
class Solution {
public:
void merge(vector<int>& arr1, int m, vector<int>& arr2, int n) {
//int len1 = arr1.size();
//int len2 = arr2.size();
if(m==0)
{
arr1.assign(arr2.begin(),arr2.end());
return;
}
if(n==0) return;
int i = m - 1;
int j = n - 1;
int k = m + n - 1;
while (i>= 0 && j>= 0)
{
while (i>= 0 && j>=0 && arr1[i] >= arr2[j])
{
arr1[k--] = arr1[i--];
}
while (i >= 0 && j >= 0 && arr1[i] <= arr2[j])
{
arr1[k--] = arr2[j--];
}
}
while (i>=0 )
{
arr1[k--] = arr1[i--];
}
while (j>=0)
{
arr1[k--] = arr2[j--];
}
return ;
}
};
n = 0, [0]
n = 1, [0,1] //新的元素1,为0+2^0
n = 2, [0,1,3,2] // 新的元素[3,2]为[0,1]->[1,0]后分别加上2^1
n = 3, [0,1,3,2,6,7,5,4] // 新的元素[6,7,5,4]为[0,1,3,2]->[2,3,1,0]后分别加上2^2->[6,7,5,4]
作者:chengm15
链接:https://leetcode-cn.com/problems/gray-code/solution/zhi-xing-yong-shi-nei-cun-xiao-hao-ji-bai-liao-1-5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<int> grayCode(int n) {
if(n==0)return {0};
vector<int> res = {0,1};
while(n-1)
{
n--;
int p = pow(2,n);
auto res1 = res;
reverse(res1.begin(),res1.end());
for(int i =0;i<res1.size();i++)res.push_back(res1[i]+p);
}
return res;
}
};
做这种有重复元素的dfs之前要对数组进行排序,这样去重时可以保证内部同时去重了
class Solution {
public:
set<vector<int>> st;
vector<int> path;
void dfs(vector<int>& nums, int p,int len)
{
st.insert(path);
if(p==len)return;
for(int i = p;i<len;i++)
{
path.push_back(nums[i]);
dfs(nums,i+1,len);
path.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
int len = nums.size();
sort(nums.begin(),nums.end());
dfs(nums,0,len);
vector<vector<int>> res(st.begin(),st.end());
return res;
}
};
动态规划,暂时不考虑0的情况
本来是想使s[i-1]+s[i]拼接成一个string字符串,但是发现直接相加拼接是不可以的,甚至写成注释那样在一行都是不可以的,因为程序会先执行等号右边的内容,只有写成两个小式子才可以。对于这种拼接(连续的)最好直接使用substr,实在要拼接也要先定义string然后分布写才行
int numDecodings(string s) {
int len= s.size();
vector<int> dp(len,1);
for(int i = 1;i<len;i++)
{
string s1;
//s1 += s[i-1]+s[i];
s1 += s[i - 1]; s1 += s[i];
int temp = stoi(s1);
if( temp<=26 )dp[i]=dp[i-1]+1;
else dp[i]=dp[i-1];
}
return dp[len-1];
}
#include
#include
class Solution {
public:
int numDecodings(string s) {
int len = s.size();
vector<int> dp(len,0);
dp[0]=1;
for(int i = 1 ;i<len;i++)
{
if(atoi(s.substr(i-1,2).c_str())<=26)dp[i] = dp[i-1]+1;
else dp[i] =dp[i-1];
}
return dp[len-1];
}
};
atoi(str.c_str());
stoi(str);
int(char-'0')
涉及到的参量实在太多了,必须要画图进行分析才行
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
auto head1 = new ListNode(0);
head1->next = head;
auto temp = head1;
while(m-1){m--; temp = temp -> next;}
auto start = temp;
auto pre1 = start->next,pre = pre1;
auto cur = pre->next;
temp = head;
while(n-1){n--;temp = temp->next;}
auto end = temp;
auto nexts = end->next;
while(cur != nexts)
{
auto temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
start->next = end;
pre1->next = nexts;
return head1->next;
}
};
dfs里的循环方法设置的比较巧妙,设置一个p然后在这三位进行寻找,使用这种回溯的始终是比较快的,但是要注意的是越界问题,所以设置i的循环时要加min这是一种比较重要的防止越界的方法。另外注意path和p都有可能先到达极限,所以对这两个变量都要设置终止递归条件
class Solution {
public:
vector<vector<string>> res;
vector<string> path;
void dfs(string s, int p)
{
if(path.size()==4 )
{
if(p==s.size()){res.push_back(path);}
return;
}
if (p >= s.size())return;
for(int i=p;i<=min((int)s.size()-1,p+2);i++)
{
auto temp = s.substr(p,i-p+1);
if(temp[0]=='0' && temp.size()>1)break;
if(stoi(temp)<=255)
{
path.push_back(temp);
dfs(s,i+1);
path.pop_back();
}
}
}
vector<string> restoreIpAddresses(string s) {
dfs(s,0);
vector<string> ss;
for(auto r:res)
{
string s1;
for(auto rr:r)
{
s1 += rr + '.';
}
s1.pop_back();
ss.push_back(s1);
}
return ss;
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
vector<int> res;
public:
void dfs(TreeNode* root)
{
if(!root) return;
dfs(root->left);
res.push_back(root->val);
dfs(root->right);
}
vector<int> inorderTraversal(TreeNode* root) {
if(!root) return res;
dfs(root);
return res;
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> res;
auto cur = root;
while(cur || !st.empty())
{
while(cur)
{
st.push(cur);
cur = cur->left;
}
auto temp = st.top(); st.pop();
res.push_back(temp->val);
if(temp->right)cur = temp->right;
}
return res;
}
};
看不懂为什么这么做
解法一完全没有用到查找二叉树的性质,暴力尝试了所有可能从而造成了重复。我们可以利用一下查找二叉树的性质。左子树的所有值小于根节点,右子树的所有值大于根节点。
所以如果求 1…n 的所有可能。
我们只需要把 1 作为根节点,[ ] 空作为左子树,[ 2 … n ] 的所有可能作为右子树。
2 作为根节点,[ 1 ] 作为左子树,[ 3…n ] 的所有可能作为右子树。
3 作为根节点,[ 1 2 ] 的所有可能作为左子树,[ 4 … n ] 的所有可能作为右子树,然后左子树和右子树两两组合。
4 作为根节点,[ 1 2 3 ] 的所有可能作为左子树,[ 5 … n ] 的所有可能作为右子树,然后左子树和右子树两两组合。
…
n 作为根节点,[ 1… n ] 的所有可能作为左子树,[ ] 作为右子树。
至于,[ 2 … n ] 的所有可能以及 [ 4 … n ] 以及其他情况的所有可能,可以利用上边的方法,把每个数字作为根节点,然后把所有可能的左子树和右子树组合起来即可。
如果只有一个数字,那么所有可能就是一种情况,把该数字作为一棵树。而如果是 [ ],那就返回 null。
作者:windliang
链接:https://leetcode-cn.com/problems/unique-binary-search-trees-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-2-7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
public List<TreeNode> generateTrees(int n) {
List<TreeNode> ans = new ArrayList<TreeNode>();
if (n == 0) {
return ans;
}
return getAns(1, n);
}
private List<TreeNode> getAns(int start, int end) {
List<TreeNode> ans = new ArrayList<TreeNode>();
//此时没有数字,将 null 加入结果中
if (start > end) {
ans.add(null);
return ans;
}
//只有一个数字,当前数字作为一棵树加入结果中
if (start == end) {
TreeNode tree = new TreeNode(start);
ans.add(tree);
return ans;
}
//尝试每个数字作为根节点
for (int i = start; i <= end; i++) {
//得到所有可能的左子树
List<TreeNode> leftTrees = getAns(start, i - 1);
//得到所有可能的右子树
List<TreeNode> rightTrees = getAns(i + 1, end);
//左子树右子树两两组合
for (TreeNode leftTree : leftTrees) {
for (TreeNode rightTree : rightTrees) {
TreeNode root = new TreeNode(i);
root.left = leftTree;
root.right = rightTree;
//加入到最终结果中
ans.add(root);
}
}
}
return ans;
}
作者:windliang
链接:https://leetcode-cn.com/problems/unique-binary-search-trees-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-2-7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<TreeNode*> generateTrees(int n) {
if(n == 0) return {};
return helper(1, n);
}
vector<TreeNode*> helper(int start, int end) {
if(start > end) return {nullptr};
vector<TreeNode*> res;
for(int i=start; i<=end; i++) {
auto left = helper(start, i-1), right = helper(i+1, end);
for(auto a:left) {
for(auto b:right) {
TreeNode* node = new TreeNode(i);
node->left = a;
node->right = b;
res.push_back(node);
}
}
}
return res;
}
};
作者:lioney
链接:https://leetcode-cn.com/problems/unique-binary-search-trees-ii/solution/lioney-cjian-dan-di-gui-by-lioney-16/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
都不需要使用节点就可以求,和上题的思路一样
class Solution {
public:
int dfs(int p,int q)
{
if(p>q)return 1;
int res = 0;
for(int i =p; i<=q ;i++)
{
res += dfs(p,i-1)*dfs(i+1,q);
}
return res;
}
int numTrees(int n) {
if(n==0)return 0;
return dfs(1,n);
}
};
能正确判断,但是超时了,因为递归的效率比较低;
对于字符串的题,使用递归都比较耗时
class Solution {
public:
bool dfs(string s1, string s2, string s3, int a1, int a2 ,int a3)
{
if( a1==s1.size() && a2==s2.size() && a3==s3.size() )return true;
if(s3[a3]!=s1[a1] && s3[a3]!=s2[a2] )return false;
else if(s3[a3]==s1[a1] && s3[a3]!=s2[a2] )return dfs(s1,s2,s3,a1+1,a2,a3+1);
else if(s3[a3]!=s1[a1] && s3[a3]==s2[a2] )return dfs(s1,s2,s3,a1,a2+1,a3+1);
else if(s3[a3]==s1[a1] && s3[a3]==s2[a2] )return dfs(s1,s2,s3,a1+1,a2,a3+1)||dfs(s1,s2,s3,a1,a2+1,a3+1);
return false;
}
bool isInterleave(string s1, string s2, string s3) {
if(s3.size()!=s1.size()+s2.size())return false;
return dfs(s1,s2,s3,0,0,0);
}
};
public class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
if (s3.length() != s1.length() + s2.length()) {
return false;
}
boolean dp[][] = new boolean[s1.length() + 1][s2.length() + 1];
for (int i = 0; i <= s1.length(); i++) {
for (int j = 0; j <= s2.length(); j++) {
if (i == 0 && j == 0) {
dp[i][j] = true;
} else if (i == 0) {
dp[i][j] = dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1);
} else if (j == 0) {
dp[i][j] = dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1);
} else {
dp[i][j] = (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1)) || (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1));
}
}
}
return dp[s1.length()][s2.length()];
}
}
作者:LeetCode
链接:https://leetcode-cn.com/problems/interleaving-string/solution/jiao-cuo-zi-fu-chuan-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
int N1 = s1.size();
int N2 = s2.size();
int N3 = s3.size();
if (N1 + N2 != N3) return false;
vector<vector<bool> > dp(N1 + 1, vector<bool>(N2 + 1, false));
dp[0][0] = true;
for (int i = 0; i <= N1; ++i) {
for (int j = 0; j <= N2; ++j) {
if (i > 0 && s1[i - 1] == s3[i + j - 1]) {
dp[i][j] = dp[i][j] || dp[i - 1][j];
}
if (j > 0 && s2[j - 1] == s3[i + j - 1]) {
dp[i][j] = dp[i][j] || dp[i][j - 1];
}
}
}
return dp[N1][N2];
}
};
作者:da-li-wang
链接:https://leetcode-cn.com/problems/interleaving-string/solution/c-dong-tai-gui-hua-by-da-li-wang-32/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> res;
void dfs(TreeNode* root)
{
if(!root)return;
dfs(root->left);
res.push_back(root->val);
dfs(root->right);
}
bool isValidBST(TreeNode* root) {
dfs(root);
for(int i = 1;i<res.size();i++)
{
if(res[i]<=res[i-1])return false;
}
return true;
}
};
之前的思路是判断两百边的数组,但是获得数组就需要进行遍历,十分麻烦,下面的解法目的不是求节点是否在左右节点数组的中间,而是每个节点和一个区间进行比较,这个区间一开始是无限大,每经过一个节点就将区间范围缩小,往左节点走时父节点作为有边界,往右边界走时父节点作为左边界,这样可以不断的将父节点的区间范围传递下去,十分巧妙
思路:引入上下边界
对于树的每个节点 val ,设其上下边界 low , high。(用 long 防止 INT_MAX 溢出 )
判断根结点时,须满足 low < val < high ,否则返回 false
判断左节点时,仅 上界 变化 ( 新上界为 high 与 val 较小值。又因 val 必小于 high,故新上界为 val )
判断右节点时,仅 下界 变化 ( 同理,新下界为 val )
bool fun(struct TreeNode* root, long low, long high) {
if (root == NULL) return true;
long num = root->val;
if (num <= low || num >= high) return false;
return fun(root->left, low, num) && fun(root->right, num, high);
}
bool isValidBST(struct TreeNode* root){
return fun(root, LONG_MIN, LONG_MAX);
}
作者:penn-10
链接:https://leetcode-cn.com/problems/validate-binary-search-tree/solution/cyu-yan-yan-zheng-er-cha-sou-suo-shu-by-penn-10/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这道题用到了一个特别重要的知识:中序遍历一定是顺序的,如果发生了节点交换,通过中序遍历就可以找出是哪些节点被该改变了
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> res;
int point1= 0,point2 = 0;
void dfs2(TreeNode* root)
{
if(!root)return;
if(root->val==point1){root->val=point2;}
else if(root->val==point2){root->val=point1;}
dfs2(root->left);
dfs2(root->right);
}
void dfs1(TreeNode* root)
{
if(!root)return;
dfs1(root->left);
res.push_back(root->val);
dfs1(root->right);
}
void recoverTree(TreeNode* root) {
dfs1(root);
for(int i = 0;i<res.size()-1;i++)
{
if(res[i]>res[i+1])
{
point1 = res[i];
break;
}
}
for(int i = res.size()-1;i>0;i--)
{
if(res[i]<res[i-1])
{
point2 = res[i];
break;
}
}
dfs2(root);
return;
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> res;
void dfs1(TreeNode* root)
{
if(!root)return;
dfs1(root->left);
res.push_back(root->val);
dfs1(root->right);
}
void dfs2(TreeNode* root, vector<int>& res1)
{
if(!root)return;
dfs2(root->left,res1);
if(root->val==res1.front())res1.erase(res1.begin());
else {root->val=res1.front();res1.erase(res1.begin());}
dfs2(root->right,res1);
}
void recoverTree(TreeNode* root) {
dfs1(root);
auto res1 = res;
sort(res1.begin(),res1.end());
dfs2(root,res1);
return;
}
};