⭐️我叫恒心,一名喜欢书写博客的研究生在读生。
原创不易~转载麻烦注明出处,并告知作者,谢谢!!!
这是一篇近期会不断更新的博客欧~~~ 有什么问题的小伙伴 欢迎留言提问欧。
文章目录
- 1 反转链表
- 2 排序
- 3 设计LRU缓存结构
- 4 最小K个数
- 5 求二叉树的层次遍历
- 6 **NC33** **合并两个排序的链表**
- 7 **用两个栈实现队列**
- 8 跳台阶
- 9 求连续子数组的最大和
- 10 判断一个链表是否有环
- 11 删除链表倒数第K个节点(已经考了)
- 12 大小端
- 13 二叉树公共祖先
- 14 二叉搜素树的公共祖先
- 15 **字符串出现次数的TopK问题**
- 16 加起来和位目标值的组合(二)
- 17 连续子数组的最大乘积
- 18 设计一个循环数组
1 反转链表
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode* newHead = nullptr;
while(pHead){
ListNode* nex = pHead->next;
pHead->next = newHead;
newHead = pHead;
pHead = nex;
}
return newHead;
}
}
递归的形式
class Solution {
public:
ListNode* ReverseListCore(ListNode* node) {
if (node == nullptr || node->next == nullptr) return node;
ListNode* nexHead = node->next;
ListNode* newHead = ReverseListCore(nexHead);
nexHead->next = node;
node->next = nullptr;
return newHead;
}
ListNode* ReverseList(ListNode* pHead) {
return ReverseListCore(pHead);
}
};
2 排序
堆排序
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 将给定数组排序
* @param arr int整型vector 待排序的数组
* @return int整型vector
*/
void quickSort(vector<int>& num, int begin, int end){
if(begin > end) return ;
int low = begin;
int high = end;
int key = num[begin];
while(low < high){
// 跟右边进行比较
while(low < high && key <= num[high]){
high--;
}
if(low < high) num[low++] = num[high];
while(low < high && key >= num[low]){
low++;
}
if(low < high) num[high--] = num[low];
}
num[low] = key;
quickSort(num, begin, low-1);
quickSort(num, low+1, end);
}
void heapfy(vector<int>& arr, int i, int n){
if(i >= n) return ;
int c1 = 2*i + 1;
int c2 = 2*i + 2;
int max = i;
if(c1 < n && (arr[c1] > arr[max])) max = c1;
if(c2 < n && (arr[c2] > arr[max])) max = c2;
if(max != i){
swap(arr[max],arr[i]);
heapfy(arr,max,n);
}
}
void build_heap(vector<int>& arr, int n){
int parent = (n-2) / 2;
for(int i = parent; i>=0; --i){
heapfy(arr,i,n);
}
}
void heapSort(vector<int>& arr){
int n = arr.size();
build_heap(arr,n);
for(int i = n-1; i >=0; --i){
cout<<arr[0]<<endl;
swap(arr[0],arr[i]);
heapfy(arr,0,i);
}
}
vector<int> MySort(vector<int>& arr) {
// write code here
// 快速排序
int n = arr.size();
//quickSort(arr,0,n-1);
heapSort(arr);
return arr;
}
};
3 设计LRU缓存结构
#include<iostream>
#include<unordered_map>
#include<algorithm>
using namespace std;
//这里放你的代码
struct DKLinkNode{
int key,value;
DKLinkNode* next;
DKLinkNode* pre;
DKLinkNode():key(0),value(0),pre(nullptr),next(nullptr){}
DKLinkNode(int _key, int _val):key(_key),value(_val),pre(nullptr),next(nullptr){}
};
class LRUCache {
private:
// 借助哈希表来查询存储的位置,key value(链表节点)
unordered_map<int, DKLinkNode*> cache;
int capacity;
int size;
DKLinkNode* head;
DKLinkNode* tail;
public:
LRUCache(int _capacity):capacity(_capacity),size(0) {
// 创建头尾 伪节点 便于定位
head = new DKLinkNode();
tail = new DKLinkNode();
head->next = tail;
tail->pre = head;
}
~LRUCache(){
if(head != nullptr){
delete head;
head = nullptr;
}
if(tail != nullptr){
delete tail;
tail = nullptr;
}
for(auto& c : cache){
if(c.second != nullptr){
delete c.second;
c.second = nullptr;
}
}
}
int get(int key) {
// 如果双向链表中没有这个节点则直接返回
if(!cache.count(key)){return -1;}
// 如果有节点 则通过哈希表获取这个节点的地址,将这个节点移到前面
DKLinkNode* node = cache[key];
moveToHead(node);
return node->value;
}
void put(int key, int value) {
// 如果哈希表查找不到这个key 则插入新的值到哈希表中
// 将新的值插入双向链表的头部
if(!cache.count(key)){
DKLinkNode* node = new DKLinkNode(key, value);
cache[key] = node;
addHeadNode(node);
++size;
// 如果当前的容量大于缓存的最大容量,则移除某段节点
if(size > capacity){
DKLinkNode* rNode = removeTail();
cache.erase(rNode->key);
delete rNode;
--size;
}
}else{
// 如果查找得到key,则将该节点移动到头部
DKLinkNode* moveNode = cache[key];
// 更新当前key对应的value 并移动链表
moveNode->value = value;
moveToHead(moveNode);
}
}
void addHeadNode(DKLinkNode* node){
node->pre = head;
node->next = head->next;
head->next->pre = node;
head->next = node;
}
void removeNode(DKLinkNode* rNode){
rNode->pre->next = rNode->next;
rNode->next->pre = rNode->pre;
}
DKLinkNode* removeTail(){
DKLinkNode* rNode = tail->pre;
removeNode(rNode);
return rNode;
}
void moveToHead(DKLinkNode* node){
// 删除当前节点
removeNode(node);
// 在头结点处添加进去
addHeadNode(node);
}
};
int main(){
LRUCache* cache = new LRUCache(2);
cache->put(1, 1);
cache->put(2, 2);
int res = cache->get(1); // 返回 1
cout<<res<<endl;
cache->put(3, 3); // 该操作会使得密钥 2 作废
res = cache->get(2); // 返回 -1 (未找到)
cache->put(4, 4); // 该操作会使得密钥 1 作废
res = cache->get(1); // 返回 -1 (未找到)
cout<<res<<endl;
res = cache->get(3); // 返回 3
cout<<res<<endl;
res = cache->get(4); // 返回 4
cout<<res<<endl;
return 0;
}
4 最小K个数
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> res;
if(input.size() == 0 || k == 0) return res;
// 利用最小堆来做。
priority_queue<int, vector<int>, greater<int>> minHeap;
for(auto num : input){
minHeap.push(num);
}
while(k--){
res.push_back(minHeap.top());
minHeap.pop();
}
return res;
}
};
最小k个数 应该用大根堆来做
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> ret;
if (k==0 || k > input.size()) return ret;
priority_queue<int, vector<int>> pq;
for (const int val : input) {
if (pq.size() < k) {
pq.push(val);
}
else {
if (val < pq.top()) {
pq.pop();
pq.push(val);
}
}
}
while (!pq.empty()) {
ret.push_back(pq.top());
pq.pop();
}
return ret;
}
};
5 求二叉树的层次遍历
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
/**
*
* @param root TreeNode类
* @return int整型vector<vector<>>
*/
vector<vector<int> > levelOrder(TreeNode* root) {
// write code here
vector<vector<int>> res;
if (root == nullptr) return res;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int q_size = q.size();
vector<int> temp;
while (q_size--) {
TreeNode* node = q.front();
temp.push_back(node->val);
q.pop();
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
res.push_back(temp);
}
return res;
}
};
6 NC33 合并两个排序的链表
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1 == nullptr) return l2;
if(l2 == nullptr) return l1;
ListNode* dummy = new ListNode(0);
ListNode* cur = dummy;
while(l1 && l2){
if(l1->val <= l2->val){
cur->next = l1;
cur = l1;
l1 = l1->next;
}else if(l1->val > l2->val){
cur->next = l2;
cur = l2;
l2 = l2->next;
}
}
if(l1!=nullptr){
cur->next = l1;
}else if(l2 != nullptr){
cur->next = l2;
}
return dummy->next;
}
};
7 用两个栈实现队列
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
// 借助辅助栈完成
while(!stack1.empty()){
stack2.push(stack1.top());
stack1.pop();
}
int val = stack2.top();
stack2.pop();
while(!stack2.empty()){
stack1.push(stack2.top());
stack2.pop();
}
return val;
}
private:
stack<int> stack1;
stack<int> stack2; // 辅助栈
};
8 跳台阶
class Solution {
public:
int jumpFloor(int n) {
// 跳台阶的动态规划
vector<int> dp(n+1,0);
dp[0] = 1;
for(int i = 1; i <= n; ++i){
for(int j = 1; j <=2; ++j){
if(i - j >= 0) dp[i] += dp[i - j];
}
}
return dp[n];
}
};
9 求连续子数组的最大和
时间复杂度 O(n)
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
// 动态规划 dp[i] 表示添加i个数组后 最大和
if(array.size() == 1) return array[0];
int res = array[0];
int n = array.size();
vector<int> dp(n+1,0);
dp[0] = array[0];
for(int i = 1; i < array.size(); ++i){
dp[i] = max(dp[i-1]+array[i], array[i]);
res = max(res, dp[i]);
}
return res;
}
};
优化空间复杂度
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
int sum = 0;
int maxVal = array[0];
for(int i = 0; i < array.size(); ++i){
sum = max(sum + array[i], array[i]);
maxVal = max(sum, maxVal);
}
return maxVal;
}
};
10 判断一个链表是否有环
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
// 特殊情况 当链表长度为空为1无环
// 有环 必然会相遇
// 无环 则必然会遇到空节点
if(head == nullptr || head->next == nullptr){
return false;
}
ListNode* fast = head->next;
ListNode* slow = head;
while(fast->next!=nullptr && fast->next->next!=nullptr){
if(slow == fast){
return true;
}else{
fast = fast->next->next;
slow = slow->next;
}
}
return false;
}
};
11 删除链表倒数第K个节点(已经考了)
class Solution {
public:
//求链表的长度
int len(ListNode* head){
int s=0;
while(head!=NULL){
s++;
head=head->next;
}
return s;
}
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* pre=head;
int k=len(pre)-n;
//要是之间是删除的是头节点 直接指针后移
if(k==0){
return head->next;
}
for(int i=0;i<k-1;i++){
pre=pre->next;
}
//越过删除的结点
pre->next=pre->next->next;
return head;
}
};
12 大小端
#include<iostream>
using namespace std;
int main(){
union{
int num;
char lowC;
}data;
data.num = 1;
if(data.lowC == 1){
cout<<"small "<<endl;
}else{
cout<<"big "<<endl;
}
return 0;
}
13 二叉树公共祖先
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == q || root == p || root == NULL) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (left != NULL && right != NULL) return root;
if (left == NULL && right != NULL) return right;
else if (left != NULL && right == NULL) return left;
else { // (left == NULL && right == NULL)
return NULL;
}
}
};
14 二叉搜素树的公共祖先
解题思路: 公共祖先必然是再左右节点之间 [p,q]
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root->val > p->val && root->val > q->val) {
return lowestCommonAncestor(root->left, p, q);
} else if (root->val < p->val && root->val < q->val) {
return lowestCommonAncestor(root->right, p, q);
} else return root;
}
};
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while(root) {
if (root->val > p->val && root->val > q->val) {
root = root->left;
} else if (root->val < p->val && root->val < q->val) {
root = root->right;
} else return root;
}
return NULL;
}
};
15 字符串出现次数的TopK问题
自定义小堆
struct cmp {
bool operator() (pair<string, int> &p1, pair<string, int> &p2) {
return p1.second > p2.second || (p1.second == p2.second && p1.first < p2.first); //出现次数较高或者出现次数相同字典序小的优先级高(堆顶的元素优先级最低)
}
};
class Solution {
public:
vector<vector<string> > topKstrings(vector<string>& strings, int k) {
vector<vector<string> > res;
unordered_map<string, int> umap; //用于统计字符串出现次数
for(string &s: strings) umap[s]++;
priority_queue<pair<string, int>, vector<pair<string, int> >, cmp> pq; //自定义优先队列
for(auto it = umap.begin(); it != umap.end(); it++) { //遍历无序map
if(pq.size() < k) pq.emplace(pair<string, int> {it->first, it->second}); //当堆元素数小于k直接入堆
else if(it->second > pq.top().second || (it->second == pq.top().second && it->first < pq.top().first)) { //否则判断是否能取出堆顶放入新元素
pq.pop();
pq.emplace(pair<string, int> {it->first, it->second});
}
}
while(!pq.empty()) { //由优先级从小到大依次取出
res.emplace_back(vector<string> {pq.top().first, to_string(pq.top().second)});
pq.pop();
}
reverse(res.begin(), res.end()); //逆转使优先级从大到小
return res; //返回结果
}
};
16 加起来和位目标值的组合(二)
class Solution {
public:
void dfs(vector<int>& num, int target, vector<vector<int> >& res,
vector<int>& tmp, int start) {
if (target == 0) {
res.push_back(tmp);
return;
}
if (start >= num.size()) return;
for (int i = start; i < num.size(); ++i) {
if (i > start && num[i] == num[i - 1]) continue;
// 剪枝
//前面的排序就有意义了 这块要是剩余的num[i]的值已经大于target的大小 后面已经是无效搜索了
if (num[i] <= target ) {
tmp.push_back(num[i]);
dfs(num, target - num[i], res, tmp,i + 1);
tmp.pop_back();
}
}
}
vector<vector<int> > combinationSum2(vector<int>& num, int target) {
vector<vector<int> > res;
vector<int> tmp;
if (num.empty()) return res;
sort(num.begin(), num.end());
dfs(num, target, res, tmp, 0);
return res;
}
};
17 连续子数组的最大乘积
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* @param nums int整型vector
* @return int整型
*/
int maxProduct(vector<int>& nums) {
vector<int> pos(nums); // 存储以nums[i] 结尾的最大乘积
vector<int> neg(nums); // 存储以 nums[i] 结尾的最小乘积
int result=nums[0];
for(int i=1;i<nums.size();i++){
pos[i]=max(nums[i],max(nums[i]*pos[i-1],nums[i]*neg[i-1]));
neg[i]=min(nums[i],min(nums[i]*pos[i-1],nums[i]*neg[i-1]));
result=max(result,pos[i]);
}
return result;
}
};
18 设计一个循环数组
class MyCircularQueue {
private:
int front;
int tail;
int capity;
vector<int> element;
public:
MyCircularQueue(int k) {
this->capity = k + 1;
front = tail = 0;
this->element = vector<int>(capity);
}
bool enQueue(int value) {
if(isFull()){
return false;
}
element[tail] = value;
tail = (tail + 1) % capity;
return true;
}
bool deQueue() {
if(isEmpty()){
return false;
}
front = (front + 1) % capity;
return true;
}
int Front() {
if(isEmpty()){
return -1;
}
return element[front];
}
int Rear() {
if(isEmpty()){
return -1;
}
return element[(tail -1 + capity) % capity];
}
bool isEmpty() {
return front == tail;
}
bool isFull() {
return front == (tail + 1) % capity;
}
};
/**
* Your MyCircularQueue object will be instantiated and called as such:
* MyCircularQueue* obj = new MyCircularQueue(k);
* bool param_1 = obj->enQueue(value);
* bool param_2 = obj->deQueue();
* int param_3 = obj->Front();
* int param_4 = obj->Rear();
* bool param_5 = obj->isEmpty();
* bool param_6 = obj->isFull();
*/
最后 🐶狗头保命
一名喜欢书写博客的研究生在读生
如果觉得有用,麻烦三连支持一下欧,希望这篇文章可以帮到你,你的点赞是我持续更新的动力