格雷 lru 寻找重复数 旋图 第k个最大 topk sharedptr 奇偶链 重排链

89. 格雷编码 - 力扣(LeetCode)

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 然后进去 倒序遍历

48. 旋转图像 - 力扣(LeetCode)

先上下翻转 再对角线翻转

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-。。-。。

剩余的一种情况就是找到了直接返回

287. 寻找重复数 - 力扣(LeetCode)

不需要额外的数组开销 在原数组上操作即可 首先用一个变量记录一下当前位置的数字,然后把这个数字当作数组的下标,把对应的为位置加上数组的长度,然后每次遍历的时候如果发现当前位置的数大于数组长度 说明这个位置被其他映射过 取出这个数字减去数组长度重新操作即可,如果再遍历的数字然后他的下标位置被映射过 说明这个下标已经被其他的映射过了 已经重复出现了 直接返回

LRU缓存

146. LRU 缓存 - 力扣(LeetCode)

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问题

拜托,面试别再问我TopK了!!!-CSDN博客

海量数据中找出前k大数(topk问题),一篇文章教会你-阿里云开发者社区 (aliyun.com)

C++ 语言中 priority_queue 的常见用法详解 - 知乎 (zhihu.com)

c++优先队列(priority_queue)用法详解_c++ 优先队列-CSDN博客

奇偶链表

328. 奇偶链表 - 力扣(LeetCode)

两个头节点 一个鸡头一个偶头

鸡头就是头节点 偶头是头节点的下一个节点

需要两个节点分别遍历奇偶

鸡的下一个等于偶的下一个

鸡往下挪一位

偶的下一个等于鸡的下一个

偶往下挪一位

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;
    }
};

重排链表

143. 重排链表 - 力扣(LeetCode)

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位空的时候截止

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值