【持续更新中】
一些小细节or遗忘点or疑问的汇总
写写题让自己习惯写c++而不是以前那种按c的写法写c++
而且leetcode不用自己处理输入输出也不用本地运行意外的很爽(懒死我算了XD
目录
- 记忆点汇总
- 题目记录
- 1. Two Sum
- 2. Add Two Numbers
- 3. Longest Substring Without Repeating Characters
- 4. Median of Two Sorted Arrays
- 5. Longest Palindromic Substring ★
- 6. ZigZag Conversion
- 7. Reverse Integer
- 8. String to Integer (atoi)
- 9. Palindrome Number
- 10. Regular Expression Matching❓
- 11. Container With Most Water
- 12. Integer to Roman
- 13. Roman to Integer
记忆点汇总
指针
string
str.substr(st,len);
生成从st开始长度为len的s的子字符串
isspace(c)
isdigit(c)
STL
vector
动态数组
v.empty()
v为空返回true,否则返回false
v.size()
返回v中元素个数
v.push_back(t)
向v的末尾添加一个值为t的元素
v.pop_back()
删除v末尾的元素,如果v为空,行为未定义
v[n]
返回v中第n个位置上的元素的引用,位置n从0开始计
v.clear
清空向量中的元素
v1 = v2
赋值
v = {a,b,c,...}
替换
v1 == v2 v1 != v2
v1和v2相等当且仅当他们的元素数目相同且对应位置元素相同
<,<=,>,>=
以字典顺序进行比较
v.at(n) (cin>>v.at(0);)
返回v中第n个位置上的元素的引用,下标越界抛出异常
迭代器
vector<int>::iterator it;
for(it=a.begin();it!=a.end();it++)
cout<<*it<<" ";
其他
a.insert(a.begin(), 10) ; //将10插入到向量a的起始位置前
a.insert(a.begin(), 3, 10); //将10分别插入到向量a的0-2处
b.insert(b.begin(), a.begin(), a.end()); //将a插入到b.begin前
a.erase(a.begin()); //将起始位置的元素删除
a.erase(a.begin(), a.begin() + 3); //将a的0-3处元素删除
a.swap(b); //将向量a与向量b交换
map
map与unordered_map区别及使用
map - 红黑树
unordered_map - 哈希表
题目记录
1. Two Sum
数组中找两个数使其和为target的值。本来的思路是排序后从前后往中间找,结果发现排序后下标就变了没法返回正确的下标(如果是自己处理输入的话会考虑用结构体标记数的初始位置),所以索性就暴力了(反正没超时就行XD
//#include<algorithm>
using std::cout;
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
/* 排序后从两边到中间遍历的代码
std::sort(nums.begin(),nums.end());
int i=0,j=nums.size()-1;
while(i<j){
if(nums[i]+nums[j]==target)break;
if(nums[i]+nums[j]>target){cout<<0;
j--;
}
else i++;
}
vector<int> ans;
ans.push_back(i);
ans.push_back(j);
return ans;*/
int i,j,flag=0;
vector<int> ans;
for(i=0;i<nums.size();i++){
for(j=i+1;j<nums.size();j++){
if(nums[i]+nums[j]==target){
flag=1;break;
}
}if(flag==1)break;
}
ans.push_back(i);
ans.push_back(j);
return ans;
}
};
提一嘴备注掉的代码,省得以后忘了,可以理解成在坐标轴给定点中找 两点构成的线段中点的值*2==target 的线段 ,所以寻找过程中当值比目标值大or小的时候只要往中间移动其中一端就可以了
2. Add Two Numbers
链表加法,和以前写过的一题不同的是这次用链表表示的数是 个位->十位->百位
这样加法进位处理起来就很轻松。我这里直接把加完的结果更新到第一个链表中,没有开新的
指针练的少,写的时候老容易分不清然后出语法错误…
出现的问题:更高位接上去出现数组越界,还是看到题解里Java代码用new才想起来cpp也有这个东西XD
/**
* 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) {
int an=0,m=0;
ListNode *a=l1,*b=l2;
while(1){
an=a->val+b->val+m;
m=an/10;
an=an%10;
a->val=an;
if(a->next!=NULL && b->next!=NULL){
a=a->next;b=b->next;
}
else break;
}
if(b->next!=NULL){
a->next=b->next;
}
while(m!=0){
if(a->next!=NULL){
a=a->next;
an=a->val+m;
m=an/10;
an=an%10;
a->val=an;
}
else{
// ListNode aa(m%10);直接赋值会越界
a->next=new ListNode(m%10); //new一个新的
a=a->next;
m=m/10;
}
}
return l1;
}
};
3. Longest Substring Without Repeating Characters
字符串中最长无重复字符子串
我用的方法是标记子串中出现过的字符,依次以主串中的每个字符作为子串首字符进行遍历
wa点:本题字符包括所有字母数字符号空格,即ASCII表中32~126全包括在内
疑问:memset对数组进行初始化时数组长度不用sizeof(flag)
会出问题,无法全部置0,为什么?
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int flag[100],maxx=0,m=0;
memset(flag,0,sizeof(flag)); //为什么写100没法全置零,用sizeof(flag)可以??
for(int i=0;i<s.length();i++){
int j=i;
while(s[j]>=' '){
if(flag[s[j]-' ']!=0){
if(m>maxx) maxx=m;
m=0;
memset(flag,0,sizeof(flag));
break;
}
else{
flag[s[j]-' ']=1;
m++;
j++;
}
}
if(m>maxx) maxx=m;
if(s.length()-i<maxx) break;
}
return maxx;
}
};
4. Median of Two Sorted Arrays
求两个增序数组的中位数,看到hard做好了卡题准备,结果一写,就这??就这????
一发过,解法也没啥好说的…完全不能理解hard在哪…
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int n=nums1.size(),m=nums2.size();
int flag=(m+n)/2,t=0,i=0,j=0;
double a=0.0,b=0.0;
while(t<=flag){
if(i<n&&j<m){
if(nums1[i]<nums2[j]){
b=nums1[i];
i++;
}
else{
b=nums2[j];
j++;
}
}
else if(i<n){
b=nums1[i];i++;
}
else if(j<m){
b=nums2[j];j++;
}
if(t==flag-1) a=b;
t++;
}
if((m+n)%2==0) return (a+b)/2;
else return b;
}
};
5. Longest Palindromic Substring ★
这题就比较有意思了,求字符串最长回文子串
- 动规
子串长度为1,一定是回文串;长度为2,若两个字符相等为回文串;
对于一个长度大于2的回文子串,去掉首位字符后依旧是回文子串,即若回文串两端新增的字符相等则新的字符串依旧是回文串 - 中心扩散
所有状态在转移的时候的可能性都是唯一的。即从所有边界情况(子串长度为1或2)开始扩展也能得到所有状态对应的答案
枚举边界情况并从边界子串向两端扩展,两边字母相同继续扩展;字母不同停止扩展并进入下一种边界情况 - Manacher算法O(n)
基于动规+中心扩散的优化算法,真的很巧妙
首先在字符串中间隔插入特殊字符使所有回文串情况转化为单数形
(插入字符后的回文子串长度-1)/2 = 原始回文子串长度 = 以 i 为中心能扩散的步数
用p[i]存储以i点为中心的最大扩散长度分四种情况:
(1)i >= maxRight
用中心扩散向两边匹配
因为此时 i 没有被包含在以center为对称中心的回文串内,无法利用回文串的对称性
(2)i < maxRight
这里考虑以对称点mirror为中心的最长回文串的长度,包含三种情况:
······1.p[mirror] < maxRight - i
时,p[i] = p[mirror]
······2.p[mirror] == maxRight - i
时,p[i] >= maxRight-1
需扩散求值
······3.p[mirror] > maxRight - i
时,p[i] = maxRight - i
这三种情况综合可得p[i] = min( p[mirror] , maxRight - i )
,并尝试中心扩散
按Manacher写:
class Solution {
public:
int expend(string &s, int left, int right){
while(left>=0&&right<s.length()&&s[left]==s[right]){
left--;right++;
}
return (right-left-2)/2;
}
string longestPalindrome(string s) {
string t="#";
for(char c:s){
t+=c;
t+='#';
}
t+='#';s=t;
vector<int> p;
int st=0,ed=-1,cen=0,right=0;
for(int i=0;i<s.length();i++){
int x;
if(i>=right){
x=expend(s,i,i);
}
else{
x=min(p[2*cen-i],right - i);
x=expend(s,i-x,i+x);
}
p.push_back(x);
if(i+x>right){
right=i+x;
cen=i;
}
if(x*2+1>ed-st){
st=i-x;
ed=i+x;
}
}
t.clear();
for(int i=st;i<=ed;i++){
if(s[i]!='#'){
t+=s[i];
}
}
return t;
}
};
这两次提交之间我只是把expend(string s, int left, int right)
改成了引用expend(string &s, int left, int right)
。好家伙,我快乐了
6. ZigZag Conversion
就,找下标规律,按行取数
class Solution {
public:
string convert(string s, int numRows) {
string ans;
int len=s.length();
int mid=numRows*2-2;
if(numRows==1) return s;
for(int j=0;j<numRows;j++){
for(int i=0;i<len;i+=mid){
if(i+j<len) ans+=s[i+j];
if(i+mid-j<len&&j!=0&&j!=numRows-1) ans+=s[i+mid-j];
}
}
return ans;
}
};
7. Reverse Integer
注意判断溢出
class Solution {
public:
int reverse(int x) {
int a=0;
while(x){
int mid=x%10;
if(a>INT_MAX/10||(a==INT_MAX/10&&mid>7)) return 0;
if(a<INT_MIN/10||(a==INT_MIN/10&&mid<-8))return 0;
a=a*10+mid; x=x/10;
}
return a;
}
};
8. String to Integer (atoi)
最开始题目审错了wa了几次。其实就是顺序的状态转变
普通解法:
class Solution {
public:
int myAtoi(string s) {
int ans=0,flag=1,i=0;
while(s[i]==' '&&i<s.length())i++;
if(s[i]=='-'){flag=-1;i++;}
else if(s[i]=='+'){
i++;
}
while(s[i]=='0') i++;
while(i<s.length()){
int mid=s[i]-'0';
if(mid<0||mid>9) break;
if(ans==0&&s[i]=='0') {i++;continue;}
mid=mid*flag;
if(ans>INT_MAX/10||(ans==INT_MAX/10&&mid>=7)) return INT_MAX;
if(ans<INT_MIN/10||(ans==INT_MIN/10&&mid<=-8))return INT_MIN;
ans=ans*10+mid;
i++;
}
return ans;
}
};
DFA(有穷自动机:
class Automaton{
string state="st";
unordered_map<string,vector<string>> table={
{"st",{"st","sign","num","ed"}},
{"sign",{"ed","ed","num","ed"}},
{"num",{"ed","ed","num","ed"}},
{"ed",{"ed","ed","ed","ed"}}
};
int flag_c(char c){
if (isspace(c)) return 0; //空格
if (c=='+'||c=='-') return 1;
if (isdigit(c)) return 2; //数字
return 3;
}
public:
int sign=1;
long long ans=0;
void get(char c){
state = table[state][flag_c(c)];
if(state=="sign"){
sign=(c=='+'?1:-1);
}
else if(state=="num"){
ans=ans*10+(c-'0');
ans=(sign==1?min(ans,(long long)INT_MAX):min(ans,-(long long)INT_MIN));
}
}
};
class Solution {
public:
int myAtoi(string s) {
Automaton autom;
for(char c:s){
autom.get(c);
}
return autom.ans*autom.sign;
}
};
单就这题而言自动机似乎没普通解法优
9. Palindrome Number
class Solution {
public:
bool isPalindrome(int x) {
if(x<0) return false;
long long bef=x,aft=0;
while(x){
aft=aft*10+x%10;
x=x/10;
}
if(bef==aft)return true;
else return false;
}
};
//从结果上来看下面这个优化了时间
class Solution {
public:
bool isPalindrome(int x) {
if(x<0||x%10==0&&x!=0) return false;
if(x>=0&&x<10) return true;
int aft=0;
bool flag;
while(x){
aft=aft*10+x%10;
x=x/10;
if(aft>=x){
if(aft==x) flag=true;
else if(aft>=10&&aft/10==x) flag=true;
else flag=false;
break;
}
}
return flag;
}
};
10. Regular Expression Matching❓
题解
动规,思路算是看懂了…但是代码里还有些疑问
class Solution {
public:
bool isMatch(string s, string p) {
int slen=s.length();
int plen=p.length();
auto matche = [&](int i,int j){
if(i==0) return false;
if(p[j-1]=='.')return true;
return s[i-1]==p[j-1];
}; //auto matche = [&](int a,int b){...};没懂,这算函数吗?还是定义?
vector<vector<int>> f(slen+1,vector<int>(plen+1));
f[0][0]=true;
for(int i=0;i<=slen;i++){
for(int j=1;j<=plen;j++){
if(p[j-1]=='*'){
f[i][j]|=f[i][j-2]; //按位与?
if(matche(i,j-1)){
f[i][j]|=f[i-1][j];
}
}
else{
if(matche(i,j)) f[i][j]|=f[i-1][j-1];
}
}
}
return f[slen][plen];
}
};
11. Container With Most Water
两边往中间找最优解
class Solution {
public:
int maxArea(vector<int>& height) {
int nowl=0,nowr=height.size()-1;
int maxx=0;
while(nowr>nowl){
int nm=(nowr-nowl)*min(height[nowr],height[nowl]);
maxx=max(maxx,nm);
if(height[nowr]<height[nowl]){
nowr--;
}
else{
nowl++;
}
}
return maxx;
}
};
12. Integer to Roman
这个是贪心。不过直接分类比较速度和内存都更优,但代码会比较长
class Solution {
public:
string intToRoman(int num) {
vector<int> value={1000,900,500,400,100,90,50,40,10,9,5,4,1};
vector<string> symbol={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
string ans;
int i=0;
while(num){
while(num>=value[i]){
ans=ans+symbol[i];
num=num-value[i];
}
i++;
}
return ans;
}
};
直接暴力分类的:(缺点就是代码长XD
class Solution {
public:
string Roman(int flag,int x){
string s;
if(flag==1){
if(x==4) s="IV";
else if(x==9) s="IX";
else if(x>=5){
s="V";
x=x-5;
while(x--)s=s+"I";
}
else{
while(x--)s=s+"I";
}
}
else if(flag==2){
if(x==4) s="XL";
else if(x==9) s="XC";
else if(x>=5){
s="L";
x=x-5;
while(x--)s=s+"X";
}
else{
while(x--)s=s+"X";
}
}
else if(flag==3){
if(x==4) s="CD";
else if(x==9) s="CM";
else if(x>=5){
s="D";
x=x-5;
while(x--)s=s+"C";
}
else{
while(x--)s=s+"C";
}
}
else if(flag==4){
while(x--)s=s+"M";
}
return s;
}
string intToRoman(int num) {
string ans;
int flag=0,x;
while(num){
x=num%10;
num=num/10;
flag++;
string st;
st=Roman(flag,x);
ans=st+ans;
}
return ans;
}
};
13. Roman to Integer
小值右边有大值用减,没大值用加
class Solution {
public:
int getValue(char c){
int num=0;
if(c=='M') num=1000;
else if(c=='D') num=500;
else if(c=='C') num=100;
else if(c=='L') num=50;
else if(c=='X') num=10;
else if(c=='V') num=5;
else if(c=='I') num=1;
return num;
}
int romanToInt(string s) {
int ans=0;
int i=0,len=s.length();
for(i=0;i<len;i++){
int flag=1;
if(getValue(s[i])<getValue(s[i+1])) flag=-1;
ans+=flag*getValue(s[i]);
}
return ans;
}
};