27. 移除元素(双指针相关)

双指针法

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。

27. 移除元素

27. 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:
给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。

示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4

你不需要考虑数组中超出新长度后面的元素。

思路:使用快慢指针,fast用于遍历整个数组,判断指向的数值是否是valslow用于记录数值不是val的元素的个数,也方便在此处改变原nums数组中元素的值。

定义快慢指针

快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置

Go代码

func removeElement(nums []int, val int) int {
    //思路:使用快慢指针,fast用于遍历整个数组,判断指向的数值是否是val
    //slow用于记录数值不是val的元素的个数,也方便在此处改变原nums数组中元素的值
    if len(nums) == 0 {
        return -1
    }

    slow := 0
    for  _,num:= range nums {
        if num == val { // 当前值是val就跳过
            continue
        }
        nums[slow] = num // 当前值不是val,就放在慢指针的位置,相当于后续元素前移
        slow++
    }
    return slow
}

在这里插入图片描述

26. 删除有序数组中的重复项

26. 删除有序数组中的重复项

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。返回 k

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过。

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示:

  • 1 < = n u m s . l e n g t h < = 3 ∗ 1 0 4 1 <= nums.length <= 3 * 10^4 1<=nums.length<=3104
  • − 1 0 4 < = n u m s [ i ] < = 1 0 4 -10^4 <= nums[i] <= 10^4 104<=nums[i]<=104
  • n u m s 已按非严格递增排列 nums 已按 非严格递增 排列 nums已按非严格递增排列

思路: 快慢指针,从第二个数开始,只要与前一个数相等,则可以跳过他,快指针移动一步,不相等时,放于慢指针的位置,慢指针移动一步。

func removeDuplicates(nums []int) int {
    if len(nums) == 0 {
        return -1
    }
    if len(nums) == 1 {
        return 1
    }

    // 简单遍历一遍,遇到重复的则跳过,遇到不重复的则放到数组开始出现重复时的下标处即可
    slow,fast := 1,1 // 第一个不重复的元素是从索引1开始的
    for i := fast;i < len(nums);i++ {
        if nums[i] == nums[i - 1] {
            continue
        }
        nums[slow] = nums[i]
        slow++
    }
    return slow
}

在这里插入图片描述

283. 移动零

283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]
输出: [0]

提示:

1 < = n u m s . l e n g t h < = 1 0 4 1 <= nums.length <= 10^4 1<=nums.length<=104
− 2 31 < = n u m s [ i ] < = 2 31 − 1 -2^{31} <= nums[i] <= 2^{31} - 1 231<=nums[i]<=2311

进阶:你能尽量减少完成的操作次数吗?

思路:实际所有非0数移动到前面之后,后续的索引位置都赋值为0就相当于将0移到了末尾

Go代码

func moveZeroes(nums []int)  {
    // 因为要求原地操作,又要将0移到末尾
    // 实际所有非0数移动到前面之后,后续的索引位置都赋值为0就相当于将0移到了末尾
    if len(nums) == 0 {
        return 
    }

    slow ,fast := 0,0
    for i := fast ;i < len(nums);i++ {
        if nums[i] == 0 {
            continue //i进入下轮循环i++,实际上,i充当的就是快指针
        }
        nums[slow] = nums[i]
        slow++
    }

    // 后续的位置置为0
    for i:= slow;i < len(nums);i++ {
        nums[i] = 0
    }
    return 
}

在这里插入图片描述

844. 比较含退格的字符串

844. 比较含退格的字符串

给定 st 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true# 代表退格字符。

注意:如果对空文本输入退格字符,文本继续为空。

示例 1:

输入:s = "ab#c", t = "ad#c"
输出:true
解释:s 和 t 都会变成 "ac"

示例 2:

输入:s = "ab##", t = "c#d#"
输出:true
解释:s 和 t 都会变成 ""

示例 3:

输入:s = "a#c", t = "b"
输出:false
解释:s 会变成 "c",但 t 仍然是 "b"

提示:

  • 1 < = s . l e n g t h , t . l e n g t h < = 200 1 <= s.length, t.length <= 200 1<=s.length,t.length<=200
  • s 和 t 只含有小写字母以及字符 ‘#’

进阶:

你可以用 O ( n ) O(n) O(n) 的时间复杂度和 O ( 1 ) O(1) O(1) 的空间复杂度解决该问题吗?

思路:主要是要注意不要索引越界

Go代码

func backspaceCompare(s string, t string) bool {
    // 分别遍历两个数组,如果遇到#,则慢指针回退一步,否则将当前数字放于慢指针处,最后比较两个两个字符串是否相等
    if len(s) == 0 && len(t) == 0 {
        return true
    }

    sb,tb := []byte(s),[]byte(t)
    slow,slow2,fast := 0,0,0
    for i := fast ;i < len(sb);i++{
        if sb[i] == '#' { 
             if slow > 0 { // 注意slow不要越界,因为可能第一个字符就是#,或出现的#比已经出现的字符更多
                slow-- 
            }
            continue // 可以遇到多个#,此时slow已经是0,无需递减可直接continue
        }
        sb[slow] = sb[i]
        slow++
    }
    sbRes := string(sb[0:slow])
    fmt.Println(sbRes)

    for i := fast ;i < len(tb);i++{
        if tb[i] == '#'  { 
            if slow2 > 0 { // 注意slow2不要越界,因为可能第一个字符就是#,或出现的#比已经出现的字符更多
                slow2-- 
            }
            continue // 可以遇到多个#,此时slow2已经是0,无需递减可直接continue
        }
        tb[slow2] = tb[i]
        slow2++
    }
    tbRes := string(tb[0:slow2])
    fmt.Println(tbRes)

    if sbRes == tbRes {
        return true
    }

    return false
}

在这里插入图片描述

方法二:使用栈来解
最容易想到的方法是将给定的字符串中的退格符和应当被删除的字符都去除,还原给定字符串的一般形式。然后直接比较两字符串是否相等即可。

具体地,我们用栈处理遍历过程,每次我们遍历到一个字符:

  • 如果它是退格符,那么我们将栈顶弹出;

  • 如果它是普通字符,那么我们将其压入栈中。

Go代码

func build(str string) string {
    s := []byte{}
    for i := range str {
        if str[i] != '#' {
            s = append(s, str[i])
        } else if len(s) > 0 {
            s = s[:len(s)-1]
        }
    }
    return string(s)
}

func backspaceCompare(s, t string) bool {
    return build(s) == build(t)
}

977. 有序数组的平方

977. 有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

示例 2:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

提示:

  • 1 < = n u m s . l e n g t h < = 1 0 4 1 <= nums.length <= 10^4 1<=nums.length<=104
  • − 1 0 4 < = n u m s [ i ] < = 1 0 4 -10^4 <= nums[i] <= 10^4 104<=nums[i]<=104
  • n u m s 已按非递减顺序排序 nums 已按 非递减顺序 排序 nums已按非递减顺序排序

进阶:

请你设计时间复杂度为 O ( n ) O(n) O(n)的算法解决本问题

思路:我们知道一个负数平方后,会是正数,所以如果两个数都是负数的情况,负值越小(如-5-4小),平方后反而越大(25大于16)。

双指针法,因为负数的平方是正数,所以平方后较大值一定是在数组的两端,越往中间靠近0的位置,平方后越小

Go 代码

func sortedSquares(nums []int) []int {
    // 思路:双指针法,因为负数的平方是正数,所以平方后较大值一定是在数组的两端,越往中间靠近0的位置,平方后越小

    if len(nums) == 0 {
        return []int{}
    }

    res := make([]int,len(nums))
    k := len(nums) - 1 // 从后往前放元素,因为较大的放结果数组后面

    i,j := 0,len(nums) - 1
    // 因为最后指向的那个数字也是要计算放入res中的,所以是<=,而不是<
    for(i <= j) { 
        if nums[i] * nums[i] < nums[j] * nums[j] {
            res[k] = nums[j] * nums[j]
            j--
        } else {
            res[k] = nums[i] * nums[i]
            i++
        }
        k-- // 尾部索引减一
    }

    return res

}

在这里插入图片描述

### 回答1: 1. 首先需要在n1盒子安装Armbian操作系统,可以从官网下载对应的镜像文件,然后通过刷写工具将其烧录到SD卡中。 2. 安装完成后,进入系统后台,使用命令行工具安装Docker。可以使用以下命令: ``` curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh ``` 3. 安装完成后,可以使用以下命令验证Docker是否安装成功: ``` sudo docker version ``` 4. 如果需要使用Docker Compose,可以使用以下命令安装: ``` sudo apt-get install -y python3-pip sudo pip3 install docker-compose ``` 5. 安装完成后,可以使用以下命令验证Docker Compose是否安装成功: ``` docker-compose version ``` 6. 至此,n1盒子上的Armbian系统已经成功安装DockerDocker Compose,可以开始使用了。 ### 回答2: N1盒子是一种基于ARM架构的迷你计算机,它广泛应用于家庭娱乐、智能家居、物联网等领域,这些领域的应用都需要使用容器技术,因此,在N1盒子安装Docker是非常有必要的。以下是在N1盒子安装Docker的步骤: 1. 下载Armbian系统 Armbian系统是一款专门为ARM架构开发的操作系统,可以支持多种型号的开发板和迷你计算机,需要选择适合自己设备的版本进行下载,同时也需要确认下载的版本是否支持Docker。下载完成后,将系统烧录到SD卡中。 2. 连接N1盒子 将SD卡插入N1盒子的卡槽中,同时插入网线、鼠标、键盘和显示器,然后通电。随后,在显示器上会出现Armbian系统的安装界面,按照指示进行设置。 3. 安装Docker 安装Docker需要先进行系统更新,使用以下命令: sudo apt-get update sudo apt-get upgrade 然后安装Docker需要安装的依赖: sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg2 \ software-properties-common 接着,添加Docker的官方GPG密钥: curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - 然后添加Docker软件源: sudo add-apt-repository \ "deb [arch=arm64] https://download.docker.com/linux/debian \ $(lsb_release -cs) \ stable" 最后,安装Docker: sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io 4. 测试Docker 安装完成后,使用以下命令启动Docker: sudo systemctl enable docker sudo systemctl start docker 确认Docker是否已经正确安装,可以使用以下命令: sudo docker run hello-world 如果Docker已经正确安装,将会显示一些信息,表示安装成功。 总体来说,在N1盒子安装Docker并不是一件复杂的事情,只需要按照上述步骤进行即可,但是在安装过程中需要注意以下几点: 1. 确认下载的Armbian系统和Docker是否支持自己的N1盒子设备; 2. 如果不能连接显示器的话,需要通过SSH远程连接N1盒子,再进行安装和配置; 3. 在安装过程中,如果出现错误信息,需要仔细阅读错误提示,并按照提示进行处理。 ### 回答3: n1盒子是一种开源的硬件平台,是基于arm架构的小型电脑,主要运行在Linux系统上。Armbian是一种灵活且易于使用的Linux发行版,它支持各种开发板和嵌入式系统,包括n1盒子。 在n1盒子安装Docker可以让您轻松地部署和运行容器化应用程序。Docker是一个开源的容器管理平台,它允许您将应用程序和其依赖项打包到可移植的容器中,并通过简单的命令在各种环境中运行。 以下是在n1盒子安装Docker的步骤: 1. 安装Armbian操作系统 在n1盒子安装Armbian操作系统是必须的。Armbian安装过程相对简单,您可以按照官方文档的指示进行安装。 2. 安装DockerArmbian操作系统上安装Docker非常简单,只需运行以下命令: sudo apt-get update sudo apt-get install docker-ce 这将从Docker的官方仓库安装Docker CE(社区版)。 3. 配置Docker安装Docker后,您可以使用以下命令将当前用户添加到docker组中: sudo usermod -aG docker $USER 注销并重新登录,以使更改生效。 4. 测试Docker 安装Docker后,您可以使用以下命令测试它是否正确运行: sudo docker run hello-world 如果所有配置正确,将下载并运行Docker映像hello-world,并在终端中显示一条消息。 总结 在n1盒子安装Docker很容易,只需遵循上述步骤即可。有了Docker,您可以轻松地部署容器化应用程序,提高开发和部署的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值