class Solution {
public:
vector<int> grayCode(int n) {
vector<int> res;
res.push_back(0);
int head = 1;
for (int i = 0; i < n; i++) {
for (int j = res.size() - 1; j >= 0; j--) {
res.push_back(head + res[j]);
}
head <<= 1;
}
return res;
}
};
第二层for循环的意思是 前四个数跟上一次一样 我们需要再加上四个数 从上一个数组的最后一个数开始 每一个数的第一位加一个1 然后进去 倒序遍历
先上下翻转 再对角线翻转
j=i是对角线 控制对角线左边的元素翻转 就得j<i
手撕shared_ptr
#include <iostream>
using namespace std;
class Count{
public:
Count(){
count = 1;
}
void Increase(){
count++;
}
void Decrease(){
count--;
}
int GetCount(){
return count;
}
private:
int count = 0; //不能直接赋值为1,防止成员声明时SmartPtr<int> sp,引用计数会错误为1
};
template<typename T>
class SmartPtr{
public:
SmartPtr(): ptr_(nullptr),count_(nullptr){}
explicit SmartPtr(T*ptr) : ptr_(ptr), count_(new Count()) {}
~SmartPtr(){
if(count_!=nullptr){
count_->Decrease();
if(count_->GetCount() == 0){
delete ptr_;
delete count_;
ptr_ = nullptr;
count_ = nullptr;
}
}
}
SmartPtr(const SmartPtr<T>& other){
ptr_ = other.ptr_;
count_ = other.count_;
count_->Increase();
}
SmartPtr<T>& operator=(const SmartPtr<T>& other) {
if(ptr_ == other.ptr_) {
return *this;
}
ptr_ = other.ptr_;
count_ = other.count_;
count_->Increase();
return *this;
}
T* get() {
return ptr_;
}
T* operator->() {
return ptr_;
}
T& operator*() {
return *ptr_;
}
int GetCnt(){
if (count_ == nullptr) return 0;
return count_->GetCount();
}
private:
Count* count_;
T* ptr_;
};
class Test {
int a{23};
string b{"asdad"};
};
int main(){
SmartPtr<Test> sp0;
cout<<"sp0: "<<sp0.GetCnt() <<endl;
{
SmartPtr<Test> sp1(new Test());
cout<<"sp1: "<<sp1.GetCnt() <<endl;
SmartPtr<Test> sp2(sp1);
cout<<"sp2: "<<sp2.GetCnt() <<endl;
sp0 = sp2;
cout<<"sp0: "<<sp0.GetCnt() <<endl;
}
cout<<"sp0: "<<sp0.GetCnt() <<endl;
return 0;
}
215. 数组中的第K个最大元素 - 力扣(LeetCode)
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
return quickSelect(nums, k);
}
int quickSelect(vector<int>& nums, int k) {
// 基于快排的快速选择
// 随机选择基准数字
int p = nums[rand() % nums.size()];
// 将大于等于小于的元素分别放入三个数组
vector<int> big, equal, small;
for (int a : nums) {
if (a < p) small.push_back(a);
else if (a == p) equal.push_back(a);
else big.push_back(a);
}
// 第k大元素在big中, 递归划分
if (k <= big.size()) {
return quickSelect(big, k);
}
// 第k大元素在small中, 递归划分
if (big.size() + equal.size() < k) {
return quickSelect(small, k - (big.size() + equal.size()));
}
// 第k大元素在equal中, 返回p
return p;
}
};
用了快排的思想 随机选出一个标准值
大于他的放一个数组big里面
小于他的放一个small数组里面
等于他的数放在eqaull数组里面
先看k的值小不小于big数组的大小 因为big数组就代表着前多少大的数 比如说要第二大的数 big为3
说明第二大的数肯定在big数组里面
如果判断不是的话说明在其他两个数组里面
再看第k大的数在不在small里面 k越大说明数越小 k大于了big+eqall说明一定在small里面
在samll里面的话就不能穿k了 穿的是在small里面第几大的数 就是k-。。-。。
剩余的一种情况就是找到了直接返回
不需要额外的数组开销 在原数组上操作即可 首先用一个变量记录一下当前位置的数字,然后把这个数字当作数组的下标,把对应的为位置加上数组的长度,然后每次遍历的时候如果发现当前位置的数大于数组长度 说明这个位置被其他映射过 取出这个数字减去数组长度重新操作即可,如果再遍历的数字然后他的下标位置被映射过 说明这个下标已经被其他的映射过了 已经重复出现了 直接返回
LRU缓存
struct DLinkedNode {
int key, value;
DLinkedNode* prev;
DLinkedNode* next;
DLinkedNode(): key(0), value(0), prev(nullptr), next(nullptr) {}
DLinkedNode(int _key, int _value): key(_key), value(_value), prev(nullptr), next(nullptr) {}
};
class LRUCache {
private:
unordered_map<int, DLinkedNode*> cache;
DLinkedNode* head;
DLinkedNode* tail;
int size;
int capacity;
public:
LRUCache(int _capacity): capacity(_capacity), size(0) {
// 使用伪头部和伪尾部节点
head = new DLinkedNode();
tail = new DLinkedNode();
head->next = tail;
tail->prev = head;
}
int get(int key) {
if (!cache.count(key)) {
return -1;
}
// 如果 key 存在,先通过哈希表定位,再移到头部
DLinkedNode* node = cache[key];
moveToHead(node);
return node->value;
}
void put(int key, int value) {
if (!cache.count(key)) {
// 如果 key 不存在,创建一个新的节点
DLinkedNode* node = new DLinkedNode(key, value);
// 添加进哈希表
cache[key] = node;
// 添加至双向链表的头部
addToHead(node);
++size;
if (size > capacity) {
// 如果超出容量,删除双向链表的尾部节点
DLinkedNode* removed = removeTail();
// 删除哈希表中对应的项
cache.erase(removed->key);
// 防止内存泄漏
delete removed;
--size;
}
}
else {
// 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
DLinkedNode* node = cache[key];
node->value = value;
moveToHead(node);
}
}
void addToHead(DLinkedNode* node) {
node->prev = head;
node->next = head->next;
head->next->prev = node;
head->next = node;
}
void removeNode(DLinkedNode* node) {
node->prev->next = node->next;
node->next->prev = node->prev;
}
void moveToHead(DLinkedNode* node) {
removeNode(node);
addToHead(node);
}
DLinkedNode* removeTail() {
DLinkedNode* node = tail->prev;
removeNode(node);
return node;
}
};
topk问题
海量数据中找出前k大数(topk问题),一篇文章教会你-阿里云开发者社区 (aliyun.com)
C++ 语言中 priority_queue 的常见用法详解 - 知乎 (zhihu.com)
c++优先队列(priority_queue)用法详解_c++ 优先队列-CSDN博客
奇偶链表
两个头节点 一个鸡头一个偶头
鸡头就是头节点 偶头是头节点的下一个节点
需要两个节点分别遍历奇偶
鸡的下一个等于偶的下一个
鸡往下挪一位
偶的下一个等于鸡的下一个
偶往下挪一位
while循环 截止条件就是 偶为空或者是偶的下一个为空
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if(head==nullptr)return NULL;
ListNode* ouhead = head->next;
ListNode* ji = head;
ListNode* ou = ouhead;
while(ou!=NULL && ou->next!=NULL){
ji->next=ou->next;
ji=ji->next;
ou->next=ji->next;
ou=ou->next;
}
ji->next=ouhead;
return head;
}
};
重排链表
class Solution {
// 876. 链表的中间结点
ListNode *middleNode(ListNode *head) {
ListNode *slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
// 206. 反转链表
ListNode *reverseList(ListNode *head) {
ListNode *pre = nullptr, *cur = head;
while (cur) {
ListNode *nxt = cur->next;
cur->next = pre;
pre = cur;
cur = nxt;
}
return pre;
}
public:
void reorderList(ListNode *head) {
ListNode *mid = middleNode(head);
ListNode *head2 = reverseList(mid);
while (head2->next) {
ListNode *nxt = head->next;
ListNode *nxt2 = head2->next;
head->next = head2;
head2->next = nxt;
head = nxt;
head2 = nxt2;
}
}
};
先找到中间节点 用快慢指针 慢指针走一步 快指针走两步 当快指针为空或者快指针的下一个为空停止 此时慢指针正好在中间 如果节点是偶数的话 慢指针在偏右侧的第一个 返回慢指针
然后从慢指针开始翻转链表 cur pre 翻转完之后 cur指向空 pre指向链表末尾
然后一个头节点 还有一个cur 记为head2 拿两个临时变量分别存储这两个节点的下一个
然后head指向head2 head2指向head的下一个 head和head2再分别指向临时变量里
head2位空的时候截止