栈
基本运算器I
给定一个包含正整数、加(+)、减(-)、乘(* )、除(/)的算数表达式(括号除外),计算其结果。
表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格 。 整数除法仅保留整数部分。
class Solution {
public:
int calculate(string s) {
stack<int> ops;
ops.push(1);
int sign = 1;
int ret = 0;
int n = s.length();
int i = 0;
while(i < n){
if(s[i] == ' '){
i++;
}
else if(s[i] == '+'){
sign = ops.top();
i++;
}
else if(s[i] == '-'){
sign = -ops.top();
i++;
}
else if(s[i] == '('){
ops.push(sign);
i++;
}
else if(s[i] == ')'){
ops.pop();
i++;
}
else{
long num = 0;
while(i < n && s[i] >= '0' && s[i] <= '9'){
num = num * 10 + s[i] - '0';
i++;
}
ret += sign * num;
}
}
return ret;
}
};
基本运算器II
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
例如:(1+(4+5+2)-3)+(6+8)
class Solution {
public:
int calculate(string s) {
stack<int> ops;
ops.push(1);
int sign = 1;
int ret = 0;
int n = s.length();
int i = 0;
while(i < n){
if(s[i] == ' '){
i++;
}
else if(s[i] == '+'){
sign = ops.top();
i++;
}
else if(s[i] == '-'){
sign = -ops.top();
i++;
}
else if(s[i] == '('){
ops.push(sign);
i++;
}
else if(s[i] == ')'){
ops.pop();
i++;
}
else{
long num = 0;
while(i < n && s[i] >= '0' && s[i] <= '9'){
num = num * 10 + s[i] - '0';
i++;
}
ret += sign * num;
}
}
return ret;
}
};
动态规划
整数拆分
给定一个正整数 n ,将其拆分为 k 个 正整数 的和( k >= 2 ),并使这些整数的乘积最大化。
返回 你可以获得的最大乘积 。
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n, 1);
for(int i = 1; i < n; i++){
for(int j = 2; j <= i; j++){
dp[i] = max(dp[i], dp[i-j] * j);
dp[i] = max(dp[i], (i-j+1) * j);
}
}
return dp[n-1];
}
};
最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
int res = 0, maxlen = 0;
vector<vector<bool>> dp(n, vector<bool>(n));
for(int len = 1; len <= n; len++){
for(int j = 0; j < n-len+1; j++){
if(len <= 2){
dp[j][j+len-1] = s[j] == s[j+len-1];
}
else if(s[j] == s[j+len-1]){
dp[j][j+len-1] = dp[j+1][j+len-2];
}
if(dp[j][j+len-1] && len > maxlen){
maxlen = len;
res = j;
}
}
}
return s.substr(res, maxlen);
}
};
最长有效括号
给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号
子串的长度。
class Solution {
public:
int longestValidParentheses(string s) {
int n = s.size();
vector<int> dp(n+1, 0);
int res = 0;
for(int i = 1; i < n; i++){
if(s[i] == ')' && s[i-1] == '('){
dp[i+1] = max(dp[i+1], dp[i-1]+2);
}
if(s[i] == ')' && s[i-1] == ')' && i >= dp[i]+1 && s[i-dp[i]-1] == '('){
dp[i+1] = max(dp[i+1], dp[i - dp[i] - 1] + dp[i] + 2);
}
res = max(res, dp[i+1]);
}
return res;
}
};
链表
反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* tail = head;
if(!tail){
return head;
}
while(tail->next){
ListNode* temp = tail->next;
tail->next = tail->next->next;
temp->next = head;
head = temp;
}
return head;
}
};
环形链表 II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
unordered_set<ListNode*> set;
while(head){
if(set.count(head)){
return head;
}
set.insert(head);
head = head->next;
}
return NULL;
}
};
LRU缓存
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
个人想法:直接对vector进行查找,增加操作,(会超时)
class LRUCache {
public:
vector<vector<int>> v;
int n;
LRUCache(int capacity) {
n = capacity;
}
int get(int key) {
for(int i = 0; i < v.size(); i++){
if(v[i][0] == key){
vector<int> temp = v[i];
while(i < v.size()-1){
v[i] = v[i+1];
i++;
}
v[i] = temp;
return v[i][1];
}
}
return -1;
}
void put(int key, int value) {
int flag = 0;
for(int i = 0; i < v.size(); i++){
if(v[i][0] == key){
flag = 1;
while(i < v.size()-1){
v[i] = v[i+1];
i++;
}
v[i] = {key, value};
}
}
if(flag == 0){
if(v.size() < n){
v.push_back({key, value});
}
else{
int i = 0;
while(i < v.size()-1){
v[i] = v[i+1];
i++;
}
v[i] = {key, value};
}
}
}
};
哈希表+双向链表
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 {
public:
unordered_map<int, DLinkedNode*> cache;
DLinkedNode* head;
DLinkedNode* tail;
int size;
int capacity;
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;
}
DLinkedNode* node = cache[key];
moveToHead(node);
return node->value;
}
void put(int key, int value) {
if(!cache.count(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{
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;
}
};
二叉树
二叉树的中序遍历
递归
class Solution {
public:
void helper(TreeNode* root, vector<int>& v){
if(root == nullptr){
return;
}
helper(root->left, v);
v.push_back(root->val);
helper(root->right, v);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
helper(root, res);
return res;
}
};
栈
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> stk;
while(root != nullptr || !stk.empty()){
while(root != nullptr){
stk.push(root);
root = root->left;
}
root = stk.top();
stk.pop();
res.push_back(root->val);
root = root->right;
}
return res;
}
};
二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
class Solution {
public:
TreeNode* ans;
bool dfs(TreeNode* root, TreeNode* p, TreeNode* q){
if(root == NULL){
return false;
}
bool lson = dfs(root->left, p, q);
bool rson = dfs(root->right, p, q);
if((lson && rson) || ((root->val == p->val || root->val == q->val) &&(lson || rson))){
ans = root;
}
return lson || rson ||(root->val == p->val || root->val == q->val);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
dfs(root, p, q);
return ans;
}
};
滑动窗口
无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set<char> set;
int left = 0;
int res = 0;
for(int i = 0; i < s.size(); i++){
while(set.count(s[i])){
set.erase(s[left]);
left++;
}
set.insert(s[i]);
res = max(res, i - left + 1);
}
return res;
}
};