class Solution {
public:
int TreeDepth(TreeNode* root) {
if (root == NULL) return 0;
return max(TreeDepth(root->left), TreeDepth(root->right)) + 1;
}
};
二叉树的宽度
思路
层序遍历(队列)
C++
class Solution {
public:
int widthOfBinaryTree(TreeNode* root) {
if (root == nullptr)
return 0;
queue<TreeNode*> Q;
Q.push(root);
int ans = 1;
while(!Q.empty()) {
int cur_w = Q.size(); // 当前层的宽度
ans = max(ans, cur_w);
for (int i=0; i<cur_w; i++) {
auto p = Q.front();
Q.pop();
if (p->left)
Q.push(p->left);
if (p->right)
Q.push(p->right);
}
}
return ans;
}
};
class Solution: def rotateRight(self, h, k): """ :type h: ListNode :type k: int :rtype: ListNode """ if not h or k == 0: return h
n = 1 # 记录链表的长度,因为只遍历到最后一个非空节点,所以从 1 开始
l = h
r = h # tail
while r.next is not None and k > 0:
k -= 1
n += 1
r = r.next
# print(k, n)
if k > 0:
k -= 1 # 这里要先减 1,因为 n 是从 1 开始计数的
k = k % n
r = h
while k > 0:
k -= 1
r = r.next
# 找到倒数第 k 个节点
while r.next is not None:
l = l.next
r = r.next
r.next = h
h = l.next
l.next = None
return h
**代码 2**
- 代码量少一点,但是遍历的长度要多一点。
```python
class Solution:
def rotateRight(self, h, k):
"""
:type h: ListNode
:type k: int
:rtype: ListNode
"""
if not h or k == 0:
return h
n = 1 # 记录链表的长度,因为只遍历到最后一个非空节点,所以从 1 开始
r = h # tail
while r.next is not None:
n += 1
r = r.next
r.next = h # 构成环
k %= n
t = n - k
while t > 0:
r = r.next
t -= 1
h = r.next
r.next = None # 断开 链表
return h
反转链表
题目描述
输入一个链表,反转链表后,输出新链表的表头。
要求:不使用额外空间
思路
辅助图示思考
Code(迭代)
class Solution {
public:
ListNode * ReverseList(ListNode* head) {
if (head == nullptr)
return nullptr;
ListNode* cur = head; // 当前节点
ListNode* pre = nullptr; // 前一个节点
ListNode* nxt = cur->next; // 下一个节点
cur->next = nullptr; // 断开当前节点及下一个节点(容易忽略的一步)
while (nxt != nullptr) {
pre = cur; // 把前一个节点指向当前节点
cur = nxt; // 当前节点向后移动
nxt = nxt->next; // 下一个节点向后移动
cur->next = pre; // 当前节点的下一个节点指向前一个节点
}
return cur;
}
};
Code(递归)
class Solution {
public:
ListNode * ReverseList(ListNode* head) {
if (head == nullptr || head->next == nullptr)
return head;
auto nxt = head->next;
head->next = nullptr; // 断开当前节点及下一个节点
auto new_head = ReverseList(nxt);
nxt->next = head;
return new_head;
}
};
合并排序链表
问题描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
迭代
class Solution {
public:
ListNode* Merge(ListNode* p1, ListNode* p2) {
if (p1 == nullptr) return p2;
if (p2 == nullptr) return p1;
// 选择头节点
ListNode* head = nullptr;
if (p1->val <= p2->val) {
head = p1;
p1 = p1->next;
} else {
head = p2;
p2 = p2->next;
}
auto cur = head;
while (p1 && p2) {
if (p1->val <= p2->val) {
cur->next = p1;
p1 = p1->next;
} else {
cur->next = p2;
p2 = p2->next;
}
cur = cur->next;
}
// 别忘了拼接剩余部分
// if (p1) cur->next = p1;
// if (p2) cur->next = p2;
if (p1) {
cur->next = p1;
} else if (p2) {
cur->next = p2;
} else {
cur->next = nullptr;
}
return head;
}
};
递归
class Solution {
public:
ListNode* Merge(ListNode* p1, ListNode* p2){
if (!p1) return p2;
if (!p2) return p1;
if (p1->val <= p2->val) {
p1->next = Merge(p1->next, p2);
return p1;
} else {
p2->next = Merge(p1, p2->next);
return p2;
}
}
};
class Solution {
public:
ListNode* insertionSortList(ListNode* h) {
if (h == nullptr || h->next == nullptr)
return h;
// 因为是链表,所以可以重新开一个新的链表来保存排序好的部分;
// 不存在空间上的问题,这一点不像数组
auto H = new ListNode(0);
auto pre = H;
auto cur = h;
ListNode* nxt;
while (cur) {
while (pre->next && pre->next->val < cur->val) {
pre = pre->next;
}
nxt = cur->next; // 记录下一个要遍历的节点
// 把 cur 插入 pre 和 pre->next 之间
cur->next = pre->next;
pre->next = cur;
// 重新下一轮
pre = H;
cur = nxt;
}
h = H->next;
delete H;
return h;
}
};
代码 2 - 原地
即不使用新链表,逻辑与数组一致;
此时链表拼接的逻辑会复杂一些
class Solution {
public:
ListNode* insertionSortList(ListNode* h) {
if (h == nullptr || h->next == nullptr)
return h;
auto beg = new ListNode(0);
beg->next = h;
auto end = h; // (beg, end] 指示排好序的部分
auto p = h->next; // 当前待排序的节点
while (p) {
auto pre = beg;
auto cur = beg->next; // p 将插入到 pre 和 cur 之间
while (cur != p && p->val >= cur->val) {
cur = cur->next;
pre = pre->next;
}
if (cur == p) {
end = p;
} else {
end->next = p->next;
p->next = cur;
pre->next = p;
}
p = end->next;
}
h = beg->next;
delete beg;
return h;
}
};
链表选择排序
思路
见代码注释
时间复杂度:最好/最坏 O(N^2)
C++
class Solution {
public:
ListNode* sortList(ListNode* h) {
if (h == nullptr || h->next == nullptr)
return h;
auto H = new ListNode(0); // 为了操作方便,添加一个头结点
H->next = h;
auto s = h; // 指向已经排好序的尾部
ListNode* m; // 指向未排序部分的最小节点 min
ListNode* p; // 迭代器
while (s->next) {
m = s;
p = s->next;
while (p) { // 寻找剩余部分的最小节点
if (p->val < m->val)
m = p;
p = p->next;
}
swap(s->val, m->val); // 交换节点内的值
s = s->next;
}
h = H->next;
delete H;
return h;
}
};
class Solution {
public:
bool searchMatrix(vector<vector<int>>& M, int t) {
if (M.size() < 1 || M[0].size() < 1)
return false;
int m = M.size();
int n = M[0].size();
int lo = 0;
int hi = m * n;
while (lo + 1 < hi) {
int mid = lo + (hi - lo) / 2;
if (M[mid / n][mid % n] > t) {
hi = mid;
} else {
lo = mid;
}
}
return M[lo / n][lo % n] == t;
}
};
搜索二维矩阵 2
思路
1)从右上角开始查找,时间复杂度 O(M+N)
2)每一行二分查找,时间复杂度 O(MlogN)
class Solution {
public:
bool searchMatrix(vector<vector<int>>& M, int t) {
if (M.size() < 1 || M[0].size() < 1)
return false;
auto m = M.size();
auto n = M[0].size();
int row = 0;
int col = n - 1;
while(row <= m - 1 && col >= 0) {
if (M[row][col] < t)
row++;
else if (M[row][col] > t)
col--;
else
return true;
}
return false;
}
};
打印二维数组
回形打印
蛇形打印
堆
堆的调整(自上而下)
栈
用两个栈模拟队列
题目描述
用两个栈来实现一个队列,完成队列的 Push 和 Pop 操作。
思路
假设 stack_in 用于处理入栈操作,stack_out用于处理出栈操作
stack_in 按栈的方式正常处理入栈数据;
关键在于出栈操作
当stack_out为空时,需要先将每个stack_in中的数据出栈后压入stack_out
反之,每次弹出stack_out栈顶元素即可
Code(C++)
class Solution {
stack<int> stack_in;
stack<int> stack_out;
public:
void push(int node) {
stack_in.push(node);
}
int pop() {
if(stack_out.size() <= 0) {
while (stack_in.size() > 0) {
auto tmp = stack_in.top();
stack_in.pop();
stack_out.push(tmp);
}
}
auto ret = stack_out.top();
stack_out.pop();
return ret;
}
};