《剑指Offer》第23-33题
AcWing 35. 反转链表
定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。
思考题:
请同时实现迭代版本和递归版本。
样例
输入:1->2->3->4->5->NULL
输出:5->4->3->2->1->NULL
递推
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
p = head
pre = None
while p != None:
temp = p.next
p.next = pre
pre = p
p = temp
return pre
递归
先我们先考虑 reverseList 函数能做什么,它可以翻转一个链表,并返回新链表的头节点,也就是原链表的尾节点。
所以我们可以先递归处理 reverseList(head->next),这样我们可以将以head->next为头节点的链表翻转,并得到原链表的尾节点tail,此时head->next是新链表的尾节点,我们令它的next指针指向head,并将head->next指向空即可将整个链表翻转,且新链表的头节点是tail。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (!head || !head->next) return head;
ListNode *tail = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return tail;
}
};
AcWing 36. 合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。
样例
输入:1->3->5 , 2->4->5
输出:1->2->3->4->5->5
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def merge(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
head = ListNode(0)
p = head
while l1 != None and l2 != None:
if l1.val < l2.val:
p.next = l1
l1 = l1.next
else:
p.next = l2
l2 = l2.next
p = p.next
if l1 != None:
p.next = l1
else:
p.next = l2
'''
while l1 != None:
temp = ListNode(l1.val)
p.next = temp
p = p.next
l1 = l1.next
while l2 != None:
temp = ListNode(l2.val)
p.next = temp
p = p.next
l2 = l2.next
p.next = None
'''
return head.next
AcWing 37. 树的子结构
输入两棵二叉树A,B,判断B是不是A的子结构。
我们规定空树不是任何树的子结构。
样例
返回 true ,因为B是A的子结构。
算法
(二叉树,递归) O(nm)
代码分为两个部分:
- 遍历树A中的所有非空节点R;
- 判断树A中以R为根节点的子树是不是包含和树B一样的结构,且我们从根节点开始匹配;
对于第一部分,我们直接递归遍历树A即可,遇到非空节点后,就进行第二部分的判断。
对于第二部分,我们同时从根节点开始遍历两棵子树:
- 如果树B中的节点为空,则表示当前分支是匹配的,返回true;
- 如果树A中的节点为空,但树B中的节点不为空,则说明不匹配,返回false;
如果两个节点都不为空,但数值不同,则说明不匹配,返回false;
否则说明当前这个点是匹配的,然后递归判断左子树和右子树是否分别匹配即可;
时间复杂度
最坏情况下,我们对于树A中的每个节点都要递归判断一遍,每次判断在最坏情况下需要遍历完树B中的所有节点。
所以时间复杂度是 O(nm),其中 n 是树A中的节点数, m 是树B中的节点数。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def dfs(self, pRoot1, pRoot2):
if pRoot2 == None:
return True
if pRoot1 == None or pRoot1.val != pRoot2.val:
return False
return self.dfs(pRoot1.left, pRoot2.left) and self.dfs(pRoot1.right, pRoot2.right)
def hasSubtree(self, pRoot1, pRoot2):
"""
:type pRoot1: TreeNode
:type pRoot2: TreeNode
:rtype: bool
"""
if pRoot1 == None or pRoot2 == None:
return False
if self.dfs(pRoot1, pRoot2) == True:
return True
return self.hasSubtree(pRoot1.left, pRoot2) or self.hasSubtree(pRoot1.right, pRoot2)
AcWing 38. 二叉树的镜像
输入一个二叉树,将它变换为它的镜像。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def dfs(self, root):
if root.left :self.dfs(root.left)
if root.right :self.dfs(root.right)
root.left, root.right = root.right, root.left
def mirror(self, root):
"""
:type root: TreeNode
:rtype: void
"""
if root != None:
self.dfs(root)
AcWing 39. 对称的二叉树
请实现一个函数,用来判断一棵二叉树是不是对称的。
如果一棵二叉树和它的镜像一样,那么它是对称的。
样例
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def dfs(self, p, q):
if p == None or q ==None:
return p == None and q == None
return p.val == q.val and self.dfs(p.left, q.right) and self.dfs(p.right, q.left)
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
if root == None :
return True
return self.dfs(root.left, root.right)
AcWing 40. 顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
样例
输入:
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12]
]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
class Solution(object):
def printMatrix(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[int]
"""
n = len(matrix)
if n == 0:
return []
m = len(matrix[0])
st = [[0] * m for _ in range(n)]
res = []
dx = [0, 1, 0, -1]
dy = [1, 0, -1, 0]
x = 0
y = -1
i = 0
while len(res) < n * m :
x1 = x + dx[i]
y1 = y + dy[i]
if x1 < n and x1 >= 0 and y1 < m and y1 >= 0 and st[x1][y1] == 0:
st[x1][y1] = 1
x = x1
y = y1
res.append(matrix[x1][y1])
else:
i = (i + 1) % 4
# print(x, y, i, matrix[x][y])
return res
AcWing 41. 包含min函数的栈
设计一个支持push,pop,top等操作并且可以在O(1)时间内检索出最小元素的堆栈。
push(x)–将元素x插入栈中
pop()–移除栈顶元素
top()–得到栈顶元素
getMin()–得到栈中最小元素
样例
MinStack minStack = new MinStack();
minStack.push(-1);
minStack.push(3);
minStack.push(-4);
minStack.getMin(); --> Returns -4.
minStack.pop();
minStack.top(); --> Returns 3.
minStack.getMin(); --> Returns -1.
直接维护一个单调栈来做
class MinStack(object):
def __init__(self):
"""
initialize your data structure here.
"""
self.stk = []
def push(self, x):
"""
:type x: int
:rtype: void
"""
self.stk.append(x)
def pop(self):
"""
:rtype: void
"""
self.stk.pop()
def top(self):
"""
:rtype: int
"""
return self.stk[-1]
def getMin(self):
"""
:rtype: int
"""
return min(self.stk)
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
class MinStack {
public:
/** initialize your data structure here. */
stack<int> stackValue;
stack<int> stackMin;
MinStack() {
}
void push(int x) {
stackValue.push(x);
if (stackMin.empty() || stackMin.top() >= x)
stackMin.push(x);
}
void pop() {
if (stackMin.top() == stackValue.top()) stackMin.pop();
stackValue.pop();
}
int top() {
return stackValue.top();
}
int getMin() {
return stackMin.top();
}
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
AcWing 42. 栈的压入、弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。
假设压入栈的所有数字均不相等。
例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
注意:若两个序列长度不等则视为并不是一个栈的压入、弹出序列。若两个序列都为空,则视为是一个栈的压入、弹出序列。
样例
输入:
[1,2,3,4,5]
[4,5,3,2,1]输出:true
class Solution(object):
def isPopOrder(self, pushV, popV):
"""
:type pushV: list[int]
:type popV: list[int]
:rtype: bool
"""
i = 0
j = 0
stk = []
while i < len(pushV):
stk.append(pushV[i])
while j < len(popV) and len(stk) > 0 and stk[-1] == popV[j]:
j += 1
stk.pop()
i += 1
return j == len(popV) and len(stk) == 0
AcWing 43. 不分行从上往下打印二叉树
从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def bfs(self, root):
res = []
q = [0 for i in range(10005)]
hh = 0
tt = -1
tt += 1
q[tt] = root
while hh <= tt:
t = q[hh]
hh += 1
res.append(t.val)
if t.left != None:
tt += 1
q[tt] = t.left
if t.right != None:
tt += 1
q[tt] = t.right
return res
def printFromTopToBottom(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if root == None:
return []
return self.bfs(root)
AcWing 44. 分行从上往下打印二叉树
从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行。
宽度优先遍历,一层一层来做
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def bfs(self, root):
res = []
q = [0 for i in range(10005)]
hh = 0
tt = -1
tt += 1
q[tt] = root
res.append([root.val])
while hh <= tt:
tail = tt
temp = []
while hh <= tail:
t = q[hh]
hh += 1
if t.left != None:
tt += 1
q[tt] = t.left
temp.append(t.left.val)
if t.right != None:
tt += 1
q[tt] = t.right
temp.append(t.right.val)
res.append(temp)
res.pop()
return res
def printFromTopToBottom(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if root == None:
return []
return self.bfs(root)
- 将根节点插入队列中;
- 创建一个新队列,用来按顺序保存下一层的所有子节点;
- 对于当前队列中的所有节点,按顺序依次将儿子加入新队列,并将当前节点的值记录在答案中;
- 重复步骤2-3,直到队列为空为止。
/**
* 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:
vector<int> get_val(vector<TreeNode*> level)
{
vector<int> res;
for (auto &u : level)
res.push_back(u->val);
return res;
}
vector<vector<int>> printFromTopToBottom(TreeNode* root) {
vector<vector<int>>res;
if (!root) return res;
vector<TreeNode*>level;
level.push_back(root);
res.push_back(get_val(level));
while (true)
{
vector<TreeNode*> newLevel;
for (auto &u : level)
{
if (u->left) newLevel.push_back(u->left);
if (u->right) newLevel.push_back(u->right);
}
if (newLevel.size())
{
res.push_back(get_val(newLevel));
level = newLevel;
}
else break;
}
return res;
}
};
AcWing 45. 之字形打印二叉树
请实现一个函数按照之字形顺序从上向下打印二叉树。
即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def bfs(self, root):
res = []
q = [0 for i in range(10005)]
hh = 0
tt = -1
tt += 1
q[tt] = root
res.append([root.val])
i = 1
while hh <= tt:
tail = tt
temp = []
while hh <= tail:
t = q[hh]
hh += 1
if t.left != None:
tt += 1
q[tt] = t.left
temp.append(t.left.val)
if t.right != None:
tt += 1
q[tt] = t.right
temp.append(t.right.val)
if i % 2 == 1:
res.append(temp[::-1])
else:
res.append(temp)
i += 1
res.pop()
return res
def printFromTopToBottom(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
if root == None:
return []
return self.bfs(root)