📅  最后修改于: 2023-12-03 15:09:46.320000             🧑  作者: Mango
在程序员面试中,常会遇到有关数据结构的问题,因此,针对常见的数据结构面试问题,本篇文章将为大家整理一套面试问题套装,希望对大家在面试中有所帮助。
可以使用线性搜索或二分查找。线性搜索是在数组中依次遍历查找,时间复杂度为 O(n)。二分查找则是通过将数组分成左右两个部分,每次比较中间值与目标值,并且根据结果调整查询方向,时间复杂度为 O(log n)。
def linear_search(arr, target):
for i in range(len(arr)):
if arr[i] == target:
return i
return -1
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = left + (right - left) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
可以通过双指针法来实现。设置两个指针 p 和 q,p 用于指向上一个不重复的元素,q 用于指向当前正在遍历的元素。遍历过程中,若 arr[p] == arr[q],则将 q 向后移动;否则将 arr[p+1] 的值修改为 arr[q],并将 p 向后移动。最终,数组中前 p+1 个元素即为不重复元素。
def remove_duplicates(arr):
if not arr:
return 0
p = 0
for q in range(1, len(arr)):
if arr[p] != arr[q]:
p += 1
arr[p] = arr[q]
return p + 1
可以通过双指针法来实现。设置一个指针 left,一个指针 right,分别指向数组的首尾元素。遍历过程中,不断交换 left 和 right 所指向的元素,并将 left 后移,将 right 前移。直到 left ≥ right。
def reverse_arr(arr):
left, right = 0, len(arr) - 1
while left < right:
arr[left], arr[right] = arr[right], arr[left]
left += 1
right -= 1
可以通过设置三个指针来实现,分别指向前驱节点、当前节点和后继节点。遍历过程中,将当前节点的指针指向前驱节点,然后将三个指针向后移动。
def reverse_list(head):
prev, curr = None, head
while curr:
tmp = curr.next
curr.next = prev
prev = curr
curr = tmp
return prev
可以用快慢指针法。设置两个指针 slow 和 fast,初始时都指向链表头节点。慢指针每次向后移动一步,快指针每次向后移动两步。如果链表有环,则快指针最终会追上慢指针。
def has_cycle(head):
if not head or not head.next:
return False
slow, fast = head, head.next
while slow != fast:
if not fast or not fast.next:
return False
slow = slow.next
fast = fast.next.next
return True
可以用双指针法。设置两个指针 p1 和 p2,初始时都指向链表头节点。p1 先移动 n 个位置,然后 p1 和 p2 同时向后移动,直到 p1 到达链表尾部。此时,p2 所指向的节点即为要删除的节点。
def remove_nth_from_end(head, n):
if not head:
return None
dummy = ListNode(0, head)
p1, p2 = dummy, head
for i in range(n):
if not p1:
return None
p1 = p1.next
while p1.next:
p1 = p1.next
p2 = p2.next
p2.next = p2.next.next
return dummy.next
可以使用栈来进行括号匹配。遍历表达式,当遇到左括号时压栈,当遇到右括号时弹出栈顶元素,并检查其是否与当前右括号匹配。
def is_valid_parentheses(s):
stack, match = [], {')': '(', ']': '[', '}': '{'}
for ch in s:
if ch in match:
if not stack or match[ch] != stack[-1]:
return False
stack.pop()
else:
stack.append(ch)
return not stack
可以使用两个队列来实现一个栈。每次插入元素时,将其加入到非空队列中;每次弹出元素时,将非空队列中的所有元素移动到另一个空队列中,直到队列中只剩下一个元素为止。
class MyStack:
def __init__(self):
self.q1 = collections.deque()
self.q2 = collections.deque()
def push(self, x: int) -> None:
if not self.q1:
self.q1.append(x)
while self.q2:
self.q1.append(self.q2.popleft())
else:
self.q2.append(x)
while self.q1:
self.q2.append(self.q1.popleft())
def pop(self) -> int:
if self.q1:
return self.q1.popleft()
else:
return self.q2.popleft()
def top(self) -> int:
if self.q1:
return self.q1[0]
else:
return self.q2[0]
def empty(self) -> bool:
return not self.q1 and not self.q2
可以使用两个栈来实现一个队列。每次插入元素时,将其加入到栈 1 中;每次弹出元素时,先检查栈 2 是否为空,若不为空,则弹出栈 2 的栈顶元素,否则,将栈 1 中的所有元素弹出并加入到栈 2 中,再弹出栈 2 的栈顶元素。
class MyQueue:
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, x: int) -> None:
self.stack1.append(x)
def pop(self) -> int:
if not self.stack2:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
def peek(self) -> int:
if not self.stack2:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2[-1]
def empty(self) -> bool:
return not self.stack1 and not self.stack2
可以使用递归法或迭代法遍历二叉树。其中,一棵二叉树可以分别进行先序遍历、中序遍历和后序遍历。
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def preorder_traversal(root: TreeNode):
if not root:
return []
return [root.val] + preorder_traversal(root.left) + preorder_traversal(root.right)
def inorder_traversal(root: TreeNode):
if not root:
return []
return inorder_traversal(root.left) + [root.val] + inorder_traversal(root.right)
def postorder_traversal(root: TreeNode):
if not root:
return []
return postorder_traversal(root.left) + postorder_traversal(root.right) + [root.val]
平衡二叉树的特点是,其任意节点的两个子树的高度差不超过 1。因此,可以采用递归计算左子树和右子树的高度,并判断其高度差的绝对值是否超过 1。若超过,该二叉树即为不平衡二叉树。
def is_balanced(root: TreeNode) -> bool:
def helper(node):
if not node:
return 0
left = helper(node.left)
if left == -1:
return -1
right = helper(node.right)
if right == -1:
return -1
return max(left, right) + 1 if abs(left - right) <= 1 else -1
return helper(root) != -1
可以采用深度优先搜索(DFS)遍历二叉树。当访问到一个节点时,将当前节点的值加入路径中,并计算路径中所有节点的和。如果该节点是叶子节点,并且路径中所有节点的和等于指定和,则将该路径加入到结果列表中。否则,遍历当前节点的左子树和右子树。
def path_sum(root: TreeNode, target: int) -> List[List[int]]:
def dfs(node, path, sum):
if not node:
return
sum += node.val
path.append(node.val)
if not node.left and not node.right:
if sum == target:
res.append(path[:])
else:
dfs(node.left, path, sum)
dfs(node.right, path, sum)
path.pop()
res = []
dfs(root, [], 0)
return res