19. 删除链表的倒数第 N 个结点
https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
auto fake = new ListNode();
fake->next = head;
int cnt = 0;
while(head){
head = head->next;
cnt++;
}
auto p = fake;
for(int i = 0; i < cnt - n; i++){
p = p->next;
}
p->next = p->next->next;
return fake->next;
}
};
难点在于找到倒数第 n 个结点,通过遍历 head 获得结点数,再从头遍历即可。值得一提的是需要用一个虚拟头结点进行操作,这样可以防止头结点被更改的问题。
21. 合并两个有序链表
https://leetcode.cn/problems/merge-two-sorted-lists/
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
auto dummy = new ListNode(-1), tail = dummy;
while(l1 && l2){
if(l1->val > l2->val){
tail = tail->next = l2;
l2 = l2->next;
}else{
tail = tail->next = l1;
l1 = l1->next;
}
}
if(l1) tail->next = l1;
if(l2) tail->next = l2;
return dummy->next;
}
};
主要是设置一个虚拟头结点即可,然后从头到尾遍历两个链表就 OK 了。
206. 反转链表
https://leetcode.cn/problems/reverse-linked-list/
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head) return NULL;
auto a = head, b = a->next;
while(b){
auto tmp = b->next;
b->next = a;
a = b;
b = tmp;
}
head->next = NULL;
return a;
}
};
画图就能搞懂,主要在于 b->next = a
相当于指反过来,然后 a 和 b 都往后移,直到 b 为 NULL。
203. 移除链表元素
https://leetcode.cn/problems/remove-linked-list-elements/
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点 。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
auto dummy = new ListNode(-1);
dummy->next = head;
for(auto p = dummy; p; p = p->next){
auto q = p->next;
while(q && q->val == val) q = q->next;
p->next = q;
}
return dummy->next;
}
};
用一个多的指针,当遇到需要删除的数字时就开始判断,判断结束后让前面的指针指向后面的那个指针即可。
83. 删除排序链表中的重复元素
https://leetcode.cn/problems/remove-duplicates-from-sorted-list/
给定一个已排序的链表的头 head
, 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head) return head;
auto dummy = head;
while(dummy->next){
if(dummy->val == dummy->next->val) dummy->next = dummy->next->next;
else dummy = dummy->next;
}
return head;
}
};
如果值相同就跳到下下个结点,相当于把值进行了删除。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head) return head;
auto fast = head, slow = head;
while(fast) {
if(fast->val != slow->val) {
slow->next = fast;
slow = slow->next;
}
fast = fast->next;
}
slow->next = NULL;
return head;
}
};
更清晰的写法,使用快慢指针,若值不同时将慢指针的下一位指向快指针即可。
20. 有效的括号
https://leetcode.cn/problems/valid-parentheses/
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对应的相同类型的左括号。
Copy class Solution {
public:
bool isValid(string s) {
stack<char> stk;
for(auto c : s){
if(c == '(' || c == '[' || c == '{') stk.push(c);
else {
if (stk.size() && abs(stk.top() - c) <= 2) stk.pop();
else return false;
}
}
return stk.empty();
}
};
因为括号之间的 ASCII 码的差都在 2 以内,所以可以通过这个进行判断是否匹配。很简单的一个栈的问题。
707. 设计链表
https://leetcode.cn/problems/design-linked-list/
设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。
在链表类中实现这些功能:
get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。 addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。 addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。 addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果 index 小于 0,则在头部插入节点。 deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
Copy class MyLinkedList {
public:
// 定义链表节点结构体
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val):val(val), next(nullptr){}
};
// 初始化链表
MyLinkedList() {
_dummyHead = new LinkedNode(0); // 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点
_size = 0;
}
// 获取到第index个节点数值,如果index是非法数值直接返回-1, 注意index是从0开始的,第0个节点就是头结点
int get(int index) {
if (index > (_size - 1) || index < 0) {
return -1;
}
LinkedNode* cur = _dummyHead->next;
while(index--){ // 如果--index 就会陷入死循环
cur = cur->next;
}
return cur->val;
}
// 在链表最前面插入一个节点,插入完成后,新插入的节点为链表的新的头结点
void addAtHead(int val) {
LinkedNode* newNode = new LinkedNode(val);
newNode->next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}
// 在链表最后面添加一个节点
void addAtTail(int val) {
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while(cur->next != nullptr){
cur = cur->next;
}
cur->next = newNode;
_size++;
}
// 在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
// 如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果index大于链表的长度,则返回空
// 如果index小于0,则在头部插入节点
void addAtIndex(int index, int val) {
if(index > _size) return;
if(index < 0) index = 0;
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while(index--) {
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
// 删除第index个节点,如果index 大于等于链表的长度,直接return,注意index是从0开始的
void deleteAtIndex(int index) {
if (index >= _size || index < 0) {
return;
}
LinkedNode* cur = _dummyHead;
while(index--) {
cur = cur ->next;
}
LinkedNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
_size--;
}
};
有空多练,经典链表操作。
24. 两两交换链表中的节点
https://leetcode.cn/problems/swap-nodes-in-pairs/
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
auto dummy = new ListNode();
dummy->next = head;
auto p = dummy;
while(p->next != NULL && p->next->next != NULL){
auto n1 = p->next, n2 = p->next->next;
n1->next = n2->next;
n2->next = n1;
p->next = n2;
p = n1;
}
return dummy->next;
}
};
主要是一个画图的问题,在图上理解清楚交换的逻辑就简单了。
160. 相交链表
https://leetcode.cn/problems/intersection-of-two-linked-lists/
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
auto a = headA, b = headB;
while(a != b){
a = a ? a->next : headB;
b = b ? b->next : headA;
}
return a;
}
};
做法很简单,但是想到不容易,把自己的跑完就去跑另外一个链表,最后相遇的时候距离相等刚好就是相交的节点。
142. 环形链表 II
https://leetcode.cn/problems/linked-list-cycle-ii/
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(!head || !head->next) return NULL;
auto s = head, f = head->next;
while(f->next && f->next->next){
s = s->next, f = f->next->next;
if(s == f){
s = head, f = f->next;
while(s != f){
s = s->next;
f = f->next;
}
return s;
}
}
return NULL;
}
};
画图才能解决,这道题比较绕,简单说就是到相遇点之后,让一个指针回 head 那个位置,然后两个指针以相同的速度重新跑,最后相遇点就是我们的答案。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
auto p = head, q = head;
while(q && q->next){
p = p->next;
q = q->next->next;
if(p == q) break;
}
if(!q || !q->next) return NULL;
p = head;
while(p != q){
p = p->next;
q = q->next;
}
return p;
}
};
更好的代码,可以看到,当快慢指针相遇时,让其中任一个指针指向头节点,然后让它俩以相同速度前进,再次相遇时所在的节点位置就是环开始的位置。
232. 用栈实现队列
https://leetcode.cn/problems/implement-queue-using-stacks/
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾 int pop() 从队列的开头移除并返回元素 int peek() 返回队列开头的元素 boolean empty() 如果队列为空,返回 true ;否则,返回 false 说明:
你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
Copy class MyQueue {
public:
stack<int> a, b;
MyQueue() {}
void push(int x) {
a.push(x);
}
int pop() {
while(a.size() > 1) b.push(a.top()), a.pop();
int t = a.top();
a.pop();
while(b.size()) a.push(b.top()), b.pop();
return t;
}
int peek() {
while(a.size() > 1) b.push(a.top()), a.pop();
int t = a.top();
while(b.size()) a.push(b.top()), b.pop();
return t;
}
bool empty() {
return a.empty();
}
};
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/
难点在于对 pop()
和 peek
的操作,用一个临时栈来存放最后一个值以外的元素,最后再将其打回即可。
Copy class MyQueue {
public:
stack<int> s1, s2;
MyQueue() {}
void push(int x) {
s2.push(x);
}
int pop() {
if(s1.empty()) {
while(!s2.empty()) {
s1.push(s2.top());
s2.pop();
}
}
int tmp = s1.top();
s1.pop();
return tmp;
}
int peek() {
if(s1.empty()) {
while(!s2.empty()) {
s1.push(s2.top());
s2.pop();
}
}
return s1.top();
}
bool empty() {
return s1.empty() && s2.empty();
}
};
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/
感觉更好理解。
225. 用队列实现栈
https://leetcode.cn/problems/implement-stack-using-queues/
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。 int pop() 移除并返回栈顶元素。 int top() 返回栈顶元素。 boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
注意:
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
Copy class MyStack {
public:
queue<int> a, b;
MyStack() {
}
void push(int x) {
a.push(x);
}
int pop() {
while(a.size() > 1) b.push(a.front()), a.pop();
int t = a.front();
a.pop();
while(b.size()) a.push(b.front()), b.pop();
return t;
}
int top() {
while(a.size() > 1) b.push(a.front()), a.pop();
int t = a.front();
a.pop();
while(b.size()) a.push(b.front()), b.pop();
a.push(t);
return t;
}
bool empty() {
return a.empty();
}
};
/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/
和上题类似。有一点点逻辑的不同,看代码就懂了。
1047. 删除字符串中的所有相邻重复项
https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
Copy class Solution {
public:
string removeDuplicates(string s) {
string res;
for(auto c : s){
if(res.size() && res.back() == c) res.pop_back();
else res += c;
}
return res;
}
};
用栈实现即可。
144. 二叉树的前序遍历
https://leetcode.cn/problems/binary-tree-preorder-traversal/
给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void traversal(TreeNode* cur, vector<int> &res){
if(!cur) return;
vec.push_back(cur->val);
traversal(cur->left, res);
traversal(cur->right, res);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
traversal(root, res);
return res;
}
};
递归即可。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> stk;
while(root || stk.size()){
while(root){
res.push_back(root->val);
stk.push(root);
root = root->left;
}
root = stk.top()->right;
stk.pop();
}
return res;
}
};
迭代法
145. 二叉树的后序遍历
https://leetcode.cn/problems/binary-tree-postorder-traversal/
给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void traversal(TreeNode *cur, vector<int>& res){
if(!cur) return;
traversal(cur->left, res);
traversal(cur->right, res);
res.push_back(cur->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
traversal(root, res);
return res;
}
};
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> stk;
while(root || stk.size()){
while(root){
res.push_back(root->val);
stk.push(root);
root = root->right;
}
root = stk.top()->left;
stk.pop();
}
reverse(res.begin(), res.end());
return res;
}
};
94. 二叉树的中序遍历
https://leetcode.cn/problems/binary-tree-inorder-traversal/
给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> stk;
while(root || stk.size()){
while(root){
stk.push(root);
root = root->left;
}
root = stk.top();
stk.pop();
res.push_back(root->val);
root = root->right;
}
return res;
}
};
102. 二叉树的层序遍历
https://leetcode.cn/problems/binary-tree-level-order-traversal/
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> q;
if(root) q.push(root);
while(q.size()){
vector<int> level;
int len = q.size();
while(len--){
auto t = q.front();
level.push_back(t->val);
q.pop();
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
res.push_back(level);
}
return res;
}
};
宽搜一下即可。
107. 二叉树的层序遍历 II
https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/
给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> q;
if(root) q.push(root);
while(q.size()){
vector<int> level;
int len = q.size();
while(len--){
auto t = q.front();
q.pop();
level.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
res.push_back(level);
}
reverse(res.begin(), res.end());
return res;
}
};
相较上一题,翻转一下即可。
199. 二叉树的右视图
https://leetcode.cn/problems/binary-tree-right-side-view/
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> res;
queue<TreeNode*> q;
if(root) q.push(root);
while(q.size()){
int len = q.size();
while(len--){
auto t = q.front();
q.pop();
if(!len) res.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
}
return res;
}
};
用宽搜,然后找到每一排最后一个即可。
104. 二叉树的最大深度
https://leetcode.cn/problems/maximum-depth-of-binary-tree/
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
int res = 0;
queue<TreeNode*> q;
if(root) q.push(root);
while(q.size()){
int len = q.size();
res++;
while(len--){
auto t = q.front();
q.pop();
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
}
return res;
}
};
一样的宽搜,每一层给结果加一即可。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int res = 0;
int depth = 0;
int maxDepth(TreeNode* root) {
dfs(root);
return res;
}
void dfs(TreeNode* root){
if(!root) return;
depth++;
if(!root->left && !root->right) res = max(res, depth);
dfs(root->left);
dfs(root->right);
depth--;
}
};
用迭代的方法做,更有普遍性。
111. 二叉树的最小深度
https://leetcode.cn/problems/minimum-depth-of-binary-tree/
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int minDepth(TreeNode* root) {
int res = 0;
queue<TreeNode*> q;
if(root) q.push(root);
while(q.size()){
int len = q.size();
res++;
while(len--){
auto t = q.front();
q.pop();
if(!t->left && !t->right) return res;
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
}
return res;
}
};
在上一题的基础上,只要遇到叶子结点就返回答案。
226. 翻转二叉树
https://leetcode.cn/problems/invert-binary-tree/
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(!root) return NULL;
swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}
};
递归翻转左右子树即可。
101. 对称二叉树
https://leetcode.cn/problems/symmetric-tree/
给你一个二叉树的根节点 root , 检查它是否轴对称。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(!root) return true;
return dfs(root->left, root->right);
}
bool dfs(TreeNode* left, TreeNode* right){
if(!left && !right) return true;
if(!left || !right || left->val != right->val) return false;
return dfs(left->right, right->left) && dfs(left->left, right->right);
}
};
爆搜左右两边,然后分别比较。
222. 完全二叉树的节点个数
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int countNodes(TreeNode* root) {
if(!root) return NULL;
int left = countNodes(root->left);
int right = countNodes(root->right);
return left + right + 1;
}
};
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int countNodes(TreeNode* root) {
int res = 0;
queue<TreeNode*> q;
if(root) q.push(root);
while(q.size()){
int len = q.size();
while(len--){
res++;
auto t = q.front();
q.pop();
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
}
return res;
}
};
两种暴力做法。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int countNodes(TreeNode* root) {
if(!root) return 0;
auto left = root->left, right = root->right;
int ld = 0, rd = 0;
while(left){
left = left->left;
ld++;
}
while(right){
right = right->right;
rd++;
}
if(ld == rd) return (2 << ld) - 1;
return countNodes(root->left) + countNodes(root->right) + 1;
}
};
更快的做法,利用了完全二叉树的性质。
110. 平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool ans;
bool isBalanced(TreeNode* root) {
ans = true;
dfs(root);
return ans;
}
int dfs(TreeNode* root){
if(!root) return 0;
int lh = dfs(root->left);
int rh = dfs(root->right);
if(abs(lh - rh) > 1) ans = false;
return max(lh, rh) + 1;
}
};
首先定义一个全局的变量保存答案,然后递归左右字数找到最深的点,取差的绝对值即可。
257. 二叉树的所有路径
给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<string> ans;
vector<int> path;
vector<string> binaryTreePaths(TreeNode* root) {
if(root) dfs(root);
return ans;
}
void dfs(TreeNode* root){
path.push_back(root->val);
if(!root->left && !root->right){
string line = to_string(path[0]);
for(int i = 1; i < path.size(); i++){
line += "->" + to_string(path[i]);
}
ans.push_back(line);
}else{
if(root->left) dfs(root->left);
if(root->right) dfs(root->right);
}
path.pop_back();
}
};
爆搜即可。
404. 左叶子之和
给定二叉树的根节点 root ,返回所有左叶子之和。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int res = 0;
int sumOfLeftLeaves(TreeNode* root) {
dfs(root);
return res;
}
void dfs(TreeNode* root){
if(!root) return;
if(root->left){
if(!root->left->left && !root->left->right) res += root->left->val;
}
dfs(root->left);
dfs(root->right);
}
};
爆搜即可。
513. 找树左下角的值
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
int res = 0;
queue<TreeNode*> q;
if(root) q.push(root);
while(q.size()){
int len = q.size();
vector<int> line;
while(len--){
auto t = q.front();
line.push_back(t->val);
q.pop();
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
res = line[0];
}
return res;
}
};
就爱层序遍历,别的咳嗽。
112. 路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool hasPathSum(TreeNode* root, int sum) {
if(!root) return false;
sum -= root->val;
if(!root->left && !root->right) return !sum;
return root->left && hasPathSum(root->left, sum) || root->right && hasPathSum(root->right, sum);
}
};
当是叶子结点且 sum = 0 时返回真即可。
654. 最大二叉树
https://leetcode.cn/problems/maximum-binary-tree/
给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:
创建一个根节点,其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums 构建的 最大二叉树 。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return dfs(nums, 0, nums.size() - 1);
}
TreeNode* dfs(vector<int>& nums, int l, int r){
if(l > r) return NULL;
int idx = l;
for(int i = l + 1; i <= r; i++){
if(nums[i] > nums[idx]) idx = i;
}
TreeNode *res = new TreeNode(nums[idx]);
res->left = dfs(nums, l, idx - 1);
res->right = dfs(nums, idx + 1, r);
return res;
}
};
直接按题目描述进行模拟即可。用递归函数 dfs(nums,l,r)dfs(nums,l,r) 表示对于 [numsl,numsr][numsl,numsr]
区间构建一棵树。具体如下:找到 [numsl,numsr][numsl,numsr]
区间内的最大值,记为 numsidnumsid,这个数字就是根节点的值。分别递归左右子树:dfs(nums,l,id−1)dfs(nums,l,id−1) 和 dfs(nums,id+1,r)dfs(nums,id+1,r)。
617. 合并二叉树
https://leetcode.cn/problems/merge-two-binary-trees/submissions/
给你两棵二叉树: root1 和 root2 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if(root2) swap(root1, root2);
if(!root1) return NULL;
if(root2) root1->val += root2->val;
root1->left = mergeTrees(root1->left, root2 ? root2->left : NULL);
root1->right = mergeTrees(root1->right, root2 ? root2->right : NULL);
return root1;
}
};
首先让 root1 一定存在,接着 root2 也存在就将值相加,最后遍历左右儿子即可。
98. 验证二叉搜索树
https://leetcode.cn/problems/validate-binary-search-tree/
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isValidBST(TreeNode* root) {
if(!root) return true;
return bfs(root)[0];
}
vector<int> bfs(TreeNode* root){
vector<int> res{1, root->val, root->val};
if(root->left){
auto t = bfs(root->left);
if(!t[0] || t[2] >= root->val) res[0] = 0;
res[1] = min(t[1], res[1]);
res[2] = max(t[2], res[2]);
}
if(root->right){
auto t = bfs(root->right);
if(!t[0] || t[1] <= root->val) res[0] = 0;
res[1] = min(t[1], res[1]);
res[2] = max(t[2], res[2]);
}
return res;
}
};
用一个数组存三个信息,一个是是否有问题,一个是最大值,一个是最小值,然后深搜即可。
530. 二叉搜索树的最小绝对差
https://leetcode.cn/problems/minimum-absolute-difference-in-bst/
给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool is_first = true;
int res = INT_MAX, last;
int getMinimumDifference(TreeNode* root) {
dfs(root);
return res;
}
void dfs(TreeNode* root){
if(!root) return;
dfs(root->left);
if(is_first) is_first = false;
else res = min(res, root->val - last);
last = root->val;
dfs(root->right);
}
};
深搜对比一下即可,首先如果是第一次进行深搜,此时没有 last ,将 is_first 置为 false,并写入 last 即可。通过中序遍历维护答案,
236. 二叉树的最近公共祖先
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
Copy /**
* 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:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root || root == p || root == q) return root;
auto left = lowestCommonAncestor(root->left, p, q);
auto right = lowestCommonAncestor(root->right, p, q);
if(!left) return right;
if(!right) return left;
return root;
}
};
左边为空,三种情况,右边为空一样的,两边都不为空,那么肯定一边一个返回根节点即可。
450. 删除二叉搜索树中的节点
https://leetcode.cn/problems/delete-node-in-a-bst/
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
del(root, key);
return root;
}
void del(TreeNode* &root, int key){
if(!root) return;
if(root->val == key){
if(!root->left && !root->right) root = NULL;
else if(!root->left) root = root->right;
else if(!root->right) root = root->left;
else {
auto p = root->right;
while(p->left) p = p->left;
root->val = p->val;
del(root->right, p->val);
}
}
else if(root->val > key) del(root->left, key);
else del(root->right, key);
}
};
分三种情况删除即可。
86. 分隔链表
https://leetcode.cn/problems/partition-list/
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
auto dummy1 = new ListNode(), dummy2 = new ListNode();
auto p1 = dummy1, p2 = dummy2;
while(head){
if(head->val >= x) p2 = p2->next = head;
else p1 = p1->next = head;
head = head->next;
}
p2->next = NULL;
p1->next = dummy2->next;
return dummy1->next;
}
};
与合并链表类似,这里需要创建两个虚拟头结点,除此之外我们需要在最后通过 p2->next = NULL 来切断他后面的指向。
23. 合并 K 个升序链表
https://leetcode.cn/problems/merge-k-sorted-lists/
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
struct Cmp {
bool operator()(ListNode* a, ListNode* b) {
return a->val > b->val;
}
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
auto dummy = new ListNode(), p = dummy;
priority_queue<ListNode*, vector<ListNode*>, Cmp> heap;
for(auto h : lists) if(h) heap.push(h);
while(heap.size()) {
auto t = heap.top();
heap.pop();
p = p->next = t;
if(t->next) heap.push(t->next);
}
return dummy->next;
}
};
通过一个优先队列小根堆来实现,其中我们需要有一个 Cmp 比较函数,背过即可。
543. 二叉树的直径
https://leetcode.cn/problems/diameter-of-binary-tree/
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int res = 0;
int diameterOfBinaryTree(TreeNode* root) {
dfs(root);
return res;
}
int dfs(TreeNode* root) {
if(!root) return 0;
int l = dfs(root->left);
int r = dfs(root->right);
res = max(res, l + r);
return max(l, r) + 1;
}
};
前序位置无法获取子树信息,所以只能让每个节点调用 dfs 函数去算子树的深度。 我们应该把计算「直径」的逻辑放在后序位置,准确说应该是放在 dfs 的后序位置,因为 dfs 的后序位置是知道左右子树的最大深度的。
105. 从前序与中序遍历序列构造二叉树
https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return dfs(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);
}
TreeNode* dfs(vector<int>& preorder, int pst, int ped, vector<int>& inorder, int ist, int ied) {
if(pst > ped) return NULL;
int val = preorder[pst], idx = -1;
auto root = new TreeNode(val);
for(int i = ist; i <= ied; i++) {
if(inorder[i] == val) {
idx = i;
break;
}
}
root->left = dfs(preorder, pst + 1, pst + idx - ist, inorder, ist, idx - 1);
root->right = dfs(preorder, pst + idx - ist + 1, ped, inorder, idx + 1, ied);
return root;
}
};
注意画图来分析递归时的参数设计。
155. 最小栈
https://leetcode.cn/problems/min-stack/
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
MinStack() 初始化堆栈对象。 void push(int val) 将元素 val 推入堆栈。 void pop() 删除堆栈顶部的元素。 int top() 获取堆栈顶部的元素。 int getMin() 获取堆栈中的最小元素。
Copy class MinStack {
public:
stack<int> s;
stack<int> t;
MinStack() {
t.push(INT_MAX);
}
void push(int val) {
s.push(val);
t.push(min(t.top(), val));
}
void pop() {
s.pop();
t.pop();
}
int top() {
return s.top();
}
int getMin() {
return t.top();
}
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(val);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/
用一个辅助栈来进行实现就行。
946. 验证栈序列
https://leetcode.cn/problems/validate-stack-sequences/
Copy class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
stack<int> stk;
int n = pushed.size();
for(int i = 0, j = 0; i < n; i++) {
stk.push(pushed[i]);
while(!stk.empty() && stk.top() == popped[j]) {
stk.pop();
j++;
}
}
return stk.empty();
}
};
模拟一下。
230. 二叉搜索树中第 K 小的元素
https://leetcode.cn/problems/kth-smallest-element-in-a-bst/
给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int res = 0, idx = 0;
int kthSmallest(TreeNode* root, int k) {
dfs(root, k);
return res;
}
void dfs(TreeNode* root, int k) {
if(!root) return;
dfs(root->left, k);
idx++;
if(idx == k) {
res = root->val;
return;
}
dfs(root->right, k);
}
};
中序遍历即可。
146. LRU 缓存
https://leetcode.cn/problems/lru-cache/
请你设计并实现一个满足 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) 的平均时间复杂度运行。
Copy class LRUCache {
public:
struct Node {
int val, key;
Node *left, *right;
Node(int _key, int _val): key(_key), val(_val), left(NULL), right(NULL) {}
}*L, *R;
unordered_map<int, Node*> hash;
int n;
void remove(Node* p) {
p->left->right = p->right;
p->right->left = p->left;
}
void insert(Node* p) {
p->left = L;
p->right = L->right;
L->right->left = p;
L->right = p;
}
LRUCache(int capacity) {
n = capacity;
L = new Node(-1, -1), R = new Node(-1, -1);
L->right = R, R->left = L;
}
int get(int key) {
if(hash.count(key) == 0) return -1;
auto p = hash[key];
remove(p);
insert(p);
return p->val;
}
void put(int key, int value) {
if(hash.count(key)) {
auto p = hash[key];
p->val = value;
remove(p);
insert(p);
} else {
if(hash.size() == n) {
auto p = R->left;
remove(p);
hash.erase(p->key);
delete(p);
}
auto p = new Node(key, value);
hash[key] = p;
insert(p);
}
}
};
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/
25. K 个一组翻转链表
https://leetcode.cn/problems/reverse-nodes-in-k-group/
给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if(!head) return head;
auto a = head, b = head;
for(int i = 0; i < k; i++) {
if(b == NULL) return head;
b = b->next;
}
auto newHead = reverseNode(a, b);
a->next = reverseKGroup(b, k);
return newHead;
}
ListNode* reverseNode(ListNode* n, ListNode* m) {
auto a = n, b = n->next;
while(b != m) {
auto t = b->next;
b->next = a;
a = b;
b = t;
}
n->next = m;
return a;
}
};
103. 二叉树的锯齿形层序遍历
https://leetcode.cn/problems/binary-tree-zigzag-level-order-traversal/
给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> q;
int cnt = 0;
if(root) q.push(root);
while(q.size()) {
int len = q.size();
vector<int> path;
while(len--) {
auto t = q.front();
q.pop();
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
path.push_back(t->val);
}
if(cnt % 2) reverse(path.begin(), path.end());
res.push_back(path);
cnt++;
}
return res;
}
};
层序遍历加一个隔一行翻转即可。
92. 反转链表 II
https://leetcode.cn/problems/reverse-linked-list-ii/
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
if(left == right || !head) return head;
auto dummy = new ListNode();
dummy->next = head;
auto p = dummy;
for(int i = 0; i < left - 1; i++) p = p->next;
auto a = p, b = a->next, c = b->next;
for(int i = 0; i < right -left; i++) {
auto t = c->next;
c->next = b;
b = c;
c = t;
}
a->next->next = c;
a->next = b;
return dummy->next;
}
};
124. 二叉树中的最大路径和
https://leetcode.cn/problems/binary-tree-maximum-path-sum/
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和 。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int res;
int maxPathSum(TreeNode* root) {
res = INT_MIN;
dfs(root);
return res;
}
int dfs(TreeNode* root) {
if(!root) return 0;
int l = max(0, dfs(root->left)), r = max(0, dfs(root->right));
res = max(res, root->val + l + r);
return root->val + max(l, r);
}
};
56. 合并区间
https://leetcode.cn/problems/merge-intervals/
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
Copy class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> res;
if(intervals.empty()) return res;
sort(intervals.begin(), intervals.end());
int l = intervals[0][0], r = intervals[0][1];
for(int i = 1; i < intervals.size(); i++) {
if(intervals[i][0] > r) {
res.push_back({l, r});
l = intervals[i][0], r = intervals[i][1];
}else r = max(r, intervals[i][1]);
}
res.push_back({l, r});
return res;
}
};
148. 排序链表
https://leetcode.cn/problems/sort-list/
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
int n = 0;
for(auto p = head; p; p = p->next) n++;
auto dummy = new ListNode();
dummy->next = head;
for(int i = 1; i < n; i *= 2) {
auto cur = dummy;
for(int j = 1; j + i <= n; j += 2 * i) {
auto p = cur->next, q = p;
for(int k = 0; k < i; k++) q = q->next;
int l = 0, r = 0;
while(l < i && r < i && p && q) {
if(p->val < q->val) cur = cur->next = p, p = p->next, l++;
else cur = cur->next = q, q = q->next, r++;
}
while(l < i && p) cur = cur->next = p, p = p->next, l++;
while(r < i && q) cur = cur->next = q, q = q->next, r++;
cur->next = q;
}
}
return dummy->next;
}
};
82. 删除排序链表中的重复元素 II
https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/
给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head) return head;
auto dummy = new ListNode();
dummy->next = head;
auto p = dummy;
while(p->next) {
auto q = p->next->next;
while(q && q->val == p->next->val) q = q->next;
if(q == p->next->next) p = p->next;
else p->next = q;
}
return dummy->next;
}
};
2. 两数相加
https://leetcode.cn/problems/add-two-numbers/
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
auto dummy = new ListNode(), q = dummy;
int t = 0;
while(l1 || l2 || t) {
if(l1) t += l1->val, l1 = l1->next;
if(l2) t += l2->val, l2 = l2->next;
q = q->next = new ListNode(t % 10);
t /= 10;
}
return dummy->next;
}
};
8. 字符串转换整数 (atoi)
https://leetcode.cn/problems/string-to-integer-atoi/
请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
函数 myAtoi(string s) 的算法如下:
读入字符串并丢弃无用的前导空格 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。 如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。 返回整数作为最终结果。 注意:
本题中的空白字符只包括空格字符 ' ' 。 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
Copy class Solution {
public:
int myAtoi(string s) {
int n = s.size(), i = 0, flag = 1;
long long res = 0;
while(i < n && s[i] == ' ') i++;
if(s[i] == '-') flag = -1, i++;
else if(s[i] == '+') i++;
while(i < n && s[i] >= '0' && s[i] <= '9') {
res = res * 10 + s[i] - '0';
if(res > INT_MAX) break;
i++;
}
if((int)res != res) return flag == 1 ? INT_MAX : INT_MIN;
return res * flag;
}
};
239. 滑动窗口最大值
https://leetcode.cn/problems/sliding-window-maximum/
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
Copy class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> q;
vector<int> res;
for(int i = 0; i < nums.size(); i++) {
if(q.size() && i - k + 1 > q.front()) q.pop_front();
while(q.size() && nums[i] >= nums[q.back()]) q.pop_back();
q.push_back(i);
if(i >= k - 1) res.push_back(nums[q.front()]);
}
return res;
}
};
41. 缺失的第一个正数
https://leetcode.cn/problems/first-missing-positive/
Copy class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n = nums.size();
for(auto& x : nums) if(x != INT_MIN) x--;
for(int i = 0; i < n; i++) while(nums[i] >= 0 && nums[i] < n && nums[i] != i && nums[i] != nums[nums[i]]) swap(nums[i], nums[nums[i]]);
for(int i = 0; i < n; i++) if(nums[i] != i) return i + 1;
return n + 1;
}
};
234. 回文链表
https://leetcode.cn/problems/palindrome-linked-list/
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
auto slow = head, fast = head;
while(fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
if(fast) slow = slow->next;
auto left = head, right = reverseList(slow);
while(right) {
if(left->val != right->val) return false;
left = left->next;
right = right->next;
}
return true;
}
ListNode* reverseList(ListNode* head) {
if(!head) return NULL;
auto a = head, b = a->next;
while(b){
auto tmp = b->next;
b->next = a;
a = b;
b = tmp;
}
head->next = NULL;
return a;
}
};
394. 字符串解码
https://leetcode.cn/problems/decode-string/
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
Copy class Solution {
public:
string decodeString(string s) {
int u = 0;
return dfs(s, u);
}
string dfs(string& s, int& u) {
string res;
while(u < s.size() && s[u] != ']') {
if(s[u] >= 'a' && s[u] <= 'z' || s[u] >= 'A' && s[u] <= 'Z') res += s[u++];
else if(s[u] >= '0' && s[u] <= '9') {
int k = u;
while(s[k] >= '0' && s[k] <= '9') k++;
int x = stoi(s.substr(u, k - u));
u = k + 1;
string y = dfs(s, u);
u++;
while(x--) res += y;
}
}
return res;
}
};
14. 最长公共前缀
https://leetcode.cn/problems/longest-common-prefix/
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。
Copy class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
string res;
if(strs.empty()) return res;
for(int i = 0;; i++) {
if(i >= strs[0].size()) return res;
auto c = strs[0][i];
for(auto str : strs) if(i >= str.size() || c != str[i]) return res;
res += c;
}
return res;
}
};
662. 二叉树最大宽度
https://leetcode.cn/problems/maximum-width-of-binary-tree/
给你一棵二叉树的根节点 root ,返回树的 最大宽度 。
树的 最大宽度 是所有层中最大的 宽度 。
每一层的 宽度 被定义为该层最左和最右的非空节点(即,两个端点)之间的长度。将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 null 节点,这些 null 节点也计入长度。
题目数据保证答案将会在 32 位 带符号整数范围内。
Copy /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int widthOfBinaryTree(TreeNode* root) {
if(!root) return 0;
queue<pair<TreeNode*, int>> q;
q.push({root, 1});
int res = 1;
while(q.size()) {
int len = q.size();
int l = q.front().second, r;
while(len--) {
auto t = q.front();
q.pop();
auto t1 = t.first;
auto p = t.second - l + 1;
r = t.second;
if(t1->left) q.push({t1->left, p * 2ll});
if(t1->right) q.push({t1->right, p * 2ll + 1});
}
res = max(res, r - l + 1);
}
return res;
}
};
739. 每日温度
https://leetcode.cn/problems/daily-temperatures/
给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。
Copy class Solution {
public:
vector<int> dailyTemperatures(vector<int>& t) {
int n = t.size();
vector<int> res(n);
stack<int> s;
for(int i = n - 1; i >= 0; i--) {
while(s.size() && t[s.top()] <= t[i]) s.pop();
res[i] = s.empty() ? 0 : (s.top() - i);
s.push(i);
}
return res;
}
};
227. 基本计算器 II
https://leetcode.cn/problems/basic-calculator-ii/
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。
Copy class Solution {
public:
stack<int> num;
stack<char> op;
int calculate(string s) {
unordered_map<char, int> pr;
pr['+'] = pr['-'] = 1;
pr['*'] = pr['/'] = 2;
for(int i = 0; i < s.size(); i++) {
char c = s[i];
if(c == ' ') continue;
if(isdigit(c)) {
int res = 0, j = i;
while(j < s.size() && isdigit(s[j])) res = res * 10 + (s[j++] - '0');
num.push(res);
i = j - 1;
} else {
while(op.size() && pr[op.top()] >= pr[c]) eval();
op.push(c);
}
}
while(op.size()) eval();
return num.top();
}
void eval() {
int res;
int b = num.top(); num.pop();
int a = num.top(); num.pop();
char c = op.top(); op.pop();
if(c == '+') res = a + b;
else if(c == '-') res = a - b;
else if(c == '*') res = a * b;
else res = a / b;
num.push(res);
}
};
179. 最大数
https://leetcode.cn/problems/largest-number/
给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
Copy class Solution {
public:
string largestNumber(vector<int>& nums) {
sort(nums.begin(), nums.end(), [](int x, int y) {
string a = to_string(x), b = to_string(y);
return a + b > b + a;
});
string res;
for(auto num : nums) res += to_string(num);
if(res[0] == '0') return "0";
return res;
}
};
138. 复制带随机指针的链表
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。
返回复制链表的头节点。
Copy /*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
*/
class Solution {
public:
Node* copyRandomList(Node* head) {
unordered_map<Node*, Node*> h;
for(auto p = head; p; p = p->next) if(!h.count(p)) h[p] = new Node(p->val);
for(auto p = head; p; p = p->next) {
if(p->next) h[p]->next = h[p->next];
if(p->random) h[p]->random = h[p->random];
}
return h[head];
}
};
61. 旋转链表
https://leetcode.cn/problems/rotate-list/
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if(!head) return head;
int n = 0;
ListNode* tail;
for(auto p = head; p; p = p->next) {
tail = p;
n++;
}
k %= n;
if(!k) return head;
auto p = head;
for(int i = 0; i < n - k - 1; i++) p = p->next;
tail->next = head;
head = p->next;
p->next = NULL;
return head;
}
};
402. 移掉 K 位数字
https://leetcode.cn/problems/remove-k-digits/
给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。
Copy class Solution {
public:
string removeKdigits(string num, int k) {
string res;
for(int x : num) {
while(res.size() > 0 && x < res.back() && k > 0) res.pop_back(), k--;
res.push_back(x);
}
while(k > 0) res.pop_back(), k--;
int n = res.size(), i = 0;
while(res[i] == '0') i++;
return n - i == 0 ? "0" : res.substr(i, n - i);
}
};
143. 重排链表
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
Copy /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
void reorderList(ListNode* head) {
auto mid = findMid(head);
auto l1 = head;
auto l2 = mid->next;
mid->next = NULL;
l2 = reverseList(l2);
mergeList(l1, l2);
}
ListNode* findMid(ListNode* head) {
auto slow = head, fast = head;
while(fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
ListNode* reverseList(ListNode* head) {
if(!head || !head->next) return head;
auto a = head, b = head->next;
while(b) {
auto t = b->next;
b->next = a;
a = b;
b = t;
}
head->next = NULL;
return a;
}
void mergeList(ListNode* l1, ListNode* l2) {
while (l1 && l2) {
auto a = l1->next;
auto b = l2->next;
l1->next = l2;
l1 = a;
l2->next = l1;
l2 = b;
}
}
};