53 - II. 0~n-1中缺失的数字

本文介绍了解决剑指Offer53-II题目的两种方法:下标对应法和二分法。下标对应法通过遍历数组比较索引与元素值来找出缺失数字,时间复杂度为O(n)。二分法则利用数组递增特性,通过二分查找不满足条件的左边界,时间复杂度为O(logn)。

剑指 Offer 53 - II. 0~n-1中缺失的数字

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。

示例 1:

输入: [0,1,3]
输出: 2

示例 2:

输入: [0,1,2,3,4,5,6,7,9]
输出: 8

限制:

  • 1 <= 数组长度 <= 10000

解法一:下标对应法

数组长度n-1,元素范围0 ~ n-1,共n个数,如果数组长度是n的话,也即所有数都出现一次,那么排序后,数组中当前元素的值应该和其所在索引相同,我们找到第一个不同的,下标代表的就是缺失的数。

要注意的是当所有的nums[i] = i时,缺失的就是最后一个n-1,即nums.length

时间复杂度: O ( n ) O(n) O(n)
在这里插入图片描述

Java代码

class Solution {
    public int missingNumber(int[] nums) {
        for(int i = 0;i < nums.length;i++){
            if(nums[i] != i){
                return i;
            }
        }
        return nums.length;
    }
}

在这里插入图片描述

解法二:二分

这道题目给定的是递增数组,假设数组中第一个缺失的数是 x,那么数组中的数如下所示;
在这里插入图片描述
从中可以看出,数组左边蓝色部分都满足nums[i] == i,数组右边橙色部分都不满足nums[i] == i,满足了二分法中的二段性质,因此我们可以二分找出不满足nums[i] = i的左边界。

另外同解法一,要注意特殊情况:当所有数都满足nums[i] == i时,表示缺失的是 n

时间复杂度: 二分中的迭代只会执行 O ( l o g n ) O(logn) O(logn)次,因此时间复杂度是 O ( l o g n ) O(logn) O(logn)

Java代码

class Solution {
    public int missingNumber(int[] nums) {
        //二分,找到不满足nums[i] == i的左边界
        //要注意的是当所有的nums[i]=i时,缺失的就是最后一个n-1,即nums.length
        int l = 0,r = nums.length - 1;
        while(l < r){
            int mid = l + r >> 1;
            if(nums[mid] != mid ) r = mid;
            else l = mid + 1; 
        }
        
        if(nums[r] == r) return nums.length;
        else return r;
    }
}

在这里插入图片描述

扩展题:LeetCode 268. 丢失的数字

268. 丢失的数字

给定一个包含 [0, n] n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

示例 1:

输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2是丢失的数字,因为它没有出现在 nums 中。

示例 2:

输入:nums = [0,1]
输出:2
解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2是丢失的数字,因为它没有出现在 nums 中。

示例 3:

输入:nums = [9,6,4,2,3,5,7,0,1]
输出:8
解释:n = 9,因为有 9 个数字,所以所有的数字都在范围[0,9] 内。8 是丢失的数字,因为它没有出现在 nums 中。

示例 4:

输入:nums = [0] 输出:1 解释:n = 1,因为有 1 个数字,所以所有的数字都在范围 [0,1] 内。1 是丢失的数字,因为它没有出现在 nums 中。

提示:

  • n == nums.length
  • 1 <= n <= 10^4
  • 0 <= nums[i] <= n
  • nums 中的所有数字都 独一无二

进阶:你能否实现线性时间复杂度、仅使用额外常数空间的算法解决此问题?

解题思路

和上题几乎完全一样,不同点在于该题给的数组不是排序好的 。

Go代码

func missingNumber(nums []int) int {
    // 0~n一共有n+1个数,而nums只含n个,所以一定存在一个数缺失了
    // 定义一个n+1的数组,我们将数字都放到对应的索引处,然后再遍历一次数组
    // 哪个索引处的元素,索引和元素数值不同,就是缺失的数字
    arr := make([]int,len(nums) + 1)
    // 由于默认值就是0,如果缺失的是0,也会符合索引位置和对应的值相等,所以想让索引0位置赋值为-1
    arr[0] = -1
    for i := 0;i < len(nums);i++ {
        arr[nums[i]] = nums[i]
    }
    for i := 0;i < len(arr);i++ {
        if i != arr[i] {
            return i
        }
    }
    return -1
}

在这里插入图片描述

扩展题 LeetCode 41. 缺失的第一个正数

41. 缺失的第一个正数

给你一个未排序的整数数组nums,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

示例 1:

输入:nums = [1,2,0]
输出:3
解释:范围 [1,2] 中的数字都在数组中。

示例 2:

输入:nums = [3,4,-1,1]
输出:2
解释:1 在数组中,但 2 没有。

示例 3:

输入:nums = [7,8,9,11,12]
输出:1
解释:最小的正数 1 没有出现。

提示:

  • 1 <= nums.length <= 10^5
  • -2^31 <= nums[i] <= 2^31 - 1

解题思路

与上两题差不多,直接看代码注释。

Java代码

class Solution {
    public int firstMissingPositive(int[] nums) {
        /*
        思路:数组最多存放nums.length个正数,我们可以把在1~nums.length范围内的数放到相应的位置
        最后遍历一遍数组,如果nums[i] <=0 || nums[i] > nums.length  || nums[nums[i]-1]!=nums[i],则i+1就是缺失的第一个正数
        也即nums[i]如果在[1,nums.length]范围内,则应该放到i+1的位置,即i+1 = nums[i];也即nums[nums[i]-1]=nums[i]
        比如【1,2,3,5】==》i=3的位置本应该放i+1=4的,但现在放的5,说明4是缺失的第一个正数
        【1,3,4,2】==》【1,2,3,4】每个位置放的都是i+1,所以缺失的第一个正数是5,即nums.length+1
        【3,4,-1,1】==》【1,-1,3,4】 i=1的位置上本应该放i+1=2的,但现在放的-1,故2就是缺失的第一个正数
        */
        
        if(nums==null || nums.length==0) return 1;
        for(int i = 0;i<nums.length;i++){
            //如果nums[i]在[1,nums.length]范围内,却没有放在nums[i]-1的位置,那么就交换这两个位置上的数,
            //交换后,交换得来的num[i]可能也没有在正确位置,所以是while循环,直到nums[i]不再满足while条件
            //这样外层for循环结束后,每个在[1,nums.length]范围内的nums[i]都放在了正确的位置
            //注:nums[nums[i]-1]!=nums[i]对于【1,1】这样的数组也适用,因为该条件考虑的是nums[i]要放的位置是否已经放着正确的数
            //但这里如果写成i!=nums[i]-1,则会出现死循环,因为如果原本需要交换的位置已经放着正确的数,即数值也是nums[i],那么又需要交换,交换,一直是他们两个互相交换,while无法退出了
            while(nums[i] >0 && nums[i] <= nums.length  && nums[nums[i]-1]!=nums[i]){
                int temp = nums[nums[i]-1];
                nums[nums[i]-1] = nums[i];
                nums[i] = temp;//例如[1,3,4,-1,7],i为1时,3应该放在下标为2的位置=》【1,4,3,-1,7】,现在换回4,4,应该放在下标为3的位置=》【1,-1,3,4,7】
                //现在nums[1] = -1,不满足while的条件了,退出while,进行下一轮for,即i=2;
            }
        }
        
        for(int i = 0;i<nums.length;i++){
            //因为在[1,nums.length]范围内的数,都已经被我们排在了i+1的位置了
            //所以遍历所有项,如果nums[i]不等于i+1,说明i+1就是缺失的第一个数
            if(nums[i]!=i+1){
                return i+1;
            }
        }
        return nums.length+1;
    }
}

在这里插入图片描述

Go代码

func firstMissingPositive(nums []int) int {
    // 数组长度为len(nums),极端情况也就是他保存的是1~len(nums)个正数,那么缺失的最小正数是len(nums) + 1
    // 所以我们将在1~len(nums)范围内的元素都放到对应的索引-1处(因为索引从0开始的),后续再看下哪个位置的值不等于索引+1
    // 该索引处的就是缺失的最小正数
    for i := 0;i < len(nums);i++ {
        // 在范围内的放到对应的位置去
        for  nums[i] > 0 && nums[i] <= len(nums) && nums[nums[i] - 1] != nums[i] {
            nums[nums[i] - 1],nums[i] = nums[i],nums[nums[i] - 1]
        } 
    }

    for i:=0;i < len(nums);i++ {
        if nums[i] != i + 1{
            return i+1
        }
    }

    // 前面的for没有return,说明数组被对应的正数填满了,缺失的是len(nums) + 1
    return len(nums) + 1
}

在这里插入图片描述

Setting up libubsan1:amd64 (10.5.0-1ubuntu1~20.04) ... dpkg: dependency problems prevent configuration of g++: g++ depends on g++-9 (>= 9.3.0-3~); however: Package g++-9 is not installed. dpkg: error processing package g++ (--configure): dependency problems - leaving unconfigured Setting up python3.8-minimal (3.8.10-0ubuntu1~20.04.18) ... Setting up libcrypt-dev:amd64 (1:4.4.10-10ubuntu4) ... dpkg: dependency problems prevent configuration of build-essential: build-essential depends on g++ (>= 4:9.2); however: Package g++ is not configured yet. dpkg: error processing package build-essential (--configure): dependency problems - leaving unconfigured Setting up libisl22:amd64 (0.22.1-1) ... Setting up python-pip-whl (20.0.2-5ubuntu1.11) ... Setting up libbinutils:amd64 (2.34-6ubuntu1.11) ... Setting up libpython3.8-stdlib:amd64 (3.8.10-0ubuntu1~20.04.18) ... Setting up libc-dev-bin (2.31-0ubuntu9.18) ... Setting up python3.8 (3.8.10-0ubuntu1~20.04.18) ... Setting up libalgorithm-diff-xs-perl (0.04-6) ... Setting up libcc1-0:amd64 (10.5.0-1ubuntu1~20.04) ... Setting up liblsan0:amd64 (10.5.0-1ubuntu1~20.04) ... Setting up libitm1:amd64 (10.5.0-1ubuntu1~20.04) ... Setting up gcc-9-base:amd64 (9.4.0-1ubuntu1~20.04.2) ... Setting up libalgorithm-merge-perl (0.08-3) ... Setting up libtsan0:amd64 (10.5.0-1ubuntu1~20.04) ... Setting up libctf0:amd64 (2.34-6ubuntu1.11) ... Setting up libasan5:amd64 (9.4.0-1ubuntu1~20.04.2) ... Setting up libpython3.8:amd64 (3.8.10-0ubuntu1~20.04.18) ... Setting up python3-pip (20.0.2-5ubuntu1.11) ... Setting up cpp-9 (9.4.0-1ubuntu1~20.04.2) ... Setting up libc6-dev:amd64 (2.31-0ubuntu9.18) ... Setting up binutils-x86-64-linux-gnu (2.34-6ubuntu1.11) ... Setting up binutils (2.34-6ubuntu1.11) ... Setting up dpkg-dev (1.19.7ubuntu3.2) ... Setting up libgcc-9-dev:amd64 (9.4.0-1ubuntu1~20.04.2) ... Setting up libexpat1-dev:amd64 (2.2.9-1ubuntu0.8) ... Setting up libpython3.8-dev:amd64 (3.8.10-0ubuntu1~20.04.18) ... Setting up zlib1g-dev:amd64 (1:1.2.11.dfsg-2ubuntu1.5) ... Setting up cpp (4:9.3.0-1ubuntu2) ... Setting up gcc-9 (9.4.0-1ubuntu1~20.04.2) ... Setting up libpython3-dev:amd64 (3.8.2-0ubuntu2) ... Setting up libstdc++-9-dev:amd64 (9.4.0-1ubuntu1~20.04.2) ... Setting up gcc (4:9.3.0-1ubuntu2) ... Setting up python3.8-dev (3.8.10-0ubuntu1~20.04.18) ... Setting up python3-dev (3.8.2-0ubuntu2) ... Processing triggers for libc-bin (2.31-0ubuntu9.9) ... /sbin/ldconfig.real: /usr/lib/wsl/lib/libcuda.so.1 is not a symbolic link Processing triggers for man-db (2.9.1-1) ... Processing triggers for mime-support (3.64ubuntu1) ... Errors were encountered while processing: g++ build-essential
最新发布
11-23
<think> 我们面对的是在Ubuntu 20.04系统中安装软件时出现的依赖问题,具体是g++依赖g++-9未安装,而build-essential又依赖g++未配置。根据引用[1]和引用[2]的建议,我们可以通过安装build-essential元包来同时解决gcc和g++的安装问题,但这里出现了循环依赖问题。我们可以尝试以下步骤: ### 解决方法 #### 1. **更新软件包列表并修复损坏的包** 首先确保系统是最新的,并尝试修复损坏的包: ```bash sudo apt update sudo apt --fix-broken install ``` 如果上述命令无法解决问题,我们可能需要手动处理依赖关系。 #### 2. **单独安装g++-9** 由于错误提示中提到了g++-9,我们可以尝试单独安装它: ```bash sudo apt install g++-9 ``` 如果这个步骤失败,我们可以使用`aptitude`工具,它能够提供更智能的依赖解决方案(引用[1]): ```bash sudo apt install aptitude sudo aptitude install g++-9 ``` 在`aptitude`的交互界面中,它会给出解决方案,通常我们选择第一个方案(按数字1),如果第一个方案不可行,它会继续给出其他方案,直到出现一个可以接受的方案(可能会提示降级或删除一些冲突的包,请仔细阅读)。 #### 3. **安装g++和build-essential** 在成功安装g++-9后,我们可以安装g++(它实际上是一个指向g++-9的符号链接): ```bash sudo apt install g++ ``` 然后安装build-essential: ```bash sudo apt install build-essential ``` #### 4. **使用aptitude安装build-essential(推荐方法)** 如果上述步骤仍然失败,我们可以直接使用`aptitude`来安装build-essential,因为它能更好地处理复杂的依赖关系(引用[1]): ```bash sudo aptitude install build-essential ``` 在交互过程中,`aptitude`可能会提供多个解决方案,选择接受安装所需依赖并可能删除冲突包的方案。注意:在删除包时,确保不会移除系统关键包。 #### 5. **手动配置未配置的包** 如果dpkg报告有未配置的包,可以尝试: ```bash sudo dpkg --configure -a ``` #### 6. **清除并重建dpkg状态(谨慎操作)** 如果问题依旧,可以尝试清除dpkg的状态文件(注意:这可能会使系统处于不可预测的状态,慎用): ```bash sudo mv /var/lib/dpkg/info /var/lib/dpkg/info_old sudo mkdir /var/lib/dpkg/info sudo apt update sudo apt -f install sudo mv /var/lib/dpkg/info/* /var/lib/dpkg/info_old/ sudo rm -rf /var/lib/dpkg/info sudo mv /var/lib/dpkg/info_old /var/lib/dpkg/info ``` ### 注意事项 - 在执行任何操作之前,建议备份重要数据。 - 使用`aptitude`时,仔细阅读它提出的解决方案,避免接受会移除重要系统组件的方案。 - 确保系统有足够的磁盘空间(至少需要200MB以上的空闲空间)。 ### 相关问题 1. 在Ubuntu中如何彻底删除一个包及其所有依赖? 2. 如何使用aptitude解决复杂的包依赖问题? 3. 如何防止Ubuntu在更新时出现包依赖冲突? 4. 如何查看一个软件包(如g++)的依赖树? 5. 当`apt --fix-broken install`无法修复时,还有哪些方法可以尝试? 希望这些步骤能帮助你解决问题。如果问题仍然存在,请提供具体的错误信息以便进一步诊断。 </think> ### 解决 Ubuntu 20.04 安装软件时 g++ 依赖问题 以下是针对 g++-9 未安装和 build-essential 依赖未配置问题的完整解决方案: #### 1. **清理系统并更新依赖** ```bash sudo apt clean # 清理下载缓存 sudo apt autoclean # 删除旧版本缓存 sudo dpkg --configure -a # 完成未完成的配置[^1] sudo apt install -f # 修复依赖关系 sudo apt update --fix-missing # 修复缺失的索引 ``` #### 2. **安装 aptitude 解决复杂依赖** 使用 aptitude 的智能依赖解析功能(引用[1]): ```bash sudo apt install aptitude # 安装高级包管理工具 # 交互式解决依赖问题(关键步骤) sudo aptitude install g++-9 ``` 在 aptitude 的交互界面中: 1. 按 `n`(no)拒绝第一个方案 2. 继续按 `n` 直到出现 "Install build-essential" 的方案 3. 接受此方案(通常显示为方案3或4) 4. 确认安装并解决所有依赖 #### 3. **完整安装构建工具链** ```bash # 安装基础编译工具(引用[2]) sudo apt install build-essential libssl-dev # 验证安装 g++ --version # 应显示 g++ 9.x 版本 ``` #### 4. **替代方案:手动安装依赖** 如果上述步骤失败: ```bash # 强制安装 g++-9 及其依赖 sudo apt install --fix-broken gcc-9 g++-9 # 创建符号链接(若 g++ 未自动链接) sudo ln -sf /usr/bin/g++-9 /usr/bin/g++ # 安装 build-essential sudo apt install build-essential ``` #### 5. **深度修复** ```bash # 重建 dpkg 数据库 sudo mv /var/lib/dpkg/status /var/lib/dpkg/status.bak sudo apt update sudo apt install -f # 清除锁定文件 sudo rm /var/lib/dpkg/lock* sudo rm /var/cache/apt/archives/lock ``` ### 验证安装 ```bash # 检查关键组件 which g++ # 应返回 /usr/bin/g++ g++ --version # 应显示 9.x 版本 dpkg -l build-essential # 应显示 "ii" 状态 ``` ### 相关问题 1. 如何彻底卸载并重新安装 Ubuntu 的编译工具链? 2. aptitude 在解决依赖冲突时有哪些独特优势? 3. 当多个 g++ 版本共存时如何指定默认版本? 4. 如何修复因内核更新导致的库文件链接损坏问题? 5. Ubuntu 20.04 中手动编译 CMake 的完整流程是怎样的?(引用[3])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值