因为不知道怎么加cmp函数,就只能pair的first设为值了,但其实这也是瞎做,应该也是O(n²)吧
class Solution {
public:
vector twoSum(vector& nums, int target) {
pairpa[10004];int n=0;
for(auto i:nums){
pa[n].first=i;pa[n].second=n;n=n+1;
}
sort(pa,pa+n);
int j=0,i=1;
while(jtarget){
j++;i=j+1;
}
else return {pa[i].second,pa[j].second};
}
return {-1,-1};
}
};
class Solution {
public:
vector twoSum(vector& nums, int target) {
int n = nums.size();
for(int i = 0; i < n; i++)
for(int j = i + 1; j < n; j++)
if(nums[i] + nums[j] == target) return {i,j};
return {-1,-1};
}
};
如果总和大于target,大的变小,如果总和小于target,小的变大。
class Solution {
public:
vector twoSum(vector& nums, int target) {
pairpa[10004];int n=0;
for(auto i:nums){
pa[n].first=i;pa[n].second=n;n=n+1;
}
sort(pa,pa+n);
int j=0, i=n-1;
while(jtarget) i--;
else j++;
}
return {-1,-1};
}
};
用了Hash。原理是加入一个值,如果map里面有对应的值就输出各自的序号,没有就保存序号。蓝桥杯有一道题好像就是这样做的
class Solution {
public:
vector twoSum(vector& nums, int target) {
int n = nums.size();
unordered_map mp;
for(int i=0;i
一开始看错了,以为最右边是个位,看了一些答案才发现是最左边是个位
首先先创建一个头节点,之后有一个移动指针p->next=new ListNode(sum%10);
一直到链表遍历完,进位(carry)结束
最后返回链表head->next
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* head=new ListNode();
ListNode* p=head;
int carry=0;
while(l1!=NULL||l2!=NULL||carry){
int sum=0;
if(l1!=NULL){
sum+=l1->val;
l1=l1->next;
}
if(l2!=NULL){
sum+=l2->val;
l2=l2->next;
}
sum+=carry;
carry=sum/10;
p->next=new ListNode(sum%10);
p=p->next; //p指向下一个结点
}
return head->next;
}
};
class Solution {
public:
ListNode *helper(ListNode *l1,ListNode *l2,int carry){
if(!l1 && !l2){
if(carry) return new ListNode(carry);
else return NULL;
}
int val=(l1?l1->val:0)+(l2?l2->val:0)+carry;
ListNode *res=new ListNode(val%10);
res->next=helper((l1?l1->next:NULL),(l2?l2->next:NULL),val/10);
return res;
}
ListNode *addTwoNumbers(ListNode *l1,ListNode *l2){
return helper(l1,l2,0);
}
};
有思路但不会写
时间复杂度为n,就是直接扫一遍,每次扫到一个字符
如果vis为0,vis[i]设为1
如果扫到的vis已经为1,从头pop_front(),直到vis[i]为0,比较ans和max的大小,选择保留
之后,将扫到的字符加入ans中
我发现string容器没有pop_front,而且每一次比较ans和max的大小,选择保留时都要重新遍历一遍,时间复杂度其实挺大的
答案也用了vis,不过直接先把string存起来,记录pair下表
之前的思路已经忘光光了,重新整理了思路,用vis记录string的下标,st的子串的左端点,string从1开始计数
若vis[s[i]]为真,那么将st到vis[s[i]]之间的字符的vis清零,st更新为vis[s[i]]+1,将vis[s[i]]更新为i;若vis[s[i]]为假,代表没遇到过这个字符,直接记录位置;
最后字符串循环一次后,记得再更新一次max的大小!!
另外初始化的时候,直接空字符串输出0!!
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s=="")return 0;
if(s=="")return 0;
int vis[300]={0};pairmaxx;int st=1;maxx.first=1; maxx.second=1;
s="!"+s;
vis[s[st]]=st;
for(int i=2;i(maxx.second-maxx.first)){
maxx.first=st; maxx.second=i;
}
while(st<=vis[s[i]]){vis[s[st]]=0;st++;}//将st更新到重复出现的位置的后面
}
vis[s[i]]=i;//如果没有,记录位置;有就更新位置
}
if((s.size()-st)>(maxx.second-maxx.first)){
maxx.first=st; maxx.second=s.size();
}
return maxx.second-maxx.first;
}
};
两个已排好序的数组 找中位数 数组从0开始计数
算法课上学过O(log(mn))的算法,但是忘记了,只会O(m+n)的合并后直接中位数了
class Solution {
public:
double findMedianSortedArrays(vector& nums1, vector& nums2) {
vectoruse;
int len1=nums1.size(),len2=nums2.size();
int i=0,j=0;
for(;i
看了解析后:
简述:用二分查找的思想做这道题。如果要更小的,把最大的那部分给删了;如果要更大的,把最小的那部分给删了
设A数组和B数组的中位数为AM和AM,其位置是AI和BI,为了找位置为K的数:
如果AI+BI小于K,说明AI和BI的位置小了,要大一点;
若AV小于BV,那么把【Astart,AI】的部分删掉,确保不会删掉第K位数;反之亦然。
如果AI+BI大于等于K,说明 Astart到AI 和 Bstart到BI (共AI+BI+2个数)中有位置为K的数;
若AV大于BV,那么把【AI,Aend】的部分删掉,确保不会删掉第K位数;反之亦然。
最后A或者B的Start>End,结束;若BStart>BEnd,最后返回A【k-BStart】,反之亦然
注意数组的范围是【0, n.size()-1】!!!
class Solution {
public:
double findMedianSortedArrays(vector& n, vector& m) {
int num=int(n.size())+int(m.size());
if(num%2)
return q(n,m,num/2,0,n.size()-1,0,m.size()-1);
return (q(n,m,num/2,0,n.size()-1,0,m.size()-1)+q(n,m,num/2-1,0,n.size()-1,0,m.size()-1))/2.0;
}
double q(vector& a,vector& b,int k,int Astart,int Aend,int Bstart,int Bend){
if(Astart>Aend)return b[k-Astart];
if(Bstart>Bend)return a[k-Bstart];
int AIndex=(Astart+Aend)/2,BIndex=(Bstart+Bend)/2;
int aV=a[AIndex],bV=b[BIndex];
if(AIndex+BIndexbV)
return q(a,b,k,Astart,Aend,BIndex+1,Bend);
else
return q(a,b,k,AIndex+1,Aend,Bstart,Bend);
}
else{//删除大的部分
if(aV>bV)
return q(a,b,k,Astart,AIndex-1,Bstart,Bend);
else
return q(a,b,k,Astart,Aend,Bstart,BIndex-1);
}
return -1;
}
};
还有一个做法是O(log(min(m,n))),但是我没有看懂,在实际运行的时候,是45ms,就很怪
class Solution {
public:
double findMedianSortedArrays(vector& nums1, vector& nums2) {
if (nums1.size() > nums2.size()) {
return findMedianSortedArrays(nums2, nums1);
}
int m = nums1.size(), n = nums2.size();
int left = 0, right = m;
while (left <= right) {
int partitionA = (left + right) / 2;
int partitionB = (m + n + 1) / 2 - partitionA;
int maxLeftA = (partitionA == 0) ? INT_MIN : nums1[partitionA - 1];
int minRightA = (partitionA == m) ? INT_MAX : nums1[partitionA];
int maxLeftB = (partitionB == 0) ? INT_MIN : nums2[partitionB - 1];
int minRightB = (partitionB == n) ? INT_MAX : nums2[partitionB];
if (maxLeftA <= minRightB && maxLeftB <= minRightA) {
if ((m + n) % 2 == 0) {
return (max(maxLeftA, maxLeftB) + min(minRightA, minRightB)) / 2.0;
} else {
return max(maxLeftA, maxLeftB);
}
} else if (maxLeftA > minRightB) {
right = partitionA - 1;
} else {
left = partitionA + 1;
}
}
return 0.0;
}
};
题意:给一个字符串,找回文串
我知道这是马拉车问题,但是我不记得马拉车的代码怎么写了;好像哈希也可以做这种题目,但是我能想到的哈希也是的
首先设回文串是单数,遍历一遍字符串,接着设回文串是双数,遍历一遍字符串,时间复杂度是
class Solution {
public:
string longestPalindrome(string s) {
string st="";
for(int i=0;i
查解析的时候看到又说区间动态规划做这道题的,动态规划已经完全不会了qwq
不过动态规划和我这个方法的时间复杂度居然差不多 哈哈
我看懂了!
首先每个字母是一个回文串,所以所有dp[0][i]=True,之后一个个排,差不多就是这意思,看代码肯定能看懂
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();
string ans="";ans+=s[0];
bool dp[1005][1005]={0};//字母最后一个的序号 里回文串长度(不包含最后一个字母的长度)
for(int i=0;i<1005;i++)dp[i][0]=1;
for(int i=1;i=0;j--){
if(s[i]==s[j]){
if(i-j==1||dp[i-1][i-j-2]){
dp[i][i-j]=1;
if((int)ans.size()
然后看到同样是O(n^2)的双指针法,但是不理解为什么能快那么多
同样是看了代码就知道怎么做的了
直接黏贴了别人的代码
class Solution {
public:
string longestPalindrome(string s) {
int lenLP=1;
int startLP=0;
int n=s.length();
for(int i=0;i=0 && rightlenLP){
lenLP=len;
startLP=left+1;
}
}
return s.substr(startLP,lenLP);
}
};
首先在首尾和每个数字之间添加”#“,例如”aofs“改成”“#a#o#f#s#”,这样解决了奇偶不同的问题,即字符串永远都是奇数,同时第0位,随便加上一个符号
p表示包括当前字符的 加入#后的 回文串半径,例如
# a # a # c # a # b # d # k # a # c # a # a #
1 2 3 2 1 4 1 2 1 2 1 2 1 2 1 2 1 4 1 2 3 2 1
pos和maxlen表示答案的中心和长度
id和mx表示最右边的回文串的中心和端点,注意:mx不包含在回文串中
遍历字符串 t 时,如果此时在最右回文串的外面(或者i=1时,mx=0),即 i>mx,那么p[i]=1
若 i 在最右边的已知回文串区域的右端点里面,说明这个回文串左边镜像字符 2*id-i 已经求过p[i]了
如果 p[2*id-i]+i 大于mx,即p[2*id-i]大于mx-i,就暂定p[i]=mx-i,因为超出回文串了
如果p[2*id-i]+i 小于mx,即p[2*id-i]小于mx-i,因为还在回文串里面,所以p[i]=p[2*id-i]
在 t[i+p[i]] == t[i-p[i]] 的基础上,向外扩展、更新p[i]
如果出现了新的最右字符串,那么更新id和mx
居然和上面的双指针时间差不多 哈哈
class Solution {
public:
string longestPalindrome(string s) {
string t = "$#";
for(auto i : s){
t += i;
t += "#";
}
vectorp(t.size(),1);//包括当前字符的 加入#后的 回文串半径
int pos = 0;
int maxlen = 0;
int id = 0;
int mx = 0;
for(int i=1;imx){//mx是最右边的已知回文串区域的右端点,不在回文串里面的第一个数字
mx = i+p[i];
id = i;//最右边的已知回文串中心
}
//记录最终的答案
if(p[i]>maxlen){
maxlen = p[i];
pos = i;
}
}
//(pos - maxlen)/2 长度
return s.substr( (pos - maxlen)/2,maxlen-1 );
}
};
题意:求min(h[l] , h[r])*(r - l)最大
双循环,O(n^2),但n=1e5 会超时,不会做不会做
参考:6.container-with-most-water(装最多水的容器
以序列最外面两条边形成的乘积为起始面积,找出两条边中较小的一条,索引加一(i++
),找出一条更大的边来代替较小的边,以使得整个容器最大(可以看参考链接的图,更易于理解)
class Solution {
public:
int maxArea(vector& h) {
int l=0,r=h.size()-1;
int maxx=0;
while(lh[r])r--;
else l++;
}
return maxx;
}
};
上述代码中还有可以优化的地方,因为当 l 或 r 更新时,一定要找到更大的h[ l ]或者h[ r ],否则对答案无影响
class Solution {
public:
int maxArea(vector& h) {
int l=0,r=h.size()-1;
int maxx=0,minh=9999999;
while(l
为什么可以连续的h[r]<=minh和h[l]<=minh?例如【8,88,8】答案为16,就算右边动了,变成了【8,16】,最小的高还是8,底宽还变小了,所以在底宽变小的前提下,一定要将minh提高才可以
题意:给一串字符串,写出代表的罗马数字
普通的模拟
改成if…else……可以从7ms进化成3ms
class Solution {
public:
int romanToInt(string s) {
int ans=0;
for(int i=0;i
题意:给出前缀组Str,找到最长的字符串前缀
用map把所有Str中的string的所有前缀都收集了,在收集过程中记录下最长的前缀
class Solution {
public:
string longestCommonPrefix(vector& strs) {
map mp;
int mx=0;string a="";string tmp="";
for(int i=0;imx){
mx=(int)tmp.size();a=tmp;
}
}
}
return a;
}
};
看公共前缀就把字符串组排序,看最后和最前的公共字符前缀即可
class Solution {
public:
string longestCommonPrefix(vector& strs) {
string tmp="";
sort(strs.begin(),strs.end());
int first=0,last=(int)strs.size()-1;
for(int i=0;i
题意:给定一串数组,输出三个数,使得三个数的和为0
O(n^2)组成pair组,存入pair的和,线性组,以后一一对照 总之全部用map实现
最后居然过了没想到的哈哈哈哈哈
class Solution {
public:
vector> threeSum(vector& nums) {
vector > pr[200005];int n=nums.size();map a;
set< vector> ans;vector> aa;
for(int i=0;i200000)continue;
pr[as+100000].push_back({i.first,j.first});
}
}//把所有的和都放好了
for(auto i:a){
int id=100000-i.first;
if(!pr[id].empty()){//如果有对应的
for(int j=0;j1
||i.first!=pr[id][j].first&&i.first==pr[id][j].second&&i.second>1
||i.first==pr[id][j].first&&i.first==pr[id][j].second&&i.second>2
){//如果三个数的序号不一样
vector a;a.push_back(i.first);
a.push_back(pr[id][j].first);a.push_back(pr[id][j].second);
sort(a.begin(),a.end());
ans.insert(a);
}
}
}
}
for (auto q:ans){aa.push_back(q);}
return aa;
}
};
首先将nums按大小排序,这样方便之后查找目标答案
顺序遍历nums,target就是-nums[i],设left是i+1,right是nums.size()-1,sum=nums[left] + nums[right]
如果sum
如果sum=target,那么刚好{nums[i], nums[left], nums[right]}加入vector中【还是排好序的】,因为适配的target的组合不止一个,所以移动left和right来跳过相同的数,之后接着查找,直到left>right停止
class Solution {
public:
vector> threeSum(vector& nums) {
vector> result;
int n = nums.size();// Sort the array to use two-pointer approach
sort(nums.begin(), nums.end());
for (int i=0; i0 && nums[i] == nums[i - 1]) {
continue; // Skip duplicates for the first element
}
int target = -nums[i];
int left = i + 1;
int right = n - 1;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum == target) {
result.push_back({nums[i], nums[left], nums[right]});
while (left < right && nums[left] == nums[left + 1])
left++; // Skip duplicates for the second element
left++;
while (left < right && nums[right] == nums[right - 1])
right--;
right--; // Skip duplicates for the third element
}
else if (sum < target) left++;
else right--;
}
}
return result;
}
};
直接死算(?),用map一个个放,最后输出符合个数的
class Solution {
public:
vector letterCombinations(string digits) {
vector result;
vector mp;
vector as={"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
int start=0,end=0;
for(int i=0;i
普通的循环:用两个vector交替,另外上面代码的-2好像不太行
class Solution {
public:
vector letterCombinations(string digits) {
if(digits.empty()) return{};
vector as={"", "", "abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
vector output={""};
for (auto st:digits){//输入
vector temp;
for(auto c: as[(st-'0')] ){//字母
for(auto t:output){
temp.push_back(t+c);
}
}
output.clear();
output=temp;
}
return output;
}
};
在主函数中,首先如果digit的长度为0,那就返回空;规定好mapping后进入递归函数
在递归函数中,跳出的条件是index大于digit的长度,ans把一次的outpu加入,退出递归;在递归中,首先是循环(表示这个按键可以是什么字母)进入递归(index+1),出递归后把这个字母弹出,进入下次循环装上下个可能的字母
class Solution {
public:
void solve(string &digits,vector &ans,string &output,int index,vector &mapping)
{
if(index>=(int)digits.size()){
ans.push_back(output);
return;
}
int id=digits[index]-'0';
for(int i=0;i<(int)mapping[id].size();i++){
output.push_back(mapping[id][i]);
solve(digits,ans,output,index+1,mapping);
output.pop_back();
}
}
vector letterCombinations(string digits) {
if(!(int)digits.size())return {};
int index=0;vector ans;
string output="";
vector mapping={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
solve(digits,ans,output,index,mapping);
return ans;
}
};