一.简单题
1.两数之和
(1)暴力求解
int* twoSum(int* nums, int numsSize, int target, int* returnSize)
{
int i=0,j=0;
for(i=0;i<numsSize-1;i++)
{
for(j=i+1;j<numsSize;j++)
{
if(nums[i]+nums[j]==target)
{
int* ret=malloc(sizeof(int)*2);
//题目要求返回类型为int*,考虑返回指向数组的指针
ret[0]=i;
ret[1]=j;
*returnSize=2;
return ret;
}
}
}
*returnSize=0;
return NULL;
}
(2)哈希表
2.回文数
bool isPalindrome(int x)
{
if(x<0)
return false;
char arr[20],brr[20];
itoa(x, arr);
char i = 0,tmp=0;
int m = strlen(arr);
strcpy( brr, arr );
for (i = 0; i <=(m - 1)/2; i++)
{
tmp = arr[i];
arr[i] = arr[m - 1 - i];
arr[strlen(arr) - 1 - i] = tmp;
}
int f=strcmp( arr, brr );
if(f==0)
return true;
else
return false;
}
3.罗马数字转整数
int romanToInt(char* s)
{
int n=strlen(s);
int i=0;
int sum=0;
for(i=0;i<n;i++)
{
switch(s[i])
{
case 'M':
sum=sum+1000;
break;
case 'D':
sum=sum+500;
break;
case 'C':
if(s[i+1]=='D')
{
sum=sum+400;
i++;
}
else if(s[i+1]=='M')
{
sum=sum+900;
i++;
}
else
{
sum=sum+100;
}
break;
case 'L':
sum=sum+50;
break;
case 'X':
if(s[i+1]=='L')
{
sum=sum+40;
i++;
}
else if(s[i+1]=='C')
{
sum=sum+90;
i++;
}
else
{
sum=sum+10;
}
break;
case 'V':
sum=sum+5;
break;
case 'I':
if(s[i+1]=='V')
{
sum=sum+4;
i++;
}
else if(s[i+1]=='X')
{
sum=sum+9;
i++;
}
else
{
sum=sum+1;
}
break;
default:
break;
}
}
return sum;
}
4.
5. 有效括号
bool isValid(char * s)
{
ST st;
StackInit(&st);
while(*s)
{
if(*s=='('||*s=='['||*s=='{')
{
StackPush(&st,*s);//入栈,栈里不存右括号
s++;
}
else
{
//遇到右括号了,但是栈里面没有数据,说明前面没有左括号,也要返回flase
if(StackEmpty(&st))
{
StackDestroy(&st);
return false;
}
STDataType top=StackTop(&st);
StackPop(&st);
if((*s==')'&&top!='(')||(*s==']'&&top!='[')||(*s=='}'&&top!='{'))
{
StackDestroy(&st); //不销毁会导致内存泄漏
return false;
}
else
{
s++;
}
}
}
//只要栈不是空,就说明里面还有还有左括号没有被匹配
bool ret=StackEmpty(&st);
StackDestroy(&st); //不销毁会导致内存泄漏
return ret;
}
.相同的树
bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
if(p==NULL && q==NULL)
return true;
if(p==NULL || q==NULL) //这里不能用异或,因为异或是个值运算
return false;
if(p->val != q->val)
return false;
return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}
经典的前序:先判断根,再是左子树,右子树
.杨辉三角
class Solution
{
public:
vector<vector<int>> generate(int numRows)
{
vector<vector<int>> vv;
vv.resize(numRows,vector<int>()); //vector<int>()是用匿名对象来初始化
for(size_t i=0;i<vv.size();i++)
{
vv[i].resize(i+1,0); //都初始化为0
vv[i][0]=vv[i][vv[i].size()-1]=1; //每一行的第一个和最后一个都初始化为1
}
for(size_t i=0;i<vv.size();i++)
{
for(size_t j=0;j<vv[i].size();j++)
{
if(vv[i][j]==0)
{
vv[i][j]=vv[i-1][j-1]+vv[i-1][j];
}
}
}
return vv;
}
};
vector的嵌套
.反转链表
struct ListNode* reverseList(struct ListNode* head)
{
if(head==NULL)
{
return head;
}
struct ListNode *n1,*n2,*n3;
n1=NULL;
n2=head;
n3=head->next;
while(n2)
{
n2->next=n1; //翻转指针
n1=n2; //让n1==n2
n2=n3; //让n2==n3
if(n3)
{
n3=n3->next;
}
}
return n1;
}
运用三指针的方法,关键是画图
.链表的中间结点
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode *fast,*slow;
fast=head;
slow=head;
while(fast!=NULL&&fast->next!=NULL)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
运用快慢指针,快指针比慢指针多走一步,最终slow会在head和fast的中间位置
拓展:找倒数第k个结点
struct ListNode* FindNode(struct ListNode* head,int k)
{
struct ListNode *fast,*slow;
fast=head;
slow=head;
int i=0;
for(i=0;i<k;i++)
{
if(fast==NULL) //K大于链表长度,提前结束
{
return NULL;
}
fast=fast->next;
}
while(fast)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
也是用快慢指针,不过是fast先走k步;
之后slow与fast一起走,当fast==NULL时,slow指向的是倒数第k个
.合并两个有序链表
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2)
{
if(l1==NULL)
{
return l2;
}
if(l2==NULL)
{
return l1;
}
//如果其中一个链表为空,返回另一个链表
struct ListNode *head,*tail;
head=NULL;
tail=NULL;
while(l1&&l2)
{
if(l1->val<l2->val)
{
if(head==NULL) //第一次的判断
{
head=l1;
tail=l1;
}
else
{
tail->next=l1;
tail=l1;
}
l1=l1->next;
}
else
{
if(head==NULL) //第一次的判断
{
head=l2;
tail=l2;
}
else
{
tail->next=l2;
tail=l2;
}
l2=l2->next;
}
}
//连接剩下的
if(l1)
{
tail->next=l1;
}
if(l2)
{
tail->next=l2;
}
return head;
}
依次比较链表结点,每次取小的结点,尾插到新的链表即可
. 回文链表
bool isPalindrome(struct ListNode* head)
{
struct ListNode* mid=middleNode(head);
struct ListNode* rhead=reverseList(mid);
struct ListNode* cur1=head; //尽量不要乱动头指针
struct ListNode* cur2=rhead;
while(cur1&&cur2)
{
if(cur1->val!=cur2->val)
{
return false;
}
else
{
cur1=cur1->next;
cur2=cur2->next;
}
}
return true;
}
先找到中间结点,然后逆置后面的链表,之后再和前面的链表比较。
.相交链表
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
struct ListNode* tail1=headA;
struct ListNode* tail2=headB;
int len1=1,len2=1; //因为没有把尾算进去,所以初始为一比较好
while(tail1->next!=NULL)
{
len1++;
tail1=tail1->next;
}
while(tail2->next!=NULL)
{
len2++;
tail2=tail2->next;
}
if(tail1!=tail2) //最好用地址去比较,用值可能会误判
{
return NULL; //不相交
}
int gap=abs(len1-len2);
struct ListNode* longlist=headA;
struct ListNode* shortlist=headB;
if(len1<len2) //先假设a长,要是a短的话再交换过来
{
longlist=headB;
shortlist=headA;
}
while(gap--) //长的先走,和短的齐平
{
longlist=longlist->next;
}
while(longlist!=shortlist)
{
longlist=longlist->next;
shortlist=shortlist->next;
}
return longlist;
}
.环形链表
bool hasCycle(struct ListNode *head)
{
struct ListNode* fast=head;
struct ListNode* slow=head;
struct ListNode* A=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast) //当相遇时
{
struct ListNode* meet=slow;
while(A!=meet)
{
A=A->next;
meet=meet->next;
}
return meet;
}
}
return NULL;
}
使用快慢指针,快比慢多一步
根据图和公式分析,结论是L==从meet到环入口的距离
法2:
还可以成链表相交求交点
list1:从head到meet (让meet做两个链表的尾巴)
list2:从meet前一个到meet
.用队列实现栈
typedef struct
{
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate()
{
MyStack* st =(MyStack*)malloc(sizeof(MyStack));
QueueInit(&st->q1);
QueueInit(&st->q2);
return st;
}
void myStackPush(MyStack* obj, int x)
{
if(!QueueEmpty(&obj->q1)) //->已经解引用过一次了,所以还是要加&
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj) {
assert(obj);
//我们需要判断那个队列是空,则将另一个队列的前n-1个数据进行出队到空队列
Queue* emptyQ = &obj->q1;
Queue* noemptyQ = &obj->q2;
if(!QueueEmpty(&obj->q1))
{
emptyQ = &obj->q2;
noemptyQ = &obj->q1;
}
// 把非空队列的前N个数据,导入空队列,剩下一个删掉
// 就实现了后进先出
while(QueueSize(noemptyQ)>1)
{
int front =QueueFront(noemptyQ);
QueuePush(emptyQ,front);
QueuePop(noemptyQ);
}
int top=QueueFront(noemptyQ); //先保存一下,不然被pop掉找不到数据了
QueuePop(noemptyQ);
return top;
}
int myStackTop(MyStack* obj)
{
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj)
{
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2); //都不为空才行
}
void myStackFree(MyStack* obj)
{
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
obj==NULL;
}
核心思路:
1.入数据,往不为空的队列里入数据,保持另外一个队列为空
2.出数据,把前n-1个数据转移到另外一个队列里存起来,把最后一个数据出出去
.用栈实现队列
typedef struct
{
ST pushST;
ST popST;
} MyQueue;
MyQueue* myQueueCreate()
{
MyQueue* q=(MyQueue*)malloc(sizeof(MyQueue));
StackInit(&q->pushST);
StackInit(&q->popST);
return q;
}
void myQueuePush(MyQueue* obj, int x)
{
StackPush(&obj->pushST,x);
}
int myQueuePop(MyQueue* obj)
{
if(StackEmpty(&obj->popST))
{
while(!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST,StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
int front=StackTop(&obj->popST);
StackPop(&obj->popST);
return front;
}
int myQueuePeek(MyQueue* obj)
{
if(StackEmpty(&obj->popST))
{
while(!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST,StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
return StackTop(&obj->popST);
}
bool myQueueEmpty(MyQueue* obj)
{
return StackEmpty(&obj->pushST) && StackEmpty(&obj->popST);
}
void myQueueFree(MyQueue* obj)
{
StackDestroy(&obj->pushST);
StackDestroy(&obj->popST);
free(obj); //不要忘了把MyQueue释放掉
obj==NULL;
}
.单值二叉树
bool isUnivalTree(struct TreeNode* root)
{
if(root==NULL)
{
return true;
}
if(root->left && root->left->val!=root->val) //跟左子树比较
{
return false;
}
if(root->right && root->right->val!=root->val) //跟右子树比较
{
return false;
}
return isUnivalTree(root->left) && isUnivalTree(root->right);
//不能是
return isUnivalTree(root->left);
return isUnivalTree(root->right);
}
每次递归都是比较孩子(子树)与父亲,只要不是单值二叉树,肯定在某个地方孩子与父亲不相等
.对称二叉树
bool _isSymmetric(struct TreeNode* leftRoot,struct TreeNode* rightRoot)
{
if(leftRoot==NULL && rightRoot==NULL)
{
return true;
}
if(leftRoot==NULL || rightRoot==NULL)
{
return false;
}
if(leftRoot->val != rightRoot->val)
{
return false; //最好写题意不满足的条件
}
return _isSymmetric(leftRoot->left,rightRoot->right)
&& _isSymmetric(leftRoot->right,rightRoot->left);
}
bool isSymmetric(struct TreeNode* root)
{
return _isSymmetric(root->left,root->right); //当给的函数不合适的时候,可以自己再编一个
}
.二叉树的前序遍历
int TreeSize(struct TreeNode* root)
{
return (root==NULL) ? 0 : TreeSize(root->left)+TreeSize(root->right)+1;
}
void _preorder(struct TreeNode* root,int* a,int *i) //递归中传数值,基本都是传址
{
if(root==NULL)
return ;
a[(*i)++]=root->val;
_preorder(root->left,a,i);
_preorder(root->right,a,i);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
*returnSize=TreeSize(root);
int *a=(int*)malloc((*returnSize)*sizeof(int));
int i=0;
_preorder(root,a,&i); //要保证每个栈帧都只有一个i
return a;
}
.两个数组的交集
class Solution
{
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2)
{
//排序+去重
set<int> s1(nums1.begin(),nums1.end());
set<int> s2(nums2.begin(),nums2.end());
auto it1=s1.begin();
auto it2=s2.begin();
vector<int> v;
while(it1!=s1.end()&& it2!=s2.end())
{
if(*it1<*it2)
{
++it1;
}
else if(*it1>*it2)
{
++it2;
}
else
{
v.push_back(*it1);
++it1;
++it2;
}
}
return v;
}
};
.字符串中的第一个唯一字符
387. 字符串中的第一个唯一字符 - 力扣(LeetCode)
class Solution
{
public:
int firstUniqChar(string s)
{
//用计数来统计次数
int count[26]={0};
for(auto ch:s)
{
count[ch-'a']++;
}
for(int i=0;i<s.size();++i)
{
if(count[s[i]-'a']==1)
{
return i;
}
}
return -1;
}
};
.字符串相加
class Solution
{
public:
string addStrings(string num1, string num2)
{
int end1=num1.size()-1,end2=num2.size()-1;
int next=0;
string str;
while(end1>=0||end2>=0)
{
int val1=0;
if(end1>=0)
{
val1=num1[end1]-'0';
}
int val2=0;
if(end2>=0)
{
val2=num2[end2]-'0';
}
int ret=val1+val2+next;
if(ret>9)
{
ret -= 10;
next=1;
}
else
{
next=0;
}
str.insert(0,1,'0'+ret);
--end1;
--end2;
}
if(next==1)
{
str.insert(0,1,'0'+1);
}
return str;
}
};
//可以用来处理大数相加
.另一颗树的子树
bool isSameTree(struct TreeNode* p, struct TreeNode* q) //第100题的函数
{
if(p==NULL && q==NULL)
return true;
if(p==NULL || q==NULL)
return false;
if(p->val != q->val)
return false;
return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{
if(root==NULL)
{
return false;
}
if(isSameTree(root,subRoot))
{
return true;
}
return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
//return isSameTree(root->left,subRoot) || isSameTree(root->right,subRoot) 是错的
}
.根据二叉树创建字符串
606. 根据二叉树创建字符串 - 力扣(LeetCode)
class Solution
{
public:
string tree2str(TreeNode* root)
{
if(root==nullptr)
return "";
string str = to_string(root->val); //转成字符串类型
if(root->left!=nullptr||root->right!=nullptr)
{
str += '(';
str += tree2str(root->left);
str += ')';
}
if(root->right!=nullptr) //判断右边省不省略
{
str += '(';
str += tree2str(root->right);
str += ')';
}
return str;
}
};
.仅仅反转字母
bool isletter(char a)
{
if((a>='a'&&a<='z')||(a>='A'&&a<='Z'))
{
return true;
}
return false;
}
class Solution
{
public:
string reverseOnlyLetters(string s)
{
size_t begin=0;
size_t end=s.size()-1;
while(begin<end)
{
while(begin<end&&!isletter(s[begin]))
begin++;
while(begin<end&&!isletter(s[end]))
end--;
swap(s[begin],s[end]);
begin++;
end--;
}
return s;
}
};
二.中等题
1.整数反转
int reverse(int x)
{
int m=0;
long int sum=0;
int flag=0;
if(x<0)
{
if(x==-2147483648)
{
return 0;
}
else
{
x=-x;
flag=1;
}
}
while(x)
{
m=x%10;
sum=sum*10+m;
x=x/10;
}
if(sum>=2147483648||sum<=-2147483648)
{
return 0;
}
if(flag==1)
{
sum=-sum;
}
return sum;
}
2.链表分割(牛客网)
typedef struct ListNode
{
int val;
struct ListNode* next;
}ListNode;
ListNode* partition(ListNode* pHead, int x)
{
struct ListNode* A_head, * A_tail, * B_head, * B_tail;
//开一个哨兵卫的头结点,方便之后的分别尾插
A_head = A_tail = (struct ListNode*)malloc(sizeof(struct ListNode));
A_tail = NULL;
B_head = B_tail = (struct ListNode*)malloc(sizeof(struct ListNode));
B_tail = NULL;
ListNode* cur = pHead;
while (cur)
{
if (cur->val < x)
{
A_tail->next = cur; //A_tail的下一个指向cur
A_tail = cur;
}
else
{
B_tail->next = cur; //A_tail的下一个指向cur
B_tail = cur;
}
cur = cur->next; //因为cur没有被改变,所以依然可以继续往下走
}
A_tail->next = B_head->next;
B_tail = NULL; // 要把b_tail指向空,不然有可能B的最后一个还连着A的下一个呢
ListNode* head=A_head->next;
//不要忘了释放内存
free(A_head);
free(B_head);
return A_head->next;
}
(这是死循环了)
.电话号码的字母组合
class Solution
{
string _numToStr[10]={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
public:
void Combinations(const string& digits,size_t di,string conbineStr,vector<string>& strV)
//这里用传值是为了往下调用的时候不影响上面的数字
{
if(di==digits.size())
{
strV.push_back(conbineStr);
return;
}
int num=digits[di]-'0';
string str=_numToStr[num];
for(auto ch:str)
{
Combinations(digits,di+1,conbineStr+ch,strV);
//这里不能是 di++和conbineStr += ch 因为会改变di和conbineStr
}
}
vector<string> letterCombinations(string digits)
{
vector<string> strV;
if(digits.size()==0)
{
return strV;
}
Combinations(digits,0,"",strV);
return strV;
}
};
.二叉树的层序遍历
class Solution
{
public:
vector<vector<int>> levelOrder(TreeNode* root)
{
queue<TreeNode*> q;
int levelsize=0;
if(root) //初始化队列
{
q.push(root);
levelsize=1;
}
vector<vector<int>> vv;
while(!q.empty())
{
//通过levelsize控制一层一层的出
vector<int> v;
while(levelsize--)
{
TreeNode* front=q.front(); //先把要出的保存起来
q.pop();
v.push_back(front->val);
//上一层出完,带出下一层
if(front->left)
q.push(front->left);
if(front->right)
q.push(front->right);
}
vv.push_back(v);
levelsize=q.size(); //更新下一层数据
}
return vv;
}
};
.从前序与中序遍历构造二叉树
105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
class Solution
{
public:
TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder,int& peri,int inbegin,int inend)
{
if(inbegin>inend)
{
return nullptr;
}
TreeNode* root=new TreeNode(preorder[peri]); //用前序找根
//分割出左右子区间
//[inbegin,rooti-1],rooti,[rooti+1,inend] 分割成三段区间
int rooti=inbegin; //rooti是根在中序序列中的下标
while(rooti<=inend)
{
if(inorder[rooti]==preorder[peri])
{
break; //找到了rooti
}
else
{
rooti++;
}
}
++peri;
root->left=_buildTree(preorder,inorder,peri,inbegin,rooti-1); //(用左子树区间)递归创建左子树
root->right=_buildTree(preorder,inorder,peri,rooti+1,inend);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
{
int i=0;
return _buildTree(preorder,inorder,i,0,inorder.size()-1);
}
};
.二叉树的层序遍历Ⅱ
107. 二叉树的层序遍历 II - 力扣(LeetCode)
class Solution
{
public:
vector<vector<int>> levelOrderBottom(TreeNode* root)
{
queue<TreeNode*> q;
int levelsize=0;
if(root) //初始化队列
{
q.push(root);
levelsize=1;
}
vector<vector<int>> vv;
while(!q.empty())
{
//通过levelsize控制一层一层的出
vector<int> v;
while(levelsize--)
{
TreeNode* front=q.front(); //先把要出的保存起来
q.pop();
v.push_back(front->val);
//上一层出完,带出下一层
if(front->left)
q.push(front->left);
if(front->right)
q.push(front->right);
}
vv.push_back(v);
levelsize=q.size(); //更新下一层数据
}
reverse(vv.begin(),vv.end()); //比102多一句代码
return vv;
}
};
关键就是这一句 reverse(vv.begin(),vv.end()),注意reverse值逆置了一维的数组,所以可以这样用
3.复制带随机指针的链表
138. 复制带随机指针的链表 - 力扣(LeetCode)
struct Node* copyRandomList(struct Node* head)
{
//1.拷贝结点,插入原节点的后面
struct Node* cur=head;
while(cur)
{
struct Node* copy=(struct Node*)malloc(sizeof(struct Node));
copy->val=cur->val;
//插入copy节点
copy->next=cur->next;
cur->next=copy;
cur=copy->next; //cur移动到下一个原节点
}
//2.根据原节点,处理copy节点的random
cur=head;
while(cur)
{
struct Node* copy=cur->next;
if(cur->random==NULL)
{
copy->random=NULL;
}
else
{
copy->random=cur->random->next;
}
cur=copy->next;
}
//3.取出复制的链表出来
cur=head;
struct Node* copyhead=NULL;
struct Node* copytail=NULL;
while(cur)
{
struct Node* copy=cur->next;
struct Node* next=copy->next;
if(copytail==NULL)
{
copyhead=copytail=copy;
}
else
{
copytail->next=copy;
copytail=copy;
}
cur->next=next; //恢复原链表
cur=next;
}
return copyhead; //别忘了返回
}
最重要的还是画图
.逆波兰表达式求值
class Solution
{
public:
int evalRPN(vector<string>& tokens)
{
stack<int> st;
for(auto& str:tokens) //一个一个取字符串时,数据量一般比较大,所以加&,不加也不会报错
{
if(str=="+"||str=="-"||str=="*"||str=="/")
{
int right=st.top();
st.pop();
int letf=st.top();
st.pop();
switch(str[0])
{
case '+':
st.push(left+right);
break;
case '-':
st.push(left-right);
break;
case '*':
st.push(left*right);
break;
case '/':
st.push(left/right);
break;
}
}
else
{
st.push(stoi(str)); //先把字符串转整型,在入栈
}
}
}
};
中缀表达式转后缀表达式:
对于括号: 可以定义一个flag,当遇到 “(” 时,把flag=1,这时候括号里的运算符全是最高级,当遇到“)” 时,把flag变回。
.最小栈
class MinStack
{
public:
MinStack()
{
}
void push(int val)
{
_st.push(val);
if(_minst.empty()||val<=_minst.top())
{
_minst.push(val);
}
}
void pop()
{
if(_minst.top()==_st.top())
{
_minst.pop();
}
_st.pop();
}
int top()
{
return _st.top();
}
int getMin()
{
return _minst.top();
}
private:
stack<int> _st;
stack<int> _minst;
};
.215数组中的第K个最大元素
215. 数组中的第K个最大元素 - 力扣(LeetCode)
class Solution
{
public:
int findKthLargest(vector<int>& nums, int k)
{
priority_queue<int> pq(nums.begin(),nums.end()); //用迭代器区间构造
while(--k)
{
pq.pop();
}
return pq.top();
}
};
O(K*logN+N)
法2:
class Solution
{
public:
int findKthLargest(vector<int>& nums, int k)
{
priority_queue<int,vector<int>,greater<int>> pq(nums.begin(),nums.begin()+k); //用堆排的思想,找大数建小堆
for(size_t i=k;i<nums.size();++i)
{
if(nums[i]>pq.top())
{
pq.pop();
pq.push(nums[i]);
}
}
//假设有n个排列好的数据,用前k个建小堆,那么后面n-k个能全部进入堆,那么最小的大数就是第n-k个,也就是堆顶,从n开始倒数第k个。
return pq.top();
}
};
O((N-K)*logK)
.二叉树的最近公共祖先
236. 二叉树的最近公共祖先 - 力扣(LeetCode)
class Solution
{
public:
bool IsInTree(TreeNode* root, TreeNode* x)
{
if(root==nullptr)
return false;
if(root==x)
return true;
return IsInTree(root->left,x)||IsInTree(root->right,x);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
if(root==nullptr)
{
return nullptr;
}
if(p==root||q==root) //如果自己是根的话,那么另一个一定是孩子,自己就是公共祖先
{
return root;
}
bool pInleft=IsInTree(root->left,p);
bool pInRight=!pInleft;
bool qInleft=IsInTree(root->left,q);
bool qInRight=!qInleft;
if( pInleft&&qInRight || pInRight&&qInleft)
{
return root;
}
else if(pInleft&&qInleft)
{
return lowestCommonAncestor(root->left,p,q);
}
else
{
return lowestCommonAncestor(root->right,p,q);
}
}
};
这个的O(N)是n方
法2:用深度搜索找公共路线
class Solution
{
public:
bool GetPath(TreeNode* root,TreeNode* x,stack<TreeNode*>& path)
{
if(root==nullptr)
return false;
path.push(root); //先入
if(root==x) //找到要找的结点了
return true;
if(GetPath(root->left,x,path))
return true;
if(GetPath(root->right,x,path))
return true;
path.pop(); //要先把那个错误的路径弹出去
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
stack<TreeNode*> Ppath,Qpath;
GetPath(root,p,Ppath);
GetPath(root,q,Qpath);
while(Ppath.size()!=Qpath.size())
{
if(Ppath.size() > Qpath.size())
Ppath.pop();
else
Qpath.pop();
}
while(Ppath.top()!=Qpath.top())
{
Ppath.pop();
Qpath.pop();
}
return Ppath.top();
}
};
.设计循环队列
(1)链表判满
(2)数组判满 (rear是下标,开辟空间数==k+1)
typedef struct
{
int *a;
int front;
int tail;
int k;
} MyCircularQueue;
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->tail==obj->front;
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
return (obj->tail+1)%(obj->k+1)==obj->front;
}
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* obj =(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a=(int*)malloc(sizeof(int)*(k+1));
obj->front=obj->tail=0;
obj->k=k;
return obj;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if(myCircularQueueIsFull(obj))
{
return false;
}
obj->a[obj->tail]=value;
obj->tail++; //别忘了放完之后,tail才++
obj->tail=(obj->tail)%(obj->k+1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return false;
}
obj->front++;
obj->front=(obj->front)%(obj->k+1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
if(obj->tail==0)
{
return obj->a[obj->k];
}
else
{
return obj->a[obj->tail-1]; //别忘了tail-1,因为push完之后tail要+1;
}
// return obj->a[(obj->tail+obj->k)%(obj->k+1)]; 也可以
}
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->a); //从小往大释放
free(obj);
}
1.也符合先进先出
2.空间大小固定
3.就结果而言,数组更好用
.前K个高频单词
class Solution
{
public:
struct Compare
{
bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2)const
{
return kv1.second > kv2.second;
}
};
vector<string> topKFrequent(vector<string>& words, int k)
{
map<string,int> countMap;
for(auto& str:words)
{
countMap[str]++;
}
vector<pair<string,int>> v(countMap.begin(),countMap.end()); //用迭代器构造
stable_sort(v.begin(),v.end(),Compare()); //不要用sort,sort不具有稳定性
vector<string> vv;
for(size_t i=0;i<k;i++)
{
vv.push_back(v[i].first);
}
return vv;
}
};
如果不用stable_sort,那么可以通过改变仿函数的比较方式,用sort也行
eg:
struct Compare
{
bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2)const
{
return kv1.second > kv2.second ||(kv1.second==kv2.second && kv1.first<kv2.first);
}
};