子集
题目链接:https://leetcode-cn.com/problems/subsets/
思路一 追加法
//层序遍历求解
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
//只有一个空数组的二维数组
vector<vector<int> > res(1);
//依次添加每一个数组元素
for(int i=0;i<nums.size();i++)
{
int max=res.size();
for(int j=0;j<max;j++)
{
vector<int> temp(res[j]);
temp.push_back(nums[i]);
res.push_back(temp);
}
}
return res;
}
};
思路二:回溯法
//回溯法(递归)
class Solution {
public:
void subsets_help(vector<vector<int> > &res,vector<int> temp,int level,vector<int> &nums)
{
if(temp.size()<=nums.size())
{
res.push_back(temp);
}
for(int i=level;i<nums.size();i++)
{
temp.push_back(nums[i]);
subsets_help(res,temp,i+1,nums);
temp.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int> > res;
vector<int> temp;
subsets_help(res,temp,0,nums);
return res;
}
};
思路三:DFS
//回溯法(递归)
class Solution {
public:
void subsets_help(vector<vector<int> > &res,vector<int> temp,int level,vector<int> &nums)
{
if(temp.size()<=nums.size())
{
res.push_back(temp);
}
for(int i=level;i<nums.size();i++)
{
temp.push_back(nums[i]);
subsets_help(res,temp,i+1,nums);
temp.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int> > res;
vector<int> temp;
subsets_help(res,temp,0,nums);
return res;
}
};
思路四:二进制
有点像是深度优先遍历,每个元素有选与不选2个选项,分别用1和0来表示。
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int> > res;
for(long long i=0;i<(1<<nums.size());i++)
{
vector<int> temp;
for(int j=0;j<nums.size();j++)
{
if((i>>j)&1)
temp.push_back(nums[j]);
}
res.push_back(temp);
}
return res;
}
};
格雷编码
题目链接:https://leetcode-cn.com/problems/gray-code/
镜像法即可
class Solution {
public:
vector<int> grayCode(int n) {
vector<int> res;
if(n==0)
{
res.push_back(0);
return res;
}
if(n==1)
{
res.push_back(0);
res.push_back(1);
return res;
}
//不要把这个忘了
res.push_back(0);
res.push_back(1);
for(int i=2;i<=n;i++)
{
int cnt=res.size()-1;
int add=pow(2,i-1);
for(int j=cnt;j>=0;j--)
{
int temp=res[j]+add;
res.push_back(temp);
}
}
return res;
}
};
LRU缓存机制
题目链接:https://leetcode-cn.com/problems/lru-cache/
要实现O(1)的时间复杂度,需要采用双向链表加哈希表的数据结构来实现。
因为过程中需要用到查找,删除,插入,并且有顺序之分(按照时间排序)要时这3项操作都满足O(1)的时间复杂度,就需要吧链表与哈希结合起来使用。
class LRUCache {
public:
LRUCache(int capacity) {
cap=capacity;
}
int get(int key) {
auto it=m.find(key);
//如果不存在
if(it==m.end())
return -1;
else
{
pair<int,int> kv=*m[key];
cache.erase(m[key]);
cache.push_front(kv);
//修改map中key对应的位置
m[key]=cache.begin();
//返回值
return kv.second;
}
}
void put(int key, int value) {
//首先查看key是否已经存在
auto it=m.find(key);
if(it==m.end())
{
//key不存在
//再判断是否已经满了
if(cache.size()==cap)
{
//cache和map中的数据都要删除
auto lastpair=cache.back();
int lastkey=lastpair.first;
m.erase(lastkey);
cache.pop_back();
}
//插入
cache.push_front(make_pair(key,value));
m[key]=cache.begin();
}
else
{
//key存在
//先删除
cache.erase(m[key]);
//插入
cache.push_front(make_pair(key,value));
m[key]=cache.begin();
}
}
private:
//哈希
unordered_map<int,list<pair<int,int>>::iterator> m;
//双向链表
list<pair<int,int>> cache;
//容量
int cap;
};
数组中的第K个最大元素
题目链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/
法一 sort排序,简单粗暴
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
sort(nums.begin(),nums.end());
int len=nums.size();
return nums[len-k];
}
};
法二 优先队列
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int,vector<int>,greater<int>> q;
for(int i=0;i<nums.size();i++)
{
q.push(nums[i]);
if(q.size()>k)
q.pop();
}
return q.top();
}
};
默认是数值越大优先级越高,效果等于less<int>。当加上greater<int>时就是数值越小优先级越高。
法三 快速排序
关于快速排序
注意点:这里是求第K大的元素,所以排序变成了从大到小排序,比较方便
//快速排序
class Solution {
public:
int partition(vector<int>& nums,int left,int right)
{
int key=nums[right];
while(left<right)
{
while(left<right&&nums[left]>=key)
left++;
nums[right]=nums[left];
while(left<right&&nums[right]<=key)
right--;
nums[left]=nums[right];
}
nums[left]=key;
return left;
}
int findKthLargest(vector<int>& nums, int k) {
int len=nums.size();
int left=0,right=len-1;
while(left<=right)
{
int mid=partition(nums,left,right);
if(mid==k-1)
return nums[mid];
else if(mid>k-1)
right=mid-1;
else
left=mid+1;
}
return -1;
}
};
二叉树中第K小的元素
题目链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/
中序遍历
/**
* 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:
void InTrans(TreeNode *root,int k,int &num,int &index)
{
if(!root)
return;
InTrans(root->left,k,num,index);
index++;
if(index==k)
{
num=root->val;
return;
}
InTrans(root->right,k,num,index);
}
int kthSmallest(TreeNode* root, int k) {
int num=0;
int index=0;
InTrans(root,k,num,index);
return num;
}
};
二叉树的最近公共祖先
题目链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/
注意不是二叉排序树。
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==NULL||p==root||q==root)
return root;
TreeNode *left=lowestCommonAncestor(root->left,p,q);
TreeNode *right=lowestCommonAncestor(root->right,p,q);
if(left&&right)
return root;
if(left)
return left;
if(right)
return right;
return NULL;
}
};
除自身以外数组的乘积
题目链接:https://leetcode-cn.com/problems/product-of-array-except-self/
注意题目的限制
思路:乘积=左侧乘积*右侧乘积
//乘积=左边数的乘积乘以右边数的乘积
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
vector<int> res(nums.size(),1);
int fac=1;
//res目前存储左边的乘积
for(int i=0;i<nums.size();i++)
{
res[i]*=fac;
fac*=nums[i];
}
fac=1;
for(int i=nums.size()-1;i>=0;i--)
{
res[i]*=fac;
fac*=nums[i];
}
return res;
}
};
优化:同时更新不同下标的左右乘积
//乘积=左边数的乘积乘以右边数的乘积
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
vector<int> res(nums.size(),1);
int left=1,right=1;
for(int i=0;i<nums.size();i++)
{
res[i]*=left;
left*=nums[i];
res[nums.size()-1-i]*=right;
right*=nums[nums.size()-1-i];
}
return res;
}
};
排序链表
题目链接:https://leetcode-cn.com/problems/sort-list/
如果不强求常数空间复杂度,直接使用归并排序
关于归并排序
class Solution {
public:
ListNode* sortList(ListNode* head) {
return mergesort(head);
}
ListNode *merge(ListNode *p,ListNode *q)
{
ListNode *dummyhead=new ListNode(0);
ListNode *k=dummyhead;
while(p&&q)
{
if(p->val<q->val)
{
k->next=p;
k=p;
p=p->next;
}
else
{
k->next=q;
k=q;
q=q->next;
}
}
k->next=p?p:q;
return dummyhead->next;
}
ListNode* mergesort(ListNode *head)
{
if(!head||!head->next)
return head;
ListNode *fast=head;
ListNode *slow=head;
ListNode *bre=NULL;
while(fast&&fast->next)
{
fast=fast->next->next;
bre=slow;
slow=slow->next;
}
bre->next=NULL;
ListNode *l1=mergesort(head);
ListNode *l2=mergesort(slow);
ListNode *node=merge(l1,l2);
return node;
}
};
注意dummyhead的使用
如果一定要使用常数时间复杂度。可以采用
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
//从链表中截取前n个节点,并返回之后断表的头节点
ListNode* cut(ListNode* head,int n)
{
auto p=head;
while(--n&&p)
{
p=p->next;
}
if(!p)
return NULL;
auto next=p->next;
p->next=NULL;
return next;
}
//合并2个有序链表
ListNode* merge(ListNode *p,ListNode *q)
{
ListNode *dummyhead=new ListNode(0);
auto k=dummyhead;
while(p&&q)
{
if(p->val<q->val)
{
k->next=p;
k=p;
p=p->next;
}
else
{
k->next=q;
k=q;
q=q->next;
}
}
k->next=p?p:q;
return dummyhead->next;
}
ListNode* sortList(ListNode* head) {
ListNode *dummyhead=new ListNode(0);
dummyhead->next=head;
auto p=head;
int len=0;
while(p)
{
++len;
p=p->next;
}
//开始归并排序,每次的区间都翻倍
for(int i=1;i<len;i*=2)
{
auto cur=dummyhead->next;
auto tail=dummyhead;
while(cur)
{
auto left=cur;
auto right=cut(left,i);
cur=cut(right,i);
tail->next=merge(left,right);
while(tail->next)
tail=tail->next;
}
}
return dummyhead->next;
}
};