0x3f-problem-solution

配合灵神题单解题

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         0x3f-problem-solution
// @namespace    https://greasyfork.org/zh-CN/users/1326420-wuxin0012
// @version      0.0.1
// @author       wuxin0011
// @description  配合灵神题单解题
// @license      MIT
// @icon         https://assets.leetcode.cn/aliyun-lc-upload/users/endlesscheng/avatar_1690721039.png
// @source       https://greasyfork.org/zh-CN/users/1326420-wuxin0012
// @match        https://leetcode.cn/circle/discuss/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js
// @require      data:application/javascript,%3Bwindow.Vue%3DVue%3B
// @require      https://unpkg.com/[email protected]/dist/index.full.js
// @resource     elementPlusCss  https://unpkg.com/[email protected]/dist/index.css
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// ==/UserScript==

(t=>{if(typeof GM_addStyle=="function"){GM_addStyle(t);return}const e=document.createElement("style");e.textContent=t,document.head.append(e)})(" .m-setting-button[data-v-6d3b190f]{position:fixed;top:200px;right:0;z-index:100000} ");

(function (vue, ElementPlus) {
  'use strict';

  var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  const inf = 4e3;
  const mi = 1e3;
  const __0x3f_problmes_solution__ = "__0x3f_problmes_solution__";
  const __0x3f_problmes_urls__ = "__0x3f_problmes_urls__";
  const __0x3f_problmes_update__ = "__0x3f_problmes_update__";
  const __add_cur__ = "__add_cur__";
  const Problems = () => Array.from(document.querySelectorAll(".css-1ayia3m-MarkdownContent li>a"));
  const defaultObj = {
    min: mi,
    max: inf,
    visiableMember: true,
    onlyUrls: false,
    useDefaultSetting: true
  };
  function isShow(text, min, max) {
    if (!text) {
      return true;
    }
    let res = text.match(/\d+/ig);
    if (!res) {
      return true;
    }
    if (Array.isArray(res) && res.length < 2) {
      return true;
    }
    let s = 0;
    for (let i = res.length - 1; i >= 0; i--) {
      s = res[i];
      if (s >= mi && s <= inf) {
        return s >= min && s <= max;
      }
    }
    return true;
  }
  let A = Problems();
  function handlerProblem(data) {
    var _a;
    if (!Array.isArray(A) || Array.isArray(A) && A.length == 0) {
      A = Problems();
    }
    let { min, max, visiableMember, useDefaultSetting, onlyUrls } = data;
    if (isNaN(min) || isNaN(max)) {
      min = mi;
      max = inf;
    }
    if (min < mi) {
      min = mi;
    }
    if (max < min) {
      max = inf;
    }
    min = Number(min);
    max = Number(max);
    data.min = min;
    data.max = max;
    _GM_setValue(__0x3f_problmes_solution__, data);
    for (let i = 0; i < A.length; i++) {
      let d = (_a = A[i]) == null ? void 0 : _a.parentElement;
      if (!d) {
        continue;
      }
      let flag = isShow(d.textContent, min, max);
      d.style.display = flag ? "" : "none";
      let c = d.textContent && d.textContent.indexOf("会员") != -1;
      if (!c) {
        continue;
      }
      d.style.display = visiableMember ? "" : "none";
    }
  }
  const initUrls = () => _GM_getValue(__0x3f_problmes_update__) ? Array.isArray(_GM_getValue(__0x3f_problmes_urls__)) ? _GM_getValue(__0x3f_problmes_urls__) : [] : defaultUrls;
  const initObj = () => _GM_getValue(__0x3f_problmes_solution__) ? Object.assign(defaultObj, _GM_getValue(__0x3f_problmes_solution__)) : defaultObj;
  const support_plugins = () => {
    const u = initObj();
    if (!u || !u.onlyUrls) return true;
    const url = window.location.href;
    const urls = initUrls();
    for (let info of urls) {
      if (!info || !(info == null ? void 0 : info.link)) {
        continue;
      }
      console.log("url find", info.link.indexOf(url) != -1, info.link, url);
      if (info.link.indexOf(url) != -1) {
        return true;
      }
    }
    return false;
  };
  const defaultUrls = [
    {
      title: "滑动窗口(定长/不定长/多指针)",
      link: "https://leetcode.cn/circle/discuss/0viNMK/"
    },
    {
      title: "二分算法(二分答案/最小化最大值/最大化最小值/第K小)",
      link: "https://leetcode.cn/circle/discuss/SqopEo/"
    },
    {
      title: "单调栈(矩形面积/贡献法/最小字典序)",
      link: "https://leetcode.cn/circle/discuss/9oZFK9/"
    },
    {
      title: "网格图(DFS/BFS/综合应用)",
      link: "https://leetcode.cn/circle/discuss/YiXPXW/"
    },
    {
      title: "位运算(基础/性质/拆位/试填/恒等式/贪心/脑筋急转弯)",
      link: "https://leetcode.cn/circle/discuss/dHn9Vk/"
    },
    {
      title: "图论算法(DFS/BFS/拓扑排序/最短路/最小生成树/二分图/基环树/欧拉路径)",
      link: "https://leetcode.cn/circle/discuss/01LUak/"
    },
    {
      title: "动态规划(入门/背包/状态机/划分/区间/状压/数位/树形/数据结构优化)",
      link: "https://leetcode.cn/circle/discuss/tXLS3i/"
    },
    {
      title: "常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)",
      link: "https://leetcode.cn/circle/discuss/mOr1u6/"
    },
    {
      title: "数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)",
      link: "https://leetcode.cn/circle/discuss/IYT3ss/"
    }
  ];
  const _export_sfc = (sfc, props) => {
    const target = sfc.__vccOpts || sfc;
    for (const [key, val] of props) {
      target[key] = val;
    }
    return target;
  };
  const _hoisted_1 = { class: "dialog-footer" };
  const formLabelWidth = "44px";
  const _sfc_main = {
    __name: "App",
    setup(__props) {
      const drawer = vue.ref(false);
      const fromData = vue.reactive(initObj());
      vue.watch(fromData, () => {
        handlerProblem(vue.toRaw(Object.assign({}, fromData)));
      });
      let tableData = vue.reactive(initUrls());
      const keywords = vue.ref("");
      const dialogTableVisible = vue.ref(false);
      const urlsData = vue.computed(() => tableData.filter((v) => v && v.title && v.title.indexOf(keywords.value) != -1));
      const dialogFormVisible = vue.ref(false);
      const info = vue.reactive({
        title: "",
        link: "",
        status: "add"
      });
      const addlocal = () => {
        let ok = false;
        for (let a of tableData) {
          if (a && a.link.indexOf(window.location.href) != -1) {
            ok = true;
          }
        }
        if (ok) {
          return;
        }
        tableData.unshift({ title: document.title, link: window.location.href });
      };
      const updateIndex = vue.ref(-1);
      const showProblems = () => {
        dialogTableVisible.value = true;
        if (_GM_getValue(__add_cur__)) {
          addlocal();
        }
      };
      const handlerProblems = (status, updateInfo = { title: "", link: "" }, index = -1) => {
        dialogFormVisible.value = true;
        info.status = status;
        updateIndex.value = index;
        Object.assign(info, updateInfo);
      };
      const handlerMessage = (u, title, link) => {
        const a = u ? "添加" : "修改";
        const error = !title || !/https?:\/\/.*/.test(link);
        if (error) {
          ElementPlus.ElMessage.error(`${a} 失败 请保证标题或者链接有效 `);
        } else {
          ElementPlus.ElMessage.success(`${a} 成功 `);
        }
        return !error;
      };
      const addOrUpdate = () => {
        if (!handlerMessage(info.status == "add", info.title, info.link)) {
          return;
        }
        if (info.status == "add") {
          tableData.unshift({ title: info.title, link: info.link });
        } else {
          let index = updateIndex.value;
          if (index != -1 && index < tableData.length) {
            tableData[index].link = info.link;
            tableData[index].title = info.title;
          }
        }
        dialogFormVisible.value = false;
      };
      const deleteProblems = (index) => {
        tableData.splice(index, 1);
        _GM_setValue(__0x3f_problmes_urls__, vue.toRaw(tableData));
      };
      const handlerDefault = () => {
        ElementPlus.ElMessageBox.confirm(
          "确认使用默认题单,将会重置题单?",
          "警告",
          {
            confirmButtonText: "确认",
            cancelButtonText: "取消",
            type: "warning"
          }
        ).then(() => {
          for (let i = 0; i < tableData.length; i++) {
            delete tableData[i];
          }
          for (let item of defaultUrls) {
            tableData.unshift(item);
          }
          ElementPlus.ElMessage({
            type: "success",
            message: "重置成功"
          });
        }).catch(() => {
          ElementPlus.ElMessage({
            type: "info",
            message: "取消重置"
          });
        });
      };
      window.addEventListener("beforeunload", () => {
        console.log("save ....");
        _GM_setValue(__0x3f_problmes_urls__, vue.toRaw(tableData));
        _GM_setValue(__0x3f_problmes_update__, true);
        _GM_setValue(__add_cur__, false);
      });
      vue.onMounted(() => {
        if (support_plugins()) {
          setTimeout(() => {
            handlerProblem(vue.toRaw(Object.assign({}, fromData)));
          }, 3e3);
        }
      });
      return (_ctx, _cache) => {
        const _component_el_button = vue.resolveComponent("el-button");
        const _component_el_input = vue.resolveComponent("el-input");
        const _component_el_col = vue.resolveComponent("el-col");
        const _component_el_form_item = vue.resolveComponent("el-form-item");
        const _component_el_switch = vue.resolveComponent("el-switch");
        const _component_el_tooltip = vue.resolveComponent("el-tooltip");
        const _component_el_form = vue.resolveComponent("el-form");
        const _component_el_divider = vue.resolveComponent("el-divider");
        const _component_el_row = vue.resolveComponent("el-row");
        const _component_el_link = vue.resolveComponent("el-link");
        const _component_el_table_column = vue.resolveComponent("el-table-column");
        const _component_el_table = vue.resolveComponent("el-table");
        const _component_el_dialog = vue.resolveComponent("el-dialog");
        const _component_el_drawer = vue.resolveComponent("el-drawer");
        return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
          vue.createElementVNode("div", null, [
            vue.createVNode(_component_el_button, {
              type: "primary",
              style: { "margin-left": "16px" },
              onClick: _cache[0] || (_cache[0] = ($event) => drawer.value = !drawer.value),
              class: "m-setting-button"
            }, {
              default: vue.withCtx(() => [
                vue.createTextVNode(" 设置 ")
              ]),
              _: 1
            })
          ]),
          vue.createVNode(_component_el_drawer, {
            modelValue: drawer.value,
            "onUpdate:modelValue": _cache[13] || (_cache[13] = ($event) => drawer.value = $event),
            "with-header": false,
            size: "30%"
          }, {
            default: vue.withCtx(() => [
              vue.createVNode(_component_el_form, {
                "label-position": "left",
                "label-width": "auto",
                model: fromData,
                style: { "max-width": "600px" }
              }, {
                default: vue.withCtx(() => [
                  vue.createVNode(_component_el_form_item, { label: "分数区间" }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_col, { span: 10 }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_input, {
                            modelValue: fromData.min,
                            "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => fromData.min = $event),
                            "aria-placeholder": "",
                            placeholder: " min  "
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      }),
                      vue.createVNode(_component_el_col, {
                        class: "text-center",
                        span: 1,
                        style: { "margin": "0 0.5rem" }
                      }, {
                        default: vue.withCtx(() => [
                          vue.createTextVNode("-")
                        ]),
                        _: 1
                      }),
                      vue.createVNode(_component_el_col, { span: 10 }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_input, {
                            modelValue: fromData.max,
                            "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => fromData.max = $event),
                            "aria-placeholder": "",
                            placeholder: " max"
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      })
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_form_item, { label: "显示会员题" }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_switch, {
                        modelValue: fromData.visiableMember,
                        "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => fromData.visiableMember = $event)
                      }, null, 8, ["modelValue"])
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_form_item, { label: "只在收藏题单中生效" }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_tooltip, {
                        content: "插件只在收藏题单中生效,刷新生效 ",
                        placement: "bottom-end"
                      }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_switch, {
                            modelValue: fromData.onlyUrls,
                            "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => fromData.onlyUrls = $event)
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      })
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_form_item, { label: "使用题单" }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_switch, {
                        modelValue: fromData.useDefaultSetting,
                        "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => fromData.useDefaultSetting = $event)
                      }, null, 8, ["modelValue"])
                    ]),
                    _: 1
                  })
                ]),
                _: 1
              }, 8, ["model"]),
              fromData.useDefaultSetting ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
                vue.createVNode(_component_el_divider),
                vue.createVNode(_component_el_button, {
                  plain: "",
                  onClick: showProblems
                }, {
                  default: vue.withCtx(() => [
                    vue.createTextVNode(" 查看收藏的题单 ")
                  ]),
                  _: 1
                }),
                vue.createVNode(_component_el_divider)
              ], 64)) : vue.createCommentVNode("", true),
              vue.createVNode(_component_el_dialog, {
                modelValue: dialogTableVisible.value,
                "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => dialogTableVisible.value = $event),
                title: "题单"
              }, {
                default: vue.withCtx(() => [
                  vue.createVNode(_component_el_row, { gutter: 10 }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_col, { span: 8 }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_input, {
                            modelValue: keywords.value,
                            "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => keywords.value = $event),
                            placeholder: "请输入关键词过滤",
                            clearable: ""
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      }),
                      vue.createVNode(_component_el_col, { span: 16 }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_button, {
                            plain: "",
                            onClick: addlocal
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode(" 添加本页 ")
                            ]),
                            _: 1
                          }),
                          vue.createVNode(_component_el_button, {
                            plain: "",
                            onClick: _cache[7] || (_cache[7] = ($event) => handlerProblems("add"))
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode(" 自定义 ")
                            ]),
                            _: 1
                          }),
                          vue.createVNode(_component_el_button, {
                            plain: "",
                            onClick: handlerDefault
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode(" 默认 ")
                            ]),
                            _: 1
                          })
                        ]),
                        _: 1
                      })
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_table, {
                    data: urlsData.value,
                    height: "300",
                    style: { "width": "100%", "margin-top": "10px" }
                  }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_table_column, {
                        label: "标题",
                        width: "auto",
                        align: "center"
                      }, {
                        default: vue.withCtx((scope) => [
                          vue.createVNode(_component_el_link, {
                            href: scope.row.link,
                            target: "_blank",
                            type: "default"
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode(vue.toDisplayString(scope.row.title), 1)
                            ]),
                            _: 2
                          }, 1032, ["href"])
                        ]),
                        _: 1
                      }),
                      vue.createVNode(_component_el_table_column, {
                        label: "操作",
                        width: "auto",
                        align: "center"
                      }, {
                        default: vue.withCtx((scope) => [
                          vue.createVNode(_component_el_button, {
                            type: "primary",
                            size: "small",
                            onClick: ($event) => handlerProblems("update", scope.row, scope.$index)
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode("编辑")
                            ]),
                            _: 2
                          }, 1032, ["onClick"]),
                          vue.createVNode(_component_el_button, {
                            type: "danger",
                            size: "small",
                            onClick: ($event) => deleteProblems(scope.$index)
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode("删除")
                            ]),
                            _: 2
                          }, 1032, ["onClick"])
                        ]),
                        _: 1
                      })
                    ]),
                    _: 1
                  }, 8, ["data"])
                ]),
                _: 1
              }, 8, ["modelValue"]),
              vue.createVNode(_component_el_dialog, {
                modelValue: dialogFormVisible.value,
                "onUpdate:modelValue": _cache[12] || (_cache[12] = ($event) => dialogFormVisible.value = $event),
                title: `${info.status == "add" ? "添加" : "编辑"}`,
                width: "400"
              }, {
                footer: vue.withCtx(() => [
                  vue.createElementVNode("div", _hoisted_1, [
                    vue.createVNode(_component_el_button, {
                      onClick: _cache[11] || (_cache[11] = ($event) => dialogFormVisible.value = false)
                    }, {
                      default: vue.withCtx(() => [
                        vue.createTextVNode("取消")
                      ]),
                      _: 1
                    }),
                    vue.createVNode(_component_el_button, {
                      type: "primary",
                      onClick: addOrUpdate
                    }, {
                      default: vue.withCtx(() => [
                        vue.createTextVNode(" 确认 ")
                      ]),
                      _: 1
                    })
                  ])
                ]),
                default: vue.withCtx(() => [
                  vue.createVNode(_component_el_form, null, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_form_item, {
                        label: "标题",
                        "label-width": formLabelWidth
                      }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_input, {
                            modelValue: info.title,
                            "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => info.title = $event),
                            autocomplete: "off"
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      }),
                      vue.createVNode(_component_el_form_item, {
                        label: "链接",
                        "label-width": formLabelWidth
                      }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_input, {
                            modelValue: info.link,
                            "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => info.link = $event),
                            autocomplete: "off"
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      })
                    ]),
                    _: 1
                  })
                ]),
                _: 1
              }, 8, ["modelValue", "title"])
            ]),
            _: 1
          }, 8, ["modelValue"])
        ], 64);
      };
    }
  };
  const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6d3b190f"]]);
  const cssLoader = (e) => {
    const t = GM_getResourceText(e);
    return GM_addStyle(t), t;
  };
  cssLoader("elementPlusCss");
  let Container = null;
  const VueApp = vue.createApp(App);
  const start = () => {
    Container = document.createElement("div");
    const body = document.querySelector("body");
    body.append(Container);
    Container.style.display = support_plugins() ? "block" : "none";
    return Container;
  };
  VueApp.use(ElementPlus).mount(start());
  _GM_registerMenuCommand(`${initObj().onlyUrls ? "仅在收藏题单页面生效" : "所有题单生效"}`, () => {
    const u = initObj();
    u.onlyUrls = !u.onlyUrls;
    Container.style.display = support_plugins() ? "block" : "none";
    _GM_setValue(__0x3f_problmes_solution__, u);
  });
  _GM_registerMenuCommand(`添加本页`, () => {
    const urls = initUrls();
    let ok = false;
    const url = window.location.href;
    for (let info of urls) {
      if (!info || !(info == null ? void 0 : info.link)) {
        continue;
      }
      if (info.link.indexOf(url) != -1) {
        ok = true;
        break;
      }
    }
    if (ok) {
      ElementPlus.ElMessage({
        message: "收藏失败,链接已经存在!",
        type: "error"
      });
    } else {
      urls.unshift({
        title: document.title,
        link: url
      });
      Container.style.display = "block";
      _GM_setValue(__0x3f_problmes_urls__, urls);
      _GM_setValue(__add_cur__, true);
      ElementPlus.ElMessage({
        message: "收藏成功!刷新生效",
        type: "success"
      });
    }
  });

})(Vue, ElementPlus);