记录利用Cursor快速实现拖拽式问卷题型创建

帮我实现一个可拖拽式的调查问卷demo,左侧是可拖拽生成的题型类别(比如:单选题、多选题、填空题),中间是可拖拽生成题型的区域,区域内的题型可以自行上下拖拽,右侧是点击中间区域对应的题型,可以对其进行编辑修改,设置禁用项,输入长度限制等等。总结来说类似于"调问"和"问卷星"。

简简单单,你就跟产品或者项目经理似的给 Cursor 提任务需求就可以了,他就能够快速自动帮你实现,话不多说,先看下成果~

Cursor 在整个实现过程前前后后可能也就不到 10分钟 就完事了,想当初为了实现此功能,先是搜索了大量的Git项目案例,找到合适的项目demo后,又是开始熟悉了解使用方法。

一开始没有找项目案例,纯找实现方法,发现实现起来还是有点费劲

《Vue2 _ 实现拖拽功能》https://blog.csdn.net/weixin_58099903/article/details/122186582?fromshare=blogdetail&sharetype=blogdetail&sharerId=122186582&sharerefer=PC&sharesource=weixin_58099903&sharefrom=from_link

后来找的项目demo,里面使用了 Vue 的一款 拖拽插件 vue.draggable

推荐学习文章:《记录Vue.Draggable拖拽组件的使用历程》

《记录Vue.Draggable拖拽组件的使用历程》https://blog.csdn.net/weixin_58099903/article/details/125655355?fromshare=blogdetail&sharetype=blogdetail&sharerId=125655355&sharerefer=PC&sharesource=weixin_58099903&sharefrom=from_link前前后后包括搜索项目案例和学习使用方法就花费了 一周 的时间,可见其成本和效率,

可以毫不夸张的说,使用 Cursor 开发,效率提升至少 10 倍!


接下来咱们细看一下 Cursor 是如何一步一步实现的吧~

1、先查看项目结构与依赖。

2、自动 安装 vue-draggable-plus 并注册 Pinia。

3、创建类型、工厂函数、Pinia store 与问卷搭建页面。

1、src\types\survey.ts --- 题型与数据结构

TypeScript 复制代码
export type QuestionKind = 'single' | 'multiple' | 'fill'

export interface OptionItem {
  id: string
  label: string
  disabled?: boolean
}

export interface SurveyQuestionBase {
  id: string
  type: QuestionKind
  title: string
  required: boolean
}

export interface SingleQuestion extends SurveyQuestionBase {
  type: 'single'
  options: OptionItem[]
}

export interface MultipleQuestion extends SurveyQuestionBase {
  type: 'multiple'
  options: OptionItem[]
  minSelect?: number
  maxSelect?: number
}

export interface FillQuestion extends SurveyQuestionBase {
  type: 'fill'
  placeholder?: string
  minLength?: number
  maxLength?: number
}

export type SurveyQuestion = SingleQuestion | MultipleQuestion | FillQuestion

export interface PaletteItem {
  id: string
  kind: QuestionKind
  label: string
  description: string
}

2、src\utils\surveyFactory.ts --- createQuestionPALETTE_ITEMS

TypeScript 复制代码
import type {
  FillQuestion,
  MultipleQuestion,
  OptionItem,
  QuestionKind,
  SingleQuestion,
  SurveyQuestion,
} from '@/types/survey'

function uid(): string {
  return crypto.randomUUID()
}

function defaultOptions(): OptionItem[] {
  return ['选项 A', '选项 B', '选项 C', '选项 D'].map((label) => ({
    id: uid(),
    label,
    disabled: false,
  }))
}

export function createQuestion(kind: QuestionKind): SurveyQuestion {
  const base = { id: uid(), title: '未命名题目', required: false }
  if (kind === 'single') {
    const q: SingleQuestion = {
      ...base,
      type: 'single',
      options: defaultOptions(),
    }
    return q
  }
  if (kind === 'multiple') {
    const q: MultipleQuestion = {
      ...base,
      type: 'multiple',
      options: defaultOptions(),
      minSelect: 1,
      maxSelect: undefined,
    }
    return q
  }
  const q: FillQuestion = {
    ...base,
    type: 'fill',
    placeholder: '请输入内容',
    minLength: undefined,
    maxLength: 200,
  }
  return q
}

export const PALETTE_ITEMS = [
  {
    id: 'palette-single',
    kind: 'single' as const,
    label: '单选题',
    description: '从多个选项中选一项',
  },
  {
    id: 'palette-multiple',
    kind: 'multiple' as const,
    label: '多选题',
    description: '从多个选项中选多项',
  },
  {
    id: 'palette-fill',
    kind: 'fill' as const,
    label: '填空题',
    description: '短文本输入',
  },
]

3、src\stores\surveyBuilder.ts --- Pinia:题目列表、选中项、patchQuestionupdateOption

TypeScript 复制代码
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import type { OptionItem, SurveyQuestion } from '@/types/survey'
export const useSurveyBuilderStore = defineStore('surveyBuilder', () => {
  const questions = ref<SurveyQuestion[]>([])
  const selectedId = ref<string | null>(null)

  const selectedQuestion = computed(() => {
    if (!selectedId.value) return null
    return questions.value.find((q) => q.id === selectedId.value) ?? null
  })

  function selectQuestion(id: string | null) {
    selectedId.value = id
  }

  function removeQuestion(id: string) {
    questions.value = questions.value.filter((q) => q.id !== id)
    if (selectedId.value === id) selectedId.value = null
  }

  function patchQuestion(id: string, patch: Partial<SurveyQuestion>) {
    const i = questions.value.findIndex((q) => q.id === id)
    if (i === -1) return
    const cur = questions.value[i]
    if (!cur) return
    questions.value[i] = { ...cur, ...patch } as SurveyQuestion
  }

  function updateOption(
    questionId: string,
    optionId: string,
    patch: Partial<OptionItem>,
  ) {
    const q = questions.value.find((x) => x.id === questionId)
    if (!q || (q.type !== 'single' && q.type !== 'multiple')) return
    const opts = q.options.map((o) =>
      o.id === optionId ? { ...o, ...patch } : o,
    )
    patchQuestion(questionId, { options: opts } as Partial<SurveyQuestion>)
  }

  function addOption(questionId: string) {
    const q = questions.value.find((x) => x.id === questionId)
    if (!q || (q.type !== 'single' && q.type !== 'multiple')) return
    const next: OptionItem = {
      id: crypto.randomUUID(),
      label: `选项 ${q.options.length + 1}`,
      disabled: false,
    }
    patchQuestion(questionId, {
      options: [...q.options, next],
    } as Partial<SurveyQuestion>)
  }

  function removeOption(questionId: string, optionId: string) {
    const q = questions.value.find((x) => x.id === questionId)
    if (!q || (q.type !== 'single' && q.type !== 'multiple')) return
    if (q.options.length <= 1) return
    patchQuestion(questionId, {
      options: q.options.filter((o) => o.id !== optionId),
    } as Partial<SurveyQuestion>)
  }

  return {
    questions,
    selectedId,
    selectedQuestion,
    selectQuestion,
    removeQuestion,
    patchQuestion,
    updateOption,
    addOption,
    removeOption,
  }
})

4、src\components\survey-builder\QuestionInspector.vue --- 右侧表单(Element Plus)

TypeScript 复制代码
<template>
  <div class="inspector">
    <h3 class="inspector-title">题目设置</h3>
    <div v-if="!q" class="inspector-empty">
      请在中间区域点击一道题目,即可在此编辑标题、选项与校验规则。
    </div>
    <el-form v-else label-position="top" class="inspector-form">
      <el-form-item label="题目标题">
        <el-input
          :model-value="q.title"
          maxlength="200"
          show-word-limit
          placeholder="请输入标题"
          @update:model-value="store.patchQuestion(q.id, { title: $event })"
        />
      </el-form-item>
      <el-form-item label="必答">
        <el-switch
          :model-value="q.required"
          @update:model-value="store.patchQuestion(q.id, { required: $event })"
        />
      </el-form-item>

      <template v-if="q.type === 'single' || q.type === 'multiple'">
        <el-divider content-position="left">选项</el-divider>
        <p class="hint">可关闭某选项前的「启用」以在答题时隐藏该选项(禁用项)。</p>
        <div
          v-for="(opt, idx) in q.options"
          :key="opt.id"
          class="option-row"
        >
          <span class="opt-index">{{ idx + 1 }}.</span>
          <el-input
            class="opt-input"
            :model-value="opt.label"
            placeholder="选项文案"
            @update:model-value="
              store.updateOption(q.id, opt.id, { label: $event })
            "
          />
          <el-switch
            :model-value="!opt.disabled"
            inline-prompt
            active-text="启用"
            inactive-text="禁用"
            style="flex-shrink: 0"
            @update:model-value="
              store.updateOption(q.id, opt.id, { disabled: !$event })
            "
          />
          <el-button
            type="danger"
            link
            :disabled="q.options.length <= 1"
            @click="store.removeOption(q.id, opt.id)"
          >
            删除
          </el-button>
        </div>
        <el-button class="add-opt" @click="store.addOption(q.id)">
          + 添加选项
        </el-button>
      </template>

      <template v-if="q.type === 'multiple'">
        <el-divider content-position="left">多选限制</el-divider>
        <el-form-item label="最少选几项">
          <el-input-number
            :model-value="q.minSelect ?? 0"
            :min="0"
            :max="q.options.length"
            controls-position="right"
            @update:model-value="patchMultipleMin($event)"
          />
        </el-form-item>
        <el-form-item label="最多选几项(空为不限制)">
          <el-input-number
            :model-value="q.maxSelect ?? undefined"
            :min="1"
            :max="q.options.length"
            controls-position="right"
            :value-on-clear="undefined"
            @update:model-value="patchMultipleMax($event)"
          />
        </el-form-item>
      </template>

      <template v-if="q.type === 'fill'">
        <el-divider content-position="left">填空设置</el-divider>
        <el-form-item label="占位提示">
          <el-input
            :model-value="q.placeholder ?? ''"
            placeholder="输入框占位文字"
            @update:model-value="patchFillPlaceholder($event)"
          />
        </el-form-item>
        <el-form-item label="最少字数">
          <el-input-number
            :model-value="q.minLength ?? undefined"
            :min="0"
            :max="99999"
            controls-position="right"
            :value-on-clear="undefined"
            placeholder="不限制"
            @update:model-value="patchFillMinLen($event)"
          />
        </el-form-item>
        <el-form-item label="最多字数">
          <el-input-number
            :model-value="q.maxLength ?? undefined"
            :min="1"
            :max="99999"
            controls-position="right"
            :value-on-clear="undefined"
            placeholder="不限制"
            @update:model-value="patchFillMaxLen($event)"
          />
        </el-form-item>
      </template>
    </el-form>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { useSurveyBuilderStore } from '@/stores/surveyBuilder'

const store = useSurveyBuilderStore()
const q = computed(() => store.selectedQuestion)

function patchMultipleMin(val: number | undefined) {
  const cur = q.value
  if (!cur || cur.type !== 'multiple') return
  store.patchQuestion(cur.id, { minSelect: val ?? undefined })
}

function patchMultipleMax(val: number | undefined) {
  const cur = q.value
  if (!cur || cur.type !== 'multiple') return
  store.patchQuestion(cur.id, { maxSelect: val ?? undefined })
}

function patchFillPlaceholder(val: string) {
  const cur = q.value
  if (!cur || cur.type !== 'fill') return
  store.patchQuestion(cur.id, { placeholder: val || undefined })
}

function patchFillMinLen(val: number | undefined) {
  const cur = q.value
  if (!cur || cur.type !== 'fill') return
  store.patchQuestion(cur.id, { minLength: val ?? undefined })
}

function patchFillMaxLen(val: number | undefined) {
  const cur = q.value
  if (!cur || cur.type !== 'fill') return
  store.patchQuestion(cur.id, { maxLength: val ?? undefined })
}
</script>

<style scoped>
.inspector {
  height: 100%;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.inspector-title {
  margin: 0 0 12px;
  font-size: 15px;
  font-weight: 600;
  color: #303133;
}

.inspector-empty {
  font-size: 13px;
  line-height: 1.6;
  color: #909399;
  padding: 8px 0;
}

.inspector-form {
  flex: 1;
  overflow: auto;
  padding-right: 4px;
}

.hint {
  margin: 0 0 12px;
  font-size: 12px;
  color: #909399;
  line-height: 1.5;
}

.option-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.opt-index {
  width: 22px;
  flex-shrink: 0;
  font-size: 13px;
  color: #606266;
}

.opt-input {
  flex: 1;
  min-width: 0;
}

.add-opt {
  width: 100%;
  margin-top: 4px;
}
</style>

值得一提的是,Cursor 会自己检测代码并修正优化。

5、src\views\SurveyBuilderDemo.vue --- 三栏布局 + 双 VueDraggable

TypeScript 复制代码
<template>
  <div class="survey-builder-wrap">
    <header class="survey-header">
      <h1 class="survey-title">问卷搭建器 Demo</h1>
      <p class="survey-sub">
        从左侧拖入题型到中间;中间可拖拽排序;点击题目在右侧编辑。
      </p>
      <router-link class="survey-link" to="/marquee">返回滚动演示</router-link>
    </header>

    <div class="survey-grid">
      <aside class="panel panel-left">
        <h2 class="panel-heading">题型库</h2>
        <p class="panel-tip">按住拖入中间画布</p>
        <VueDraggable
          v-model="paletteItems"
          :group="{ name: 'survey', pull: 'clone', put: false }"
          :clone="clonePaletteItem"
          :sort="false"
          :animation="200"
          class="palette-draggable"
        >
          <div
            v-for="p in paletteItems"
            :key="p.id"
            class="palette-card"
          >
            <span class="palette-icon" aria-hidden="true">≡</span>
            <div class="palette-body">
              <div class="palette-label">{{ p.label }}</div>
              <div class="palette-desc">{{ p.description }}</div>
            </div>
          </div>
        </VueDraggable>
      </aside>

      <main class="panel panel-center">
        <h2 class="panel-heading">问卷内容</h2>
        <VueDraggable
          v-model="questions"
          :group="{ name: 'survey', pull: true, put: true }"
          :animation="200"
          handle=".q-drag-handle"
          ghost-class="ghost-card"
          class="canvas-draggable"
        >
          <div
            v-for="(q, index) in questions"
            :key="q.id"
            class="question-card"
            :class="{ 'is-active': selectedId === q.id }"
            @click="store.selectQuestion(q.id)"
          >
            <div class="q-drag-handle" title="拖动排序" @click.stop>
              ⋮⋮
            </div>
            <div class="q-main">
              <div class="q-head">
                <span class="q-no">Q{{ index + 1 }}</span>
                <el-tag size="small" type="info">{{ typeLabel(q.type) }}</el-tag>
                <span v-if="q.required" class="q-req">必答</span>
                <el-button
                  type="danger"
                  link
                  class="q-del"
                  @click.stop="store.removeQuestion(q.id)"
                >
                  删除
                </el-button>
              </div>
              <div class="q-title">{{ q.title }}</div>
              <div class="q-preview">
                <template v-if="q.type === 'single'">
                  <el-radio-group class="preview-group" :model-value="''">
                    <el-radio
                      v-for="opt in q.options"
                      :key="opt.id"
                      :label="opt.id"
                      :disabled="opt.disabled"
                    >
                      {{ opt.label }}
                    </el-radio>
                  </el-radio-group>
                </template>
                <template v-else-if="q.type === 'multiple'">
                  <el-checkbox-group class="preview-group" :model-value="[]">
                    <el-checkbox
                      v-for="opt in q.options"
                      :key="opt.id"
                      :label="opt.id"
                      :disabled="opt.disabled"
                    >
                      {{ opt.label }}
                    </el-checkbox>
                  </el-checkbox-group>
                </template>
                <template v-else>
                  <el-input
                    :model-value="''"
                    :placeholder="q.placeholder || '答题者输入'"
                    disabled
                  />
                </template>
              </div>
            </div>
          </div>
        </VueDraggable>
        <div v-if="questions.length === 0" class="canvas-empty">
          将左侧「单选题 / 多选题 / 填空题」拖放到此处开始组卷
        </div>
      </main>

      <aside class="panel panel-right">
        <QuestionInspector />
      </aside>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { storeToRefs } from 'pinia'
import { VueDraggable } from 'vue-draggable-plus'
import { useSurveyBuilderStore } from '@/stores/surveyBuilder'
import { PALETTE_ITEMS, createQuestion } from '@/utils/surveyFactory'
import type { PaletteItem, SurveyQuestion } from '@/types/survey'
import QuestionInspector from '@/components/survey-builder/QuestionInspector.vue'

const store = useSurveyBuilderStore()
const { questions, selectedId } = storeToRefs(store)

const paletteItems = ref<PaletteItem[]>([...PALETTE_ITEMS])

function clonePaletteItem(item: PaletteItem): SurveyQuestion {
  return createQuestion(item.kind)
}

function typeLabel(type: SurveyQuestion['type']) {
  const map = { single: '单选题', multiple: '多选题', fill: '填空题' }
  return map[type]
}
</script>

<style scoped>
.survey-builder-wrap {
  position: relative;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
  width: 100vw;
  min-height: calc(100vh - 32px);
  box-sizing: border-box;
  padding: 16px 20px 24px;
  background: linear-gradient(180deg, #f5f7fa 0%, #eef1f6 100%);
}

.survey-header {
  max-width: 1200px;
  margin: 0 auto 16px;
}

.survey-title {
  margin: 0 0 6px;
  font-size: 22px;
  font-weight: 700;
  color: #303133;
}

.survey-sub {
  margin: 0 0 8px;
  font-size: 14px;
  color: #606266;
}

.survey-link {
  font-size: 13px;
  color: #409eff;
}

.survey-grid {
  display: grid;
  grid-template-columns: 240px minmax(360px, 1fr) 300px;
  gap: 16px;
  max-width: 1200px;
  margin: 0 auto;
  align-items: stretch;
  min-height: 520px;
}

.panel {
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
  padding: 14px 12px;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.panel-heading {
  margin: 0 0 4px;
  font-size: 15px;
  font-weight: 600;
  color: #303133;
}

.panel-tip {
  margin: 0 0 12px;
  font-size: 12px;
  color: #909399;
}

.palette-draggable {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.palette-card {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 10px;
  border: 1px dashed #c0c4cc;
  border-radius: 8px;
  cursor: grab;
  background: #fafafa;
  transition: border-color 0.2s, background 0.2s;
}

.palette-card:hover {
  border-color: #409eff;
  background: #ecf5ff;
}

.palette-icon {
  color: #909399;
  font-size: 18px;
  line-height: 1.2;
  user-select: none;
}

.palette-label {
  font-size: 14px;
  font-weight: 600;
  color: #303133;
}

.palette-desc {
  margin-top: 4px;
  font-size: 12px;
  color: #909399;
  line-height: 1.4;
}

.panel-center {
  position: relative;
}

.canvas-draggable {
  flex: 1;
  min-height: 200px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-bottom: 8px;
}

.canvas-empty {
  pointer-events: none;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -30%);
  max-width: 280px;
  text-align: center;
  font-size: 14px;
  color: #c0c4cc;
  line-height: 1.6;
}

.question-card {
  display: flex;
  gap: 8px;
  padding: 12px;
  border: 2px solid transparent;
  border-radius: 8px;
  background: #fafafa;
  cursor: pointer;
  transition: border-color 0.2s, box-shadow 0.2s;
}

.question-card:hover {
  background: #f0f9ff;
}

.question-card.is-active {
  border-color: #409eff;
  background: #ecf5ff;
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
}

.q-drag-handle {
  flex-shrink: 0;
  width: 28px;
  text-align: center;
  color: #c0c4cc;
  cursor: grab;
  user-select: none;
  font-size: 14px;
  line-height: 1.8;
}

.q-drag-handle:active {
  cursor: grabbing;
}

.q-main {
  flex: 1;
  min-width: 0;
}

.q-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}

.q-no {
  font-weight: 600;
  color: #606266;
  font-size: 13px;
}

.q-req {
  font-size: 12px;
  color: #f56c6c;
}

.q-del {
  margin-left: auto;
}

.q-title {
  font-size: 15px;
  font-weight: 500;
  color: #303133;
  margin-bottom: 10px;
}

.q-preview {
  font-size: 13px;
}

.preview-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}

.panel-right {
  overflow: hidden;
}

:deep(.ghost-card) {
  opacity: 0.55;
  background: #e1f0ff !important;
}
</style>

6、src\main.ts --- 已注册 Pinia、Element Plus(中文语言包)

TypeScript 复制代码
import './assets/main.css'

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router'

createApp(App)
  .use(createPinia())
  .use(ElementPlus, { locale: zhCn })
  .use(router)
  .mount('#app')

7、src\router\index.ts --- 路由 /survey-builder/ 默认重定向到 /survey-builder

TypeScript 复制代码
import { createRouter, createWebHistory } from 'vue-router'
import ScrollMarqueeDemo from '@/views/ScrollMarqueeDemo.vue'
import SurveyBuilderDemo from '@/views/SurveyBuilderDemo.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      redirect: '/survey-builder',
    },
    {
      path: '/marquee',
      name: 'marquee',
      component: ScrollMarqueeDemo,
    },
    {
      path: '/survey-builder',
      name: 'survey-builder',
      component: SurveyBuilderDemo,
    },
  ],
})

export default router

大功告成:

已实现一个可拖拽的问卷搭建 Demo,说明如下。

功能概览

区域 作用
左侧「题型库」 单选题 / 多选题 / 填空题三种卡片,拖到中间即可生成题目(vue-draggable-plusgroup + pull: 'clone')。
中间「问卷内容」 展示已添加题目,左侧 ⋮⋮ 为拖动手柄,仅在手柄上拖动可上下排序;点击卡片选中并在右侧编辑;「删除」仅移除该题。
右侧「题目设置」 对当前选中题编辑:标题、必答;单选/多选:选项文案、启用/禁用选项、增删选项;多选额外:最少/最多选几项;填空:占位符、最少/最多字数。

涉及文件

  • src/types/survey.ts --- 题型与数据结构
  • src/utils/surveyFactory.ts --- createQuestionPALETTE_ITEMS
  • src/stores/surveyBuilder.ts --- Pinia:题目列表、选中项、patchQuestionupdateOption
  • src/views/SurveyBuilderDemo.vue --- 三栏布局 + 双 VueDraggable
  • src/components/survey-builder/QuestionInspector.vue --- 右侧表单(Element Plus)
  • src/main.ts --- 已注册 Pinia、Element Plus(中文语言包)
  • src/router/index.ts --- 路由 /survey-builder/ 默认重定向到 /survey-builder

本地执行 npm run dev,打开 http://localhost:5173/survey-builder(或根路径 /)即可。


最终看一眼效果图:

相关推荐
Yzzz-F2 小时前
2018-2019 ACM-ICPC, Asia Dhaka Regional ContestC[数论]
算法
Frostnova丶2 小时前
LeetCode 3474. 字典序最小的生成字符串
算法·leetcode·职场和发展
REDcker2 小时前
Nagle 算法与 TCP_NODELAY、TCP_CORK 详解
网络·tcp/ip·算法
β添砖java2 小时前
深度优先搜索DFS
算法·深度优先
小糯米6012 小时前
C++ 并查集
java·c++·算法
IronMurphy2 小时前
【算法三十四】39. 组合总和
算法·深度优先
重庆小透明2 小时前
力扣刷题【3】相交链表
算法·leetcode·链表
算法鑫探3 小时前
C语言实战:学生成绩统计与分析
c语言·数据结构·算法·新人首发
IAUTOMOBILE3 小时前
Code Marathon 项目源码解析与技术实践
java·前端·算法