【LeetCode热题100】打卡第22天:编辑距离颜色分类

news2024/10/6 2:22:26

文章目录

  • 【LeetCode热题100】打卡第22天:编辑距离&颜色分类
    • ⛅前言
  • 编辑距离
    • 🔒题目
    • 🔑题解
  • 颜色分类
    • 🔒题目
    • 🔑题解

【LeetCode热题100】打卡第22天:编辑距离&颜色分类

⛅前言

大家好,我是知识汲取者,欢迎来到我的LeetCode热题100刷题专栏!

精选 100 道力扣(LeetCode)上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,熟练掌握这 100 道题,你就已经具备了在代码世界通行的基本能力。在此专栏中,我们将会涵盖各种类型的算法题目,包括但不限于数组、链表、树、字典树、图、排序、搜索、动态规划等等,并会提供详细的解题思路以及Java代码实现。如果你也想刷题,不断提升自己,就请加入我们吧!QQ群号:827302436。我们共同监督打卡,一起学习,一起进步。

LeetCode热题100专栏🚀:LeetCode热题100

Gitee地址📁:知识汲取者 (aghp) - Gitee.com

题目来源📢:LeetCode 热题 100 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台

PS:作者水平有限,如有错误或描述不当的地方,恳请及时告诉作者,作者将不胜感激

编辑距离

🔒题目

原题链接:72.编辑距离(二刷了(●ˇ∀ˇ●))

image-20230614121144183

🔑题解

  • 解法一:暴力DFS(时间超限)

    直接暴力DFS相当于是进行了三层for循环,枚举出每一种操作的组合,时间复杂度相当高

    /**
     * @author ghp
     * @title
     */
    
    class Solution {
    
        public int minDistance(String word1, String word2) {
            return dfs(word1, word2, 0, 0);
        }
    
        public int dfs(String word1, String word2, int i, int j) {
            if (i == word1.length()) {
                // word1已经遍历完了
                return word2.length() - j;
            }
            if (j == word2.length()) {
                // word2已经遍历完了
                return word1.length() - i;
            }
            int res = 0;
            if (word1.charAt(i) == word2.charAt(j)) {
                // 当前两个字符相同,比较下一个字符
                res = dfs(word1, word2, i + 1, j + 1);
            } else {
                // 删除word1[i],相当于在word2的j位置插入word1[i]
                int r1 = dfs(word1, word2, i + 1, j);
                // 替换word1[i]为word2[j],相当于替换word2[j]为word1[i],相当于同时删除word1[i]和word2[j]
                int r2 = dfs(word1, word2, i + 1, j + 1);
                // 删除word2[j],相当于在word1的i位置插入word2[j]
                int r3 = dfs(word1, word2, i, j + 1);
                // 获取本次最小操作的次数
                res = 1 + Math.min(r1, Math.min(r2, r3));
            }
            return res;
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( 3 m + n ) O(3^{m+n}) O(3m+n)
    • 空间复杂度: O ( m + n ) O(m+n) O(m+n)

    其中 n n n 为word1的长度, m m m为word2的长度

    代码优化:DFS+记忆搜搜

    直接使用DFS一般都是会超时,所以我们需要使用记忆搜索对搜索树进行剪枝,这样就能加快搜索效率,节约搜索时间

    import java.util.Arrays;
    
    /**
     * @author ghp
     * @title
     */
    
    class Solution {
    
        private int[][] memo;
    
        public int minDistance(String word1, String word2) {
            memo = new int[word1.length()][word2.length()];
            for (int i = 0; i < memo.length; i++) {
                Arrays.fill(memo[i], -1);
            }
            return dfs(word1, word2, 0, 0);
        }
    
        public int dfs(String word1, String word2, int i, int j) {
            if (i == word1.length()) {
                // word1已经遍历完了
                return word2.length() - j;
            }
            if (j == word2.length()) {
                // word2已经遍历完了
                return word1.length() - i;
            }
            if (memo[i][j] != -1) {
                // 当前路径已被搜索
                return memo[i][j];
            }
            int res = 0;
            if (word1.charAt(i) == word2.charAt(j)) {
                // 当前两个字符相同,比较下一个字符
                res = dfs(word1, word2, i + 1, j + 1);
            } else {
                // 删除word1[i],相当于在word2的j位置插入word1[i]
                int r1 = dfs(word1, word2, i + 1, j);
                // 替换word1[i]为word2[j],相当于替换word2[j]为word1[i],相当于同时删除word1[i]和word2[j]
                int r2 = dfs(word1, word2, i + 1, j + 1);
                // 删除word2[j],相当于在word1的i位置插入word2[j]
                int r3 = dfs(word1, word2, i, j + 1);
                // 获取本次最小操作的次数
                res = 1 + Math.min(r1, Math.min(r2, r3));
            }
            memo[i][j] = res;
            return res;
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( m ∗ n ) O(m*n) O(mn)
    • 空间复杂度: O ( m ∗ n ) O(m*n) O(mn)

    其中 n n n 为word1的长度, m m m为word2的长度

  • 解法二:动态规划

    可能时间复杂度到 O ( n ∗ m ) O(n*m) O(nm),已经是极限了,但是由于DFS需要递归,而每次递归都需要占用大量的栈内存,所以这里我们可以使用迭代替代递归,节约递归所消耗的栈内存,所以这题毫无疑问最优解就是动态规划,其实动规做得多的,一看这题就知道这是用过经典的动态规划问题,这一点从官方题解也可以看出,LeetCode官方也只提供了动态规划的题解。

    但需要注意的是,并不是所有的题目,动态规划要优于DFS+记忆搜索,在非极值问题上,就不一定,比如在子问题数量超多,而DFS可以进行高效剪枝的情况下,DFS+memo的效率会优于DP算法,比如这道题 【403.青蛙过河】

    状态转移方程最难的就是状态转移方程以及DP的定义,这里大致给出一个思路:

    • Step1:定义DP

      dp[i][j]表示word1中前i给字符,变换成word2中前j个字符,最短需要的操作数。由于wold1或world2中可能存在一个字母都没有的情况,即全增/删的情况,所以需要预留dp[0][j]dp[i][0],方便进行状态转移

    • Step2:构造状态转移方程

      第一种情况:如果word1[i](word1的第i个单词)和word2[j])(word2的第j个单词)相同,则可以直接比较下一个,当前状态没有发生改变,也就是说当前的状态就是word1[i-1]和word2[j-1]的状态,所以状态方程是 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] dp[i][j] = dp[i - 1][j - 1] dp[i][j]=dp[i1][j1]

      第二种情况:如果word[i]不等于word2[j],则需要进行三种操作,增、删、改,但是我们只需要选取三种操作中操作次数最小的一种即可。其中:

      增: d p [ i ] [ j ] = d p [ i ] [ j − 1 ] + 1 dp[i][j]=dp[i][j-1]+1 dp[i][j]=dp[i][j1]+1dp[i][j-1]表示word1前i个字母于word2前j+1个字母进行匹配的最小操作数,相当于是在word2的第 j 个单词前添加一个word1[i],是word[i]与word[j]匹配,然后当前操作数需要+1

      删: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + 1 dp[i][j]=dp[i-1][j]+1 dp[i][j]=dp[i1][j]+1,和增同理

      改: d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 dp[i][j]=dp[i-1][j-1]+1 dp[i][j]=dp[i1][j1]+1,和增同理

      当然,每次状态转移,我们都需要选取当前操作次数最小的一种,也就是有: d p [ i ] [ j ] = 1 + M a t h . m i n ( d p [ i − 1 ] [ j ] , M a t h . m i n ( d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j − 1 ] ) ) dp[i][j] = 1 + Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])) dp[i][j]=1+Math.min(dp[i1][j],Math.min(dp[i][j1],dp[i1][j1]))

    初始化DP(这里word1是horse,word2是ros):

    image-20230615110352451

    经过状态转移后的DP:

    image-20230615111022449

    /**
     * @author ghp
     * @title
     */
    
    class Solution {
    
        public int minDistance(String word1, String word2) {
            int m = word1.length(), n = word2.length();
            int[][] dp = new int[m + 1][n + 1];
            // 初始化DP
            for (int i = 1; i <= m; i++) {
                dp[i][0] = i;
            }
            for (int j = 1; j <= n; j++) {
                dp[0][j] = j;
            }
            for (int i = 1; i <= m; i++) {
                for (int j = 1; j <= n; j++) {
                    if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                        dp[i][j] = dp[i - 1][j - 1];
                    } else {
                        dp[i][j] = 1 + Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1]));
                    }
                }
            }
            return dp[m][n];
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( n ∗ m ) O(n*m) O(nm)
    • 空间复杂度: O ( n ∗ m ) O(n*m) O(nm)

    其中 n n n 为word1的长度, m m m为word2的长度

    代码优化:将二维DP压缩成一维DP

    最后,我们还可以进一步优化空间,因为dp[i][j]的值只与它的邻居dp[i-1][j]dp[i][j-1]dp[i-1][j-1]有关,将二维数组压缩为一维数组,可以天然解决前两个依赖,问题就在于dp[i-1][j-1]的值如何保存,很显然,可以将这一维的数据压缩成一个值,于是,我们可以使用一个一维数组加一个变量来替换原来的二维数组

    /**
     * @author ghp
     * @title
     */
    
    class Solution {
    
        public int minDistance(String word1, String word2) {
            int m = word1.length(), n = word2.length();
            int[] dp = new int[n + 1];
            for (int i = 1; i <= n; i++) {
                dp[i] = i;
            }
            for (int i = 1; i <= m; i++) {
                int pre = dp[0];
                dp[0] = i;
                for (int j = 1; j <= n; j++) {
                    int temp = dp[j];
                    if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                        dp[j] = pre;
                    } else {
                        dp[j] = 1 + Math.min(dp[j-1], Math.min(dp[j], pre));
                    }
                    pre = temp;
                }
            }
            return dp[n];
        }
    }
    

最后我们经过 D F S → D F S + 记忆搜索 → 二维 D P → 一维 D P DFS→DFS+记忆搜索→二维DP→一维DP DFSDFS+记忆搜索二维DP一维DP 的层层优化,最终得到本题的最优解,也就是一维DP,但需要注意并不是说所有的可以使用动规和DFS的题,就一定是DP优于DFS,有些情况,题目的子问题过多可能就是DFS优于DP

PS:说句实话,我感觉DP还更加好理解一点,DFS+记忆搜索反而绕的有点晕,而且这里DP的效率是要高于DFS+记忆搜索的

颜色分类

🔒题目

原题链接:75.颜色分类

image-20230614121222673

🔑题解

  • 解法一:调用API

    Arrays.sort是Java中用于排序的静态方法,它的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。具体来说,它使用的是快速排序或Tim排序(Java 7及以上版本)。在空间复杂度方面,Arrays.sort属于“原地排序”,也就是说,它只使用了常数级别的额外空间,因此空间复杂度为 O ( 1 ) O(1) O(1)。需要注意的是,对于基本类型数组,Arrays.sort使用的是“双轴快速排序”,而对于对象数组,Arrays.sort使用的是“归并排序”。这可能会影响排序的性能和稳定性。同时,如果要对对象数组进行排序,并且排序字段可能有重复的值,那么建议使用Java 8及以上版本的Streams API中的sorted方法,它提供了更好的排序性能和稳定性。

    import java.util.Arrays;
    
    /**
     * @author ghp
     * @title
     */
    class Solution {
        public void sortColors(int[] nums) {
            Arrays.sort(nums);
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
    • 空间复杂度: O ( 1 ) O(1) O(1)

    其中 n n n 为数组中元素的个数

  • 解法二:快排

    解法一的Arrays.sort底层也是快排算法,这里就手写一遍快排,就当作重新复习一遍吧O(∩_∩)O

    /**
     * @author ghp
     * @title
     */
    class Solution {
        public void sortColors(int[] nums) {
            quickSort(nums, 0, nums.length - 1);
        }
    
        private void quickSort(int[] nums, int l, int r) {
            if (l >= r) {
                return;
            }
            // 划分区间,同时获取主元索引
            int pivot = partition(nums, l, r);
            quickSort(nums, l, pivot - 1);
            quickSort(nums, pivot + 1, r);
        }
    
        private int partition(int[] nums, int l, int r) {
            int pivot = nums[r];
            int i = l - 1;
            int j = l;
            int temp;
            // 划分区间(左侧区间元素<主元,右侧区间元素>=主元)
            while (j < r) {
                if (nums[j] < pivot) {
                    temp = nums[j];
                    nums[j] = nums[i + 1];
                    nums[i + 1] = temp;
                    i++;
                }
                j++;
            }
            // 将主元放到分界点
            temp = nums[r];
            nums[r] = nums[i + 1];
            nums[i + 1] = temp;
            return i + 1;
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
    • 空间复杂度: O ( 1 ) O(1) O(1)

    其中 n n n 为数组中元素的个数

  • 解法三:三路快排算法

    上面的代码使用的是荷兰国旗问题的算法,也叫三路快排算法。该算法的思想源于快速排序,可以在 O ( n ) O(n) O(n)的时间复杂度内将一个数组分为三部分:小于某个数、等于某个数和大于某个数。

    这应该是本体的最优解了!这方法实现起来也简单,也容易懂,就是很难想得到🤣

    /**
     * @author ghp
     * @title
     */
    class Solution {
        public void sortColors(int[] nums) {
            int i = 0;
            int j = 0;
            for (int k = 0; k < nums.length; k++) {
                int num = nums[k];
                nums[k] = 2;
                if (num < 2) {
                    nums[j++] = 1;
                }
                if (num < 1) {
                    nums[i++] = 0;
                }
            }
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( n ) O(n) O(n)
    • 空间复杂度: O ( 1 ) O(1) O(1)

    其中 n n n 为数组中元素的个数

  • 解法四:三指针算法

    /**
     * @author ghp
     * @title
     */
    class Solution {
        public void sortColors(int[] nums) {
            int i = 0;
            int j = 0;
            int k = nums.length - 1;
            while (i <= k) {
                if (nums[i] == 0) {
                    swap(nums, i++, j++);
                } else if (nums[i] == 2) {
                    swap(nums, i, k--);
                } else {
                    i++;
                }
            }
        }
    
        private void swap(int[] nums, int i, int j) {
            int t = nums[i];
            nums[i] = nums[j];
            nums[j] = t;
        }
    }
    
  • 解法五:归并排序

    这种解法也能过,但是不符合题意,因为题目要求要原地排序,不能使用第三方数组。我写在这里,单纯是为了复习一遍归并排序算法

    import java.util.Arrays;
    
    /**
     * @author ghp
     * @title
     */
    
    class Solution {
        public void sortColors(int[] nums) {
            divide(nums, 0, nums.length - 1);
            System.out.println(Arrays.toString(nums));
        }
    
        private void divide(int[] nums, int l, int r) {
            if (l >= r) {
                return;
            }
            int mid = (r - l) / 2 + l;
            divide(nums, l, mid);
            divide(nums, mid + 1, r);
            merge(nums, l, mid, r);
        }
    
        private void merge(int[] nums, int l, int mid, int r) {
            int i = l;
            int j = mid + 1;
            int k = 0;
            int[] temp = new int[r - l + 1];
            while (i <= mid && j <= r) {
                if (nums[i] < nums[j]) {
                    temp[k++] = nums[i++];
                } else {
                    temp[k++] = nums[j++];
                }
            }
            while (i <= mid) {
                temp[k++] = nums[i++];
            }
            while (j<=r){
                temp[k++] = nums[j++];
            }
            for (int m = 0; m < k; m++) {
                nums[l+m] = temp[m];
            }
        }
    }
    

参考题解

  • 极值求解:从Brute Force到1维DP - 编辑距离 - 力扣(LeetCode)
  • 最简洁的双指针解法!一次遍历,无交换操作 - 颜色分类 - 力扣(LeetCode)
  • 三指针解法,清晰易懂 - 颜色分类 - 力扣(LeetCode)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/648820.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue杂记:全选多个选择框

可以使用 v-model 来绑定一个布尔类型的变量来实现全选多个选择框的功能。具体步骤如下&#xff1a; 在data中定义一个数组&#xff0c;用来存储所有需要选择的项的状态。 在模板中使用 v-for 指令循环渲染每个选择框&#xff0c;并将每个选择框的状态绑定到数组中对应的项上。…

关于文件操作工具类及readLine()方法

这里写自定义目录标题 一&#xff1a;文件流通用操作工具类二、工具类讲解三、拓展报错解决 一&#xff1a;文件流通用操作工具类 package com.zkyq.file.common.utils;import com.zkyq.common.utils.DateUtils; import com.zkyq.file.common.service.EleRealDataService; imp…

报表生成器FastReport .Net用户指南:“Line“对象及属性

FastReport .Net是一款全功能的Windows Forms、ASP.NET和MVC报表分析解决方案&#xff0c;使用FastReport .NET可以创建独立于应用程序的.NET报表&#xff0c;同时FastReport .Net支持中文、英语等14种语言&#xff0c;可以让你的产品保证真正的国际性。 FastReport.NET官方版…

Maven入门

目录 1.为什么要学习Maven 1. 作为jar包的管理工具 2.作为构建管理工具 3.结论 2.什么是Maven 1. 构建包含的主要环节 2.依赖 3.Maven的工作机制 3.Maven的核心概念&#xff1a; 1.坐标 2.POM 3.约定的目录结构 4.生命周期 5.插件与目标 6.仓库 4.Maven操作 5…

现实版“超级英雄”!外卖小哥从10余米高桥纵身跳下救人

“我心里也很怂啊&#xff0c;但个人害怕跟别人的命比起来&#xff0c;肯定是救人要紧&#xff0c;人命关天的事&#xff0c;还用想吗&#xff1f;” 这是一位勇敢外卖小哥在接受媒体采访时说的。 语言虽朴实无华&#xff0c;却道出了一个重要的价值观&#xff1a;人命关天&…

APP测试面试题快问快答(四)

16.App测试的实时日志如何获取&#xff1f; 考察点&#xff1a;是否有移动app测试的日志获取相关经验 一般可以通过以下方式获取&#xff1a; 1.可以使用adb命令&#xff1a;adb logcat | findstr "com.sankuai.meituan" >d:\test.txt 2.用ddms抓取&#xff0…

Android中的异步处理之RxJava与协程(Coroutines)使用案例PK

RxJava一直是我长久以来的救星。它提供了丰富的功能&#xff0c;让我在Android编程中更加注重响应式思维。我的代码中到处都是Single、Subject和Completable。 而现在&#xff0c;协程成为了备受赞誉和推崇的选择&#xff0c;许多演讲和会议都推荐使用。于是我开始学习它。 为…

使用Vision Transformers实现高效语义分割的内容感知共享Token

文章目录 Content-aware Token Sharing for Efficient Semantic Segmentation with Vision Transformers摘要本文方法Content-aware token sharing frameworkContent-aware token sharing policy 实验结果 Content-aware Token Sharing for Efficient Semantic Segmentation wi…

Vue中如何进行滚动吸顶与侧边栏固定

Vue中如何进行滚动吸顶与侧边栏固定 在Vue应用程序中&#xff0c;当需要实现滚动吸顶和侧边栏固定效果时&#xff0c;我们可以使用一些技术来实现。这些技术包括CSS和JavaScript&#xff0c;可以帮助我们实现各种各样的滚动效果。 如何实现滚动吸顶&#xff1f; 滚动吸顶是指…

Ubuntu 系统如何使用 root 用户登录实例

Ubuntu 系统的默认用户名是 ubuntu&#xff0c;并在安装过程中默认不设置 root 帐户和密码。您如有需要&#xff0c;可在设置中开启允许 root 用户登录。具体操作步骤如下&#xff1a; 1. 使用 ubuntu 帐户登录轻量应用服务器。 2. 执行以下命令&#xff0c;设置 root 密码。…

Java判断一个字符串是否包含某个字符串

开发过程中&#xff0c;有时会判断一个字符串是否包含某个字符串的操作&#xff0c;这里总结判断方法。 方式一&#xff1a;contains()方法 理解&#xff1a;contains() 方法用于判断字符串中是否包含指定的字符或字符串。&#xff08;判断一个字符串是否包含某个字符串&#…

网上书店 Vue+Spring boot+H5+Uniapp

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 基于VueSpring boot的网上书城 目录一、项目模块二、项目模块三 技术选型四、运行环境五 .PC登录页面代码六 .H5登录页面代码 运行效果源码 目录 网上书店 VueSpring bootH5U…

Cos 文件上传下载

目录 方法一&#xff1a; maven依赖&#xff1a; UploadServlet upload.jsp 方法二&#xff1a; maven依赖 UploadServlet upload.jsp success.jsp error.jsp 运行结果&#xff1a; 百度文件上传插件&#xff1a; Web Uploader 本文通过JSPServlet的架构&#xff0c…

华为OD机试真题 JavaScript 实现【字符串变换最小字符串】【2022Q4 100分】

一、题目描述 给定一个字符串s&#xff0c;最多只能进行一次变换&#xff0c;返回变换后能得到的最小字符串&#xff08;按照字典序进行比较&#xff09;。 变换规则&#xff1a;交换字符串中任意两个不同位置的字符。 二、输入描述 一串小写字母组成的字符串s。 三、输出…

文件系统整体流程介绍

一、什么是文件系统 计算机的文件系统是一种存储和组织计算机数据的方法&#xff0c;它使得对其访问和查找变得容易&#xff0c;文件系统使用文件和树形目录的抽象逻辑概念&#xff0c;用户使用文件系统来保存数据不必关心数据实际保存在硬盘的地址为多少的数据块上&#xff0…

拨云见日:Redis和数据库之间的一致性如何保证?

概 述 Redis在使用过程中&#xff0c;有四个异常问题&#xff1a;缓存穿透、缓存击穿、缓存雪崩、以及缓存和数据库&#xff08;MySQL&#xff09;双写一致性问题。 前三个问题可能会因为业务体量的不同而有所不同&#xff0c;但是最后一个问题是无法避免的。就算你的电商业…

OPNET出现错误的解决办法汇总

文章目录 Packet pointer references unowned packet(<pk_id>) 错误Standard function stack imbalance 错误Invalid Memory Access 错误 在使用 OPNET Modeler 软件时&#xff0c;会遇到很多奇奇怪怪的报错&#xff0c;这篇文章收集的是自己在使用该软件时遇到的一些错误…

易基因:组学研究揭示不同牛品种的DNA甲基化、染色质和基因表达互作机制|科研进展

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 在全球范围内&#xff0c;牛为60多亿人提供了重要的营养来源。传染病是养牛生产的主要限制因素&#xff0c;且许多疾病人畜共患&#xff0c;因此与人类健康直接相关。近年来牛的许多复杂…

CBTC信号系统ATP子系统接口

ATP/ATO车载设备与车辆接口要求 ATP/ATO车载设备应实现与车辆制动装置的可靠接口&#xff0c;保证安全和对列车实施连续有效的控制。 ATP/ATO车载设备与车辆的接口分为开关量、模拟量、通信接口三种。 涉及行车安全的电气接口应采用安全输入&#xff0f;输出接口方式。 ATP…

electron 快速创建一个本地应用

参考官方文档流程 快速入门 | Electron 建议先全局安装electron&#xff0c;npm install -g electron 开发过程中可以在本地开发安装 使用electron快速创建一个web页面 &#xff0c;参考官方demo 实例 electron-quick-start 第一步&#xff1a; mkdir my-electron-app &am…