【代码随想录刷题记录】LeetCode27移除元素

题目地址

1. 思路

1.1 基本思路及代码的初步实现

基本思路大体上和卡尔老师的想法是一致的,详见代码随想录:数组:移除元素,暴力法大家都能想到,我这里写一下算法时间复杂度为 O ( n ) O(n) O(n)时候的思路(全文都是我思考的过程,不太喜欢照着答案解算法,还是有一个自己的思考过程印象深刻):

  • slow是慢指针,用来记录删除该元素后,每个元素对应的新下标slow
  • fast是快指针,用来记录删除该元素后,新数组的元素对应旧的数组的下标nums[fast]
  • i是循环迭代的变量,从0开始到nums.size()-1,也就是数组的全部元素对应的下标

每一次循环,当目标值val和数组nums[i]的值一致的时候,fast应该继续往下走,即fast++,而slow则要保持在原地,因为slow记录的是新数组的下标,如果删除一个数值的话,当前位置的下标因为删除了一个元素,其对应的是该删除的元素的下一个元素,也就是nums[slow]=nums[fast],fast指向的是新元素的值,slow的值则是fast所指向的新元素的值的下标(相当于向前移动元素);
当目标值val和数组nums[i]的值不一样的时候,不删除当前元素,fast和slow都继续向前走,但是在向前走之前,还要执行nums[slow]=nums[fast],因为可能之前还删除过元素,所以还要继续向前移动元素,而且假设在fast和slow都向前走之后才执行nums[slow]=nums[fast],假如此时fast++后,超出了数组的范围,则fast的值就是不合理的下标值,此时会报错提示越界,所以要在slow++和fast++之前执行nums[slow]=nums[fast]。
而谈到这里,我们还注意到,当i遍历到数组中最后一个元素下标的时候,假如此时nums[i]与val是相等的,则说明最后一个元素也要删除,删除末尾元素,fast不需要再一次移动,因为fast再一次移动就越界了,所以还要在nums[i]与val相等的条件下再加一个判断条件,判断fast是否越界,也就是fast == nums.size()这个条件,然后我们还要返回新数组的长度,如果i遍历到最后,nums[i]与val不相等,则slow和fast都向前移动,slow刚好比新数组的最后元素下标多1(越界),则slow是新数组长度;如果nums[i]与val相等,说明要删除这最后一个元素,此时slow正好指向这个最后删除的元素,也就是新数组越界后的第一个内存位置(对应旧数组的最后一个元素位置),而fast在旧数组的越界1个的位置(nums.size()),此时返回slow也是新数组的长度;假设fast遍历到最后没能遍历到旧数组越界的位置且val与nums[i]相等(比如:[1,2,3,3,3]删去3),我们删除的元素对应的是slow所指向的元素,那删除后,slow自然也是指向新数组越界一个内存位置的地方,也是新数组的长度。
看了这么一大段文字描述,接下来看看代码:

class Solution {
public:
    // 引用传递,直接改nums,是改其本身,不是拷贝
    int removeElement(vector<int>& nums, int val) {
        int slow = 0; //慢指针,用来记录删除该元素后,每个元素对应的新下标slow
        int fast = 0; //快指针,用来记录删除该元素后,新数组的元素对应旧的数组的下标nums[fast]
        //每次循环,如果在数组中遇到目标值val,则slow停一下,fast继续走
        //slow停一下是因为,我们删除一个元素后,slow就不能继续再往下遍历,因为删除了一个元素,后面的下标都要减1
        //所以slow停一次,fast继续向前走
        //删几次,slow就停几次,然后把对应的新元素nums[fast]赋值过来
        //slow是每个元素对应的新下标,所以nums[slow] = nums[fast],这样就能够将新数组的元素和新数组的下标对应起来
        //slow遍历到最后,会在新数组的最后一个元素的下标的基础上slow++
        for(int i = 0; i < nums.size(); i++)
        {
            //当前元素不是要删除的元素,nums[slow] = nums[fast]
            //因为新数组还是旧数组(没删除元素),所以[slow]对应的还是nums[fast]
            //就算之前slow停止了一次,删除了元素,但是到本元素nums[i]的时候
            //由于当前的元素不是要删除的元素,所以新数组和旧数组(之前删过元素的数组)一样
            if(val != nums[i])
            {
                //先执行是防止fast越界(针对旧数组)
                nums[slow] = nums[fast];
                slow++;
                fast++;
            }
            //当前是要删除的元素,slow要停一下,fast继续走
            else
            {
                /*当i遍历到数组中最后一个元素下标的时候,
                假如此时nums[i]与val是相等的,
                则说明最后一个元素也要删除,
                删除末尾元素,fast不需要再一次移动,
                因为fast再一次移动就越界了,
                所以还要在nums[i]与val相等的条件下再加一个判断条件,
                判断fast是否越界,也就是fast == nums.size()这个条件*/
                fast++;
                if(fast == nums.size())
                {
                    /*当i遍历到数组中最后一个元素下标的时候,
                    如果nums[i]与val相等,说明要删除这最后一个元素,
                    此时slow正好指向这个最后删除的元素,
                    也就是新数组越界后的第一个内存位置
                    (对应旧数组的最后一个元素位置),
                    而fast在旧数组的越界1个的位置(nums.size()),
                    此时返回slow也是新数组的长度*/
                    return slow;
                }
                else
                {
                    nums[slow] = nums[fast];
                }
            }
            
        }
        /*返回新数组的长度,如果i遍历到最后,
        nums[i]与val不相等,则slow和fast都向前移动
        slow刚好比新数组的最后元素下标多1(越界),
        则slow是新数组长度*/
        /*假设fast遍历到最后没能遍历到旧数组越界的位置且val与nums[i]相等
        (比如:[1,2,3,3,3]删去3),
        我们删除的元素对应的是slow所指向的元素,
        那删除后,slow自然也是指向新数组越界一个内存位置的地方,
        也是新数组的长度。*/
        return slow;
    }
};

1.2 三种基本情况

这个算法能遇到的情况如下:

    1. 要移除的值在数组的中且不在末尾
    1. 要移除的值在数组末尾(逻辑上不用移动,直接舍弃末尾)
    1. 要移除的值不在数组中

下面根据这三种基本情况,我们来模拟一下其运行过程

1.3 模拟运行过程

1.3.1 要移除的值在数组的中且不在末尾

假设有这样一个数组nums[1, 2, 2, 3],val=2:
i=0
由于 nums [ i ] = nums [ 0 ] = 1 ≠ val = 2 \text{nums}[i]=\text{nums}[0]=1\ne \text{val}=2 nums[i]=nums[0]=1=val=2,则

i=1
由于 nums [ i ] = nums [ 1 ] = 2 = val = 2 \text{nums}[i]=\text{nums}[1]=2= \text{val}=2 nums[i]=nums[1]=2=val=2,则

又由于 fast = 2 ≠ nums.size() = 4 \text{fast}=2\ne\text{nums.size()}=4 fast=2=nums.size()=4,则

注意到,slow在此处停止移动一次,因为找到了要删除的元素
i=2
由于 nums [ i ] = nums [ 2 ] = 2 = val = 2 \text{nums}[i]=\text{nums}[2]=2= \text{val}=2 nums[i]=nums[2]=2=val=2,则

又由于 fast = 3 ≠ nums.size() = 4 \text{fast}=3\ne\text{nums.size()}=4 fast=3=nums.size()=4,则

注意到,slow在此处停止移动一次,因为找到了要删除的元素

i=3
由于 nums [ i ] = nums [ 3 ] = 3 ≠ val = 2 \text{nums}[i]=\text{nums}[3]=3\ne \text{val}=2 nums[i]=nums[3]=3=val=2,则



此时循环结束,可以看到slow恰好是在新数组的越界一个单元的位置,也就是新数组的长度,即return slow,示意图如下:

1.3.1 要移除的值在数组末尾

假设有这样一个数组nums[1, 2, 2, 3],val=3:
i=0
由于 nums [ i ] = nums [ 0 ] = 1 ≠ val = 3 \text{nums}[i]=\text{nums}[0]=1\ne \text{val}=3 nums[i]=nums[0]=1=val=3,则

i=1
由于 nums [ i ] = nums [ 1 ] = 2 ≠ val = 3 \text{nums}[i]=\text{nums}[1]=2\ne \text{val}=3 nums[i]=nums[1]=2=val=3,则

i=2
由于 nums [ i ] = nums [ 2 ] = 2 ≠ val = 3 \text{nums}[i]=\text{nums}[2]=2\ne \text{val}=3 nums[i]=nums[2]=2=val=3,则

i=3
由于 nums [ i ] = nums [ 3 ] = 3 = val = 3 \text{nums}[i]=\text{nums}[3]=3= \text{val}=3 nums[i]=nums[3]=3=val=3,则

又由于 fast = 3 ≠ nums.size() = 4 \text{fast}=3\ne\text{nums.size()}=4 fast=3=nums.size()=4,则return slow;

1.3.2 要移除的值不在数组中

假设有这样一个数组nums[1, 2, 2, 3],val=4:
i=0
由于 nums [ i ] = nums [ 0 ] = 1 ≠ val = 4 \text{nums}[i]=\text{nums}[0]=1\ne \text{val}=4 nums[i]=nums[0]=1=val=4,则

i=1
由于 nums [ i ] = nums [ 1 ] = 2 ≠ val = 4 \text{nums}[i]=\text{nums}[1]=2\ne \text{val}=4 nums[i]=nums[1]=2=val=4,则

i=2
由于 nums [ i ] = nums [ 2 ] = 2 ≠ val = 4 \text{nums}[i]=\text{nums}[2]=2\ne \text{val}=4 nums[i]=nums[2]=2=val=4,则

i=3
由于 nums [ i ] = nums [ 3 ] = 3 ≠ val = 4 \text{nums}[i]=\text{nums}[3]=3\ne \text{val}=4 nums[i]=nums[3]=3=val=4,则

1.4 代码进一步优化

至此,算法的解的三种情况我们都举了例子论证完了,但是注意观察,每次i自增的时候,fast在if和else两个条件里都自增,似乎fast可以放到if else条件外面自增,我们还注意到,if条件下,我们先执行的nums[slow]=nums[fast]赋值语句,然后才进行的fast++语句,这就说明,我们不能简单地将fast放在if else条件之外,我们思考一下,我们的if(val!=nums[i])的条件里,是先执行的nums[slow]=nums[fast]赋值语句而后进行的slow和fast向前移动一个单位,这是因为,如果我们先移动,再赋值,当fast移动到数组越界处的时候,nums[slow]=nums[fast]这条语句就会报越界的错误,所以我们需要判断一下fast是否越界,如果越界直接返回slow,并且将else的条件下的代码稍微变动,这样就变成了如下的等价形式(也是可以通过的):

class Solution {
public:
    // 引用传递,直接改nums,是改其本身,不是拷贝
    int removeElement(vector<int>& nums, int val) {
        int slow = 0; //慢指针,用来记录删除该元素后,每个元素对应的新下标slow
        int fast = 0; //快指针,用来记录删除该元素后,新数组的元素对应旧的数组的下标nums[fast]
        for(int i = 0; i < nums.size(); i++)
        {
            if(val != nums[i])
            {
                slow++;
                fast++;
                //先移动slow和fast,再判断其是否越界,这样就算fast越界,也能直接返回结果
                if(fast == nums.size())
                {
                    return slow;
                }
                nums[slow] = nums[fast];
            }
            else
            {
                fast++;
                if(fast == nums.size())
                {
                    return slow;
                }
                nums[slow] = nums[fast];
            }
            
        }
        return slow;
    }
};

此时,fast++在两个条件里都有,可以单独拿到if else外面(也是可以通过的):

class Solution {
public:
    // 引用传递,直接改nums,是改其本身,不是拷贝
    int removeElement(vector<int>& nums, int val) {
        int slow = 0; //慢指针,用来记录删除该元素后,每个元素对应的新下标slow
        int fast = 0; //快指针,用来记录删除该元素后,新数组的元素对应旧的数组的下标nums[fast]
        for(int i = 0; i < nums.size(); i++)
        {
            fast++;
            if(val != nums[i])
            {
                slow++;
                //先移动slow和fast,再判断其是否越界,这样就算fast越界,也能直接返回结果
                if(fast == nums.size())
                {
                    return slow;
                }
                nums[slow] = nums[fast];
            }
            else
            {
                if(fast == nums.size())
                {
                    return slow;
                }
                nums[slow] = nums[fast];
            }
            
        }
        return slow;
    }
};

然后我们又发现,每次i自增的时候,fast必然自增,是不是可以将fast 和 i等效,直接用fast来进行迭代,而且使用fast进行循环迭代,保证不能越界,因为我们最后返回的是slow,之前的情况下,当i=3的时候,如果要删除的元素不在数组之中,fast++会导致越界,但是我们已经证明slow所指才是我们需要的新数组的长度,于是我们尝试将fast等效i在循环中的迭代作用,我们思考一下,for循环的迭代变量一般是等到for循环中的代码执行后,再进行自增,而我们既然选择fast作为迭代变量进行自增,那么我们就要想方设法先将最上面的fast++语句放到for循环内的最后执行,所以我们还是要看一下之前的代码:

class Solution {
public:
    // 引用传递,直接改nums,是改其本身,不是拷贝
    int removeElement(vector<int>& nums, int val) {
        int slow = 0; //慢指针,用来记录删除该元素后,每个元素对应的新下标slow
        int fast = 0; //快指针,用来记录删除该元素后,新数组的元素对应旧的数组的下标nums[fast]
        for(int i = 0; i < nums.size(); i++)
        {
            if(val != nums[i])
            {
                nums[slow] = nums[fast];
                slow++;
                fast++;
            }
            else
            {
                fast++;
                if(fast == nums.size())
                {
                    return slow;
                }
                else
                {
                    nums[slow] = nums[fast];
                }
            }
            
        }
        return slow;
    }
};

我们原来的代码中,在if(val != nums[i])条件里,nums[slow] = nums[fast];先执行的初衷是为了防止fast和slow越界,而else条件里加上了防止fast越界的情况,那我们也把else条件里的赋值语句nums[slow] = nums[fast];放到fast++;语句前面来执行,得到了如下代码(顺利通过):

class Solution {
public:
    // 引用传递,直接改nums,是改其本身,不是拷贝
    int removeElement(vector<int>& nums, int val) {
        int slow = 0; //慢指针,用来记录删除该元素后,每个元素对应的新下标slow
        int fast = 0; //快指针,用来记录删除该元素后,新数组的元素对应旧的数组的下标nums[fast]
        for(int i = 0; i < nums.size(); i++)
        {
            if(val != nums[i])
            {
                nums[slow] = nums[fast];
                slow++;
                fast++;
            }
            else
            {
                nums[slow] = nums[fast];
                fast++;
            }
            
        }
        return slow;
    }
};

我们再进行一下等效变换,将两个if else的条件中的重复部分取出来,nums[slow] = nums[fast];语句在判断条件前,fast++;语句在判断条件后,得到如下代码(顺利通过):

class Solution {
public:
    // 引用传递,直接改nums,是改其本身,不是拷贝
    int removeElement(vector<int>& nums, int val) {
        int slow = 0; //慢指针,用来记录删除该元素后,每个元素对应的新下标slow
        int fast = 0; //快指针,用来记录删除该元素后,新数组的元素对应旧的数组的下标nums[fast]
        for(int i = 0; i < nums.size(); i++)
        {
            nums[slow] = nums[fast];
            if(val != nums[i])
            {
                slow++;
            }
            fast++;
            
        }
        return slow;
    }
};

此时我们观察,fast自增操作已在循环体内部的最后部分了,那就可以让fast代替i做迭代变量了,修改代码为(顺利通过):

class Solution {
public:
    // 引用传递,直接改nums,是改其本身,不是拷贝
    int removeElement(vector<int>& nums, int val) {
        int slow = 0; //慢指针,用来记录删除该元素后,每个元素对应的新下标slow
        for(int fast = 0; fast < nums.size(); fast++)
        {
            nums[slow] = nums[fast];
            if(val != nums[fast])
            {
                slow++;
            }       
        }
        return slow;
    }
};

但是修改到这个时候,它的实际复杂度并不好,我们继续思考,有些时候,其实nums[slow] = nums[fast];赋值是没必要的,考虑刚才的例子:
假设有这样一个数组nums[1, 2, 2, 3],val=2:
i=1
由于 nums [ i ] = nums [ 1 ] = 2 = val = 2 \text{nums}[i]=\text{nums}[1]=2= \text{val}=2 nums[i]=nums[1]=2=val=2,则

又由于 fast = 2 ≠ nums.size() = 4 \text{fast}=2\ne\text{nums.size()}=4 fast=2=nums.size()=4,则

我们先是移动了fast,然后才进行nums[slow]=nums[fast]的赋值操作,但是我们修改后的代码在此处会这样操作:
先进行一次赋值,这个赋值其实是无效的,在nums[fast]和val相等的时候,我们只需要让slow原地等待一次,fast向前走一次,此时没必要进行赋值一次,只有在不等的时候,赋值是有效的,赋值相当于逻辑上从后向前移动

然后再进行指针的移动:

它将真正从后向前赋值的过程放到了val != nums[fast]中执行,所以下一次循环必须先执行赋值操作再进行slow的自增,我们完全可以把赋值过程放到val != nums[fast]条件中执行,因为我们只需要在不等的情况下移动元素。

1.5 代码最终实现

有了上面这些思考,我们发现,其实还是最开始的思路,相等的情况下,slow等一下(不自增),fast自增,不相等的情况下,slow和fast一起自增,并且还要执行赋值过程,而且要注意是先赋值再让slow自增,原因刚才已经提到了,代码最终优化为(顺利通过):

class Solution {
public:
    // 引用传递,直接改nums,是改其本身,不是拷贝
    int removeElement(vector<int>& nums, int val) {
        int slow = 0; //慢指针,用来记录删除该元素后,每个元素对应的新下标slow
        for(int fast = 0; fast < nums.size(); fast++)
        {
            if(val != nums[fast])
            {
                // 下一次循环必须先执行赋值操作再进行slow的自增(对应上文)
                nums[slow] = nums[fast];
                slow++;
            }       
        }
        return slow;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习】YOLOv5,烟雾和火焰,目标检测,防火检测,森林火焰检测

文章目录 数据收集和数据标注查看标注好的数据的脚本下载yolov5创建 dataset.yaml训练参数开始训练yolov5n训练训练后的权重下载gradio部署 数据收集和数据标注 搜集数据集2w张。 pip install labelme labelme 然后标注矩形框和类别。 下载数据请看这里&#xff1a; https:…

2023年江西省电子专题赛——解析一

由于网上对这个竞赛资料甚少&#xff0c;为了方便省内学子交流学习&#xff0c;可加Q群聊&#xff1a;778772385 电源部分&#xff1a;比赛中只给了3个IN4007整流管&#xff0c;无法构成传统整流桥的形式&#xff0c;并且题目又要求全波整流。 我这边用两个二极管构成全波整流…

Web3解密:理解去中心化应用的核心原理

引言 在当前数字化时代&#xff0c;去中心化技术和应用正在逐渐引起人们的关注和兴趣。Web3技术作为去中心化应用&#xff08;DApps&#xff09;的基础&#xff0c;为我们提供了一个全新的互联网体验。但是&#xff0c;对于许多人来说&#xff0c;这个复杂的概念仍然充满了神秘…

【数据结构与算法】:手搓顺序表(Python篇)

文章目录 一、顺序表的概念二、顺序表的实现1. 顺序表的创建1.1 扩容1.2 整体建立顺序表 2. 顺序表的基本运算算法2.1 顺序表的添加&#xff08;尾插&#xff09;2.2 指定位置插入2.3 指定位置删除2.4 顺序表的查找2.5 顺序表元素的索引访问2.6 顺序表元素的修改2.7 顺序表长度…

Mouse without Borders(无界鼠标)使用教程 多台电脑(最多4)共用鼠标键盘,换言之一套键鼠操作多台电脑,跨电脑文件拖动传输

Mouse without Borders&#xff08;无界鼠标&#xff09;使用教程 目的&#xff1a;多台电脑&#xff08;最多4&#xff09;共用鼠标键盘&#xff0c;换言之一套键鼠操作多台电脑。 优势&#xff1a;微软官方软件&#xff0c;对于windows系统友好&#xff0c;轻量实用。 劣势…

【Diffusion实战】训练一个diffusion模型生成蝴蝶图像(Pytorch代码详解)

上一篇Diffusion实战是确确实实一步一步走的公式&#xff0c;这回采用一个更方便的库&#xff1a;diffusers&#xff0c;来实现Diffusion模型训练。 Diffusion实战篇&#xff1a;   【Diffusion实战】训练一个diffusion模型生成S曲线&#xff08;Pytorch代码详解&#xff09;…

锁,数据同步

目录 原子操作中断控制自旋锁信号量小结 经常遇到数据同步的问题&#xff0c;具体有哪些情况呢&#xff1f;来聊一聊。我知道的&#xff0c;应该有以下四种&#xff0c;原子操作&#xff0c;中断控制&#xff0c;自旋锁和信号量。 原子操作 适用情况和场景 原子操作经常用在单…

vue实现录音并转文字功能,包括PC端web,手机端web

vue实现录音并转文字功能&#xff0c;包括PC端&#xff0c;手机端和企业微信自建应用端 不止vue&#xff0c;不限技术栈&#xff0c;vue2、vue3、react、.net以及原生js均可实现。 原理 浏览器实现录音并转文字最快捷的方法是通过Web Speech API来实现&#xff0c;这是浏览器…

【Linux系统编程】第八弹---权限管理操作(中)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、修改文件权限的做法(二) 2、文件类型 3、可执行权限 4、创建文件/目录的默认权限 4.1、权限掩码 总结 前面一弹我们学…

CH4INRULZ-v1靶机练习实践报告

CH4INRULZ-v1靶机练习实践报告 1 安装靶机 靶机是.ova文件&#xff0c;需要用VirtualBox打开&#xff0c;但我习惯于使用VMWare,因此修改靶机文件&#xff0c;使其适用于VMWare打开。 解压ova文件&#xff0c;得到.ovf文件和.vmdk文件。直接用VMWare打开.ovf文件即可。 2 夺…

社区新零售:重构邻里生活圈,赋能美好未来

新时代的邻里脉动 在城市的肌理中&#xff0c;社区作为生活的基本单元&#xff0c;正经历一场由新零售引领的深刻变革。社区新零售&#xff0c;以其独特的商业模式、创新的技术手段和以人为本的服务理念&#xff0c;重新定义了社区商业的边界&#xff0c;重构了邻里生活的形态…

[C++ QT项目实战]----C++ QT系统实现多线程通信

前言 在C QT中&#xff0c;多线程通信原理主要涉及到信号与槽机制和事件循环机制。 1、信号与槽机制&#xff1a; 在QT中&#xff0c;信号与槽是一种用于对象间通信的机制。对象可以通过发送信号来通知其他对象&#xff0c;其他对象通过连接槽来接收信号并进行相应的处…

软件物料清单(SBOM)生成指南 .pdf

如今软件安全攻击技术手段不断升级&#xff0c;攻击数量显著增长。尤其是针对软件供应链的安全攻击&#xff0c;具有高隐秘性、追溯难的特点&#xff0c;对企业软件安全威胁极大。 同时&#xff0c;软件本身也在不断地更新迭代&#xff0c;软件内部成分安全性在持续变化浮动。…

web题目实操 5(备份文件和关于MD5($pass,true)注入的学习)

1.[ACTF2020 新生赛]BackupFile &#xff08;1&#xff09;打开页面后根据提示是备份文件 &#xff08;2&#xff09;查看源码发现啥都没有 &#xff08;3&#xff09;这里啊直接用工具扫描&#xff0c;可以扫描到一个文件名为&#xff1a;/index.php.bak的文件 &#xff08;…

json解析大全

JSON解析案例1 将String转为JSONObject JSONObject res JSONObject.parseObject(result);获取documents JSONArray array res.getJSONObject("result").getJSONArray("documents");遍历JSONArray for (int i 0; i < array.size(); i) {JSONObject…

IDEA pom.xml依赖警告

IDEA中&#xff0c;有时 pom.xml 中会出现如下提示&#xff1a; IDEA 2022.1 升级了检测易受攻击的 Maven 和 Gradle 依赖项&#xff0c;并建议修正&#xff0c;通过插件 Package Checker 捆绑到 IDE 中。 这并不是引用错误&#xff0c;不用担心。如果实在强迫症不想看到这个提…

稳态视觉诱发电位 (SSVEP) 分类学习系列 (4) :Temporal-Spatial Transformer

稳态视觉诱发电位分类学习系列:Temporal-Spatial Transformer 0. 引言1. 主要贡献2. 提出的方法2.1 解码的主要步骤2.2 网络的主要结构 3. 结果和讨论3.1 在两个数据集下的分类效果3.2 与基线模型的比较3.3 消融实验3.4 t-SNE 可视化 4. 总结欢迎来稿 论文地址&#xff1a;http…

Hive——DDL(Data Definition Language)数据定义语句用法详解

1.数据库操作 1.1创建数据库 CREATE DATABASE [IF NOT EXISTS] database_name [COMMENT database_comment] [LOCATION hdfs_path] [WITH DBPROPERTIES (property_nameproperty_value, ...)];IF NOT EXISTS&#xff1a;可选参数&#xff0c;表示如果数据库已经存在&#xff0c…

软考-系统分析师-精要2

5、可行性分类 经济可行性&#xff1a;成本收益分析&#xff0c;包括建设成本、运行成本和项目建设后可能的经济收益。 技术可行性&#xff1a;技术风险分析&#xff0c;现有的技术能否支持系统目标的实现&#xff0c;现有资源&#xff08;员工&#xff0c;技术积累&#xff0…

GEM TSU Interface Details and IEEE 1588 Support

摘要&#xff1a;Xilinx ZNYQ ULTRASCALE MPSOC的GEM和1588的使用 对于FPGA来说&#xff0c;只需要勾选一些znyq的配置就行了&#xff0c;其余的都是软件的工作&#xff1b; 所有配置都勾选之后&#xff0c;最终会露出来的接口如下&#xff1a; GEM需要勾选的配置如下&#xf…