input: Write a function to generate a random maze and find a path using depth-first search (DFS).
  assert isinstance(generate_maze(5, 5), list)
  assert len(generate_maze(5, 5)) == 5
  assert len(generate_maze(5, 5)[0]) == 5
output: import random
  
  def generate_maze(width, height):
      def init_maze(w, h):
          return [['#'] * w for _ in range(h)]
  
      def carve_passages_from(cx, cy, maze):
          directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
          random.shuffle(directions)
          for direction in directions:
              nx, ny = cx + direction[0] * 2, cy + direction[1] * 2
              if 0 <= nx < len(maze[0]) and 0 <= ny < len(maze):
                  if maze[ny][nx] == '#':
                      maze[cy + direction[1]][cx + direction[0]] = ' '
                      maze[ny][nx] = ' '
                      carve_passages_from(nx, ny, maze)
      
      maze = init_maze(width, height)
      start_x, start_y = 1, 1
      maze[start_y][start_x] = ' '
      carve_passages_from(start_x, start_y, maze)
      return maze
  
  def find_path(maze):
      width, height = len(maze[0]), len(maze)
      start = (1, 1)
      end = (width - 2, height - 2)
      path = []
      visited = set()
      
      def dfs(x, y):
          if (x, y) == end:
              path.append((x, y))
              return True
          if (x, y) in visited or maze[y][x] == '#':
              return False
          visited.add((x, y))
          path.append((x, y))
          for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
              if dfs(x + dx, y + dy):
                  return True
          path.pop()
          return False
      
      dfs(*start)
      return path
  
  # Example usage:
  # maze = generate_maze(5, 5)
  # path = find_path(maze)